diff options
author | Olav Kongas <ok@artecdesign.ee> | 2005-11-03 10:38:14 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-01-04 16:48:29 -0500 |
commit | 959eea2191e8d74b16ef019b0f4bf875c14f4547 (patch) | |
tree | c535857225eec2a52ce18c162ed94c5f18427dee /drivers | |
parent | 535488fcf1e4b2331e1c4a1eb67ca09468c13507 (diff) |
[PATCH] USB: isp116x-hcd: cleanup
The attached patch makes a cleanup of isp116x-hcd. Most of the volume of
the patch comes from 2 sources: moving the code around to get rid of a
few function prototypes and reworking register dumping functions/macros.
Among other things, switched over from using procfs to debugfs.
Cleanup. The following changes were made:
- Rework register dumping code so it can be used for dumping
to both syslog and debugfs.
- Switch from procfs to debugfs..
- Die gracefully on Unrecoverable Error interrupt.
- Fix memory leak in isp116x_urb_enqueue(), if HC happens to
die in a narrow time window.
- Fix a 'sparce' warning (unnecessary cast).
- Report Devices Removable for root hub ports by default
(was Devices Permanently Attached).
- Move bus suspend/resume functions down in code to get rid of
a few function prototypes.
- A number of one-line cleanups.
- Add an entry to MAINTAINERS.
Signed-off-by: Olav Kongas <ok@artecdesign.ee>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
MAINTAINERS | 6
drivers/usb/host/isp116x-hcd.c | 429 ++++++++++++++++-------------------------
drivers/usb/host/isp116x.h | 83 +++++--
3 files changed, 230 insertions(+), 288 deletions(-)
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/host/isp116x-hcd.c | 429 | ||||
-rw-r--r-- | drivers/usb/host/isp116x.h | 83 |
2 files changed, 224 insertions, 288 deletions
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c index 5f56c4a42f52..342cfadc999a 100644 --- a/drivers/usb/host/isp116x-hcd.c +++ b/drivers/usb/host/isp116x-hcd.c | |||
@@ -55,19 +55,13 @@ | |||
55 | /* enqueuing/finishing log of urbs */ | 55 | /* enqueuing/finishing log of urbs */ |
56 | //#define URB_TRACE | 56 | //#define URB_TRACE |
57 | 57 | ||
58 | #include <linux/config.h> | ||
59 | #include <linux/module.h> | 58 | #include <linux/module.h> |
60 | #include <linux/moduleparam.h> | ||
61 | #include <linux/kernel.h> | ||
62 | #include <linux/delay.h> | 59 | #include <linux/delay.h> |
63 | #include <linux/ioport.h> | 60 | #include <linux/debugfs.h> |
64 | #include <linux/sched.h> | 61 | #include <linux/seq_file.h> |
65 | #include <linux/slab.h> | ||
66 | #include <linux/smp_lock.h> | ||
67 | #include <linux/errno.h> | 62 | #include <linux/errno.h> |
68 | #include <linux/init.h> | 63 | #include <linux/init.h> |
69 | #include <linux/list.h> | 64 | #include <linux/list.h> |
70 | #include <linux/interrupt.h> | ||
71 | #include <linux/usb.h> | 65 | #include <linux/usb.h> |
72 | #include <linux/usb_isp116x.h> | 66 | #include <linux/usb_isp116x.h> |
73 | #include <linux/platform_device.h> | 67 | #include <linux/platform_device.h> |
@@ -77,14 +71,10 @@ | |||
77 | #include <asm/system.h> | 71 | #include <asm/system.h> |
78 | #include <asm/byteorder.h> | 72 | #include <asm/byteorder.h> |
79 | 73 | ||
80 | #ifndef DEBUG | ||
81 | # define STUB_DEBUG_FILE | ||
82 | #endif | ||
83 | |||
84 | #include "../core/hcd.h" | 74 | #include "../core/hcd.h" |
85 | #include "isp116x.h" | 75 | #include "isp116x.h" |
86 | 76 | ||
87 | #define DRIVER_VERSION "05 Aug 2005" | 77 | #define DRIVER_VERSION "03 Nov 2005" |
88 | #define DRIVER_DESC "ISP116x USB Host Controller Driver" | 78 | #define DRIVER_DESC "ISP116x USB Host Controller Driver" |
89 | 79 | ||
90 | MODULE_DESCRIPTION(DRIVER_DESC); | 80 | MODULE_DESCRIPTION(DRIVER_DESC); |
@@ -305,9 +295,8 @@ static void postproc_atl_queue(struct isp116x *isp116x) | |||
305 | udev = urb->dev; | 295 | udev = urb->dev; |
306 | ptd = &ep->ptd; | 296 | ptd = &ep->ptd; |
307 | cc = PTD_GET_CC(ptd); | 297 | cc = PTD_GET_CC(ptd); |
308 | |||
309 | spin_lock(&urb->lock); | ||
310 | short_not_ok = 1; | 298 | short_not_ok = 1; |
299 | spin_lock(&urb->lock); | ||
311 | 300 | ||
312 | /* Data underrun is special. For allowed underrun | 301 | /* Data underrun is special. For allowed underrun |
313 | we clear the error and continue as normal. For | 302 | we clear the error and continue as normal. For |
@@ -420,7 +409,7 @@ static void postproc_atl_queue(struct isp116x *isp116x) | |||
420 | ep->nextpid = 0; | 409 | ep->nextpid = 0; |
421 | break; | 410 | break; |
422 | default: | 411 | default: |
423 | BUG_ON(1); | 412 | BUG(); |
424 | } | 413 | } |
425 | spin_unlock(&urb->lock); | 414 | spin_unlock(&urb->lock); |
426 | } | 415 | } |
@@ -628,8 +617,12 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs) | |||
628 | u32 intstat = isp116x_read_reg32(isp116x, HCINTSTAT); | 617 | u32 intstat = isp116x_read_reg32(isp116x, HCINTSTAT); |
629 | isp116x_write_reg32(isp116x, HCINTSTAT, intstat); | 618 | isp116x_write_reg32(isp116x, HCINTSTAT, intstat); |
630 | if (intstat & HCINT_UE) { | 619 | if (intstat & HCINT_UE) { |
631 | ERR("Unrecoverable error\n"); | 620 | ERR("Unrecoverable error, HC is dead!\n"); |
632 | /* What should we do here? Reset? */ | 621 | /* IRQ's are off, we do no DMA, |
622 | perfectly ready to die ... */ | ||
623 | hcd->state = HC_STATE_HALT; | ||
624 | ret = IRQ_HANDLED; | ||
625 | goto done; | ||
633 | } | 626 | } |
634 | if (intstat & HCINT_RHSC) | 627 | if (intstat & HCINT_RHSC) |
635 | /* When root hub or any of its ports is going | 628 | /* When root hub or any of its ports is going |
@@ -640,7 +633,6 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs) | |||
640 | if (intstat & HCINT_RD) { | 633 | if (intstat & HCINT_RD) { |
641 | DBG("---- remote wakeup\n"); | 634 | DBG("---- remote wakeup\n"); |
642 | usb_hcd_resume_root_hub(hcd); | 635 | usb_hcd_resume_root_hub(hcd); |
643 | ret = IRQ_HANDLED; | ||
644 | } | 636 | } |
645 | irqstat &= ~HCuPINT_OPR; | 637 | irqstat &= ~HCuPINT_OPR; |
646 | ret = IRQ_HANDLED; | 638 | ret = IRQ_HANDLED; |
@@ -651,6 +643,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs) | |||
651 | } | 643 | } |
652 | 644 | ||
653 | isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb); | 645 | isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb); |
646 | done: | ||
654 | spin_unlock(&isp116x->lock); | 647 | spin_unlock(&isp116x->lock); |
655 | return ret; | 648 | return ret; |
656 | } | 649 | } |
@@ -724,6 +717,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd, | |||
724 | 717 | ||
725 | spin_lock_irqsave(&isp116x->lock, flags); | 718 | spin_lock_irqsave(&isp116x->lock, flags); |
726 | if (!HC_IS_RUNNING(hcd->state)) { | 719 | if (!HC_IS_RUNNING(hcd->state)) { |
720 | kfree(ep); | ||
727 | ret = -ENODEV; | 721 | ret = -ENODEV; |
728 | goto fail; | 722 | goto fail; |
729 | } | 723 | } |
@@ -888,7 +882,7 @@ static void isp116x_endpoint_disable(struct usb_hcd *hcd, | |||
888 | struct usb_host_endpoint *hep) | 882 | struct usb_host_endpoint *hep) |
889 | { | 883 | { |
890 | int i; | 884 | int i; |
891 | struct isp116x_ep *ep = hep->hcpriv;; | 885 | struct isp116x_ep *ep = hep->hcpriv; |
892 | 886 | ||
893 | if (!ep) | 887 | if (!ep) |
894 | return; | 888 | return; |
@@ -916,8 +910,6 @@ static int isp116x_get_frame(struct usb_hcd *hcd) | |||
916 | return (int)fmnum; | 910 | return (int)fmnum; |
917 | } | 911 | } |
918 | 912 | ||
919 | /*----------------------------------------------------------------*/ | ||
920 | |||
921 | /* | 913 | /* |
922 | Adapted from ohci-hub.c. Currently we don't support autosuspend. | 914 | Adapted from ohci-hub.c. Currently we don't support autosuspend. |
923 | */ | 915 | */ |
@@ -968,11 +960,10 @@ static void isp116x_hub_descriptor(struct isp116x *isp116x, | |||
968 | desc->bHubContrCurrent = 0; | 960 | desc->bHubContrCurrent = 0; |
969 | desc->bNbrPorts = (u8) (reg & 0x3); | 961 | desc->bNbrPorts = (u8) (reg & 0x3); |
970 | /* Power switching, device type, overcurrent. */ | 962 | /* Power switching, device type, overcurrent. */ |
971 | desc->wHubCharacteristics = | 963 | desc->wHubCharacteristics = cpu_to_le16((u16) ((reg >> 8) & 0x1f)); |
972 | (__force __u16) cpu_to_le16((u16) ((reg >> 8) & 0x1f)); | ||
973 | desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff); | 964 | desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff); |
974 | /* two bitmaps: ports removable, and legacy PortPwrCtrlMask */ | 965 | /* two bitmaps: ports removable, and legacy PortPwrCtrlMask */ |
975 | desc->bitmap[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1; | 966 | desc->bitmap[0] = 0; |
976 | desc->bitmap[1] = ~0; | 967 | desc->bitmap[1] = ~0; |
977 | } | 968 | } |
978 | 969 | ||
@@ -1159,145 +1150,9 @@ static int isp116x_hub_control(struct usb_hcd *hcd, | |||
1159 | return ret; | 1150 | return ret; |
1160 | } | 1151 | } |
1161 | 1152 | ||
1162 | #ifdef CONFIG_PM | ||
1163 | |||
1164 | static int isp116x_bus_suspend(struct usb_hcd *hcd) | ||
1165 | { | ||
1166 | struct isp116x *isp116x = hcd_to_isp116x(hcd); | ||
1167 | unsigned long flags; | ||
1168 | u32 val; | ||
1169 | int ret = 0; | ||
1170 | |||
1171 | spin_lock_irqsave(&isp116x->lock, flags); | ||
1172 | |||
1173 | val = isp116x_read_reg32(isp116x, HCCONTROL); | ||
1174 | switch (val & HCCONTROL_HCFS) { | ||
1175 | case HCCONTROL_USB_OPER: | ||
1176 | hcd->state = HC_STATE_QUIESCING; | ||
1177 | val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE); | ||
1178 | val |= HCCONTROL_USB_SUSPEND; | ||
1179 | if (hcd->remote_wakeup) | ||
1180 | val |= HCCONTROL_RWE; | ||
1181 | /* Wait for usb transfers to finish */ | ||
1182 | mdelay(2); | ||
1183 | isp116x_write_reg32(isp116x, HCCONTROL, val); | ||
1184 | hcd->state = HC_STATE_SUSPENDED; | ||
1185 | /* Wait for devices to suspend */ | ||
1186 | mdelay(5); | ||
1187 | case HCCONTROL_USB_SUSPEND: | ||
1188 | break; | ||
1189 | case HCCONTROL_USB_RESUME: | ||
1190 | isp116x_write_reg32(isp116x, HCCONTROL, | ||
1191 | (val & ~HCCONTROL_HCFS) | | ||
1192 | HCCONTROL_USB_RESET); | ||
1193 | case HCCONTROL_USB_RESET: | ||
1194 | ret = -EBUSY; | ||
1195 | break; | ||
1196 | default: | ||
1197 | ret = -EINVAL; | ||
1198 | } | ||
1199 | |||
1200 | spin_unlock_irqrestore(&isp116x->lock, flags); | ||
1201 | return ret; | ||
1202 | } | ||
1203 | |||
1204 | /* Get rid of these declarations later in cleanup */ | ||
1205 | static int isp116x_reset(struct usb_hcd *hcd); | ||
1206 | static int isp116x_start(struct usb_hcd *hcd); | ||
1207 | |||
1208 | static int isp116x_bus_resume(struct usb_hcd *hcd) | ||
1209 | { | ||
1210 | struct isp116x *isp116x = hcd_to_isp116x(hcd); | ||
1211 | u32 val; | ||
1212 | |||
1213 | msleep(5); | ||
1214 | spin_lock_irq(&isp116x->lock); | ||
1215 | |||
1216 | val = isp116x_read_reg32(isp116x, HCCONTROL); | ||
1217 | switch (val & HCCONTROL_HCFS) { | ||
1218 | case HCCONTROL_USB_SUSPEND: | ||
1219 | val &= ~HCCONTROL_HCFS; | ||
1220 | val |= HCCONTROL_USB_RESUME; | ||
1221 | isp116x_write_reg32(isp116x, HCCONTROL, val); | ||
1222 | case HCCONTROL_USB_RESUME: | ||
1223 | break; | ||
1224 | case HCCONTROL_USB_OPER: | ||
1225 | spin_unlock_irq(&isp116x->lock); | ||
1226 | /* Without setting power_state here the | ||
1227 | SUSPENDED state won't be removed from | ||
1228 | sysfs/usbN/power.state as a response to remote | ||
1229 | wakeup. Maybe in the future. */ | ||
1230 | hcd->self.root_hub->dev.power.power_state = PMSG_ON; | ||
1231 | return 0; | ||
1232 | default: | ||
1233 | /* HCCONTROL_USB_RESET: this may happen, when during | ||
1234 | suspension the HC lost power. Reinitialize completely */ | ||
1235 | spin_unlock_irq(&isp116x->lock); | ||
1236 | DBG("Chip has been reset while suspended. Reinit from scratch.\n"); | ||
1237 | isp116x_reset(hcd); | ||
1238 | isp116x_start(hcd); | ||
1239 | isp116x_hub_control(hcd, SetPortFeature, | ||
1240 | USB_PORT_FEAT_POWER, 1, NULL, 0); | ||
1241 | if ((isp116x->rhdesca & RH_A_NDP) == 2) | ||
1242 | isp116x_hub_control(hcd, SetPortFeature, | ||
1243 | USB_PORT_FEAT_POWER, 2, NULL, 0); | ||
1244 | hcd->self.root_hub->dev.power.power_state = PMSG_ON; | ||
1245 | return 0; | ||
1246 | } | ||
1247 | |||
1248 | val = isp116x->rhdesca & RH_A_NDP; | ||
1249 | while (val--) { | ||
1250 | u32 stat = | ||
1251 | isp116x_read_reg32(isp116x, val ? HCRHPORT2 : HCRHPORT1); | ||
1252 | /* force global, not selective, resume */ | ||
1253 | if (!(stat & RH_PS_PSS)) | ||
1254 | continue; | ||
1255 | DBG("%s: Resuming port %d\n", __func__, val); | ||
1256 | isp116x_write_reg32(isp116x, RH_PS_POCI, val | ||
1257 | ? HCRHPORT2 : HCRHPORT1); | ||
1258 | } | ||
1259 | spin_unlock_irq(&isp116x->lock); | ||
1260 | |||
1261 | hcd->state = HC_STATE_RESUMING; | ||
1262 | mdelay(20); | ||
1263 | |||
1264 | /* Go operational */ | ||
1265 | spin_lock_irq(&isp116x->lock); | ||
1266 | val = isp116x_read_reg32(isp116x, HCCONTROL); | ||
1267 | isp116x_write_reg32(isp116x, HCCONTROL, | ||
1268 | (val & ~HCCONTROL_HCFS) | HCCONTROL_USB_OPER); | ||
1269 | spin_unlock_irq(&isp116x->lock); | ||
1270 | /* see analogous comment above */ | ||
1271 | hcd->self.root_hub->dev.power.power_state = PMSG_ON; | ||
1272 | hcd->state = HC_STATE_RUNNING; | ||
1273 | |||
1274 | return 0; | ||
1275 | } | ||
1276 | |||
1277 | |||
1278 | #else | ||
1279 | |||
1280 | #define isp116x_bus_suspend NULL | ||
1281 | #define isp116x_bus_resume NULL | ||
1282 | |||
1283 | #endif | ||
1284 | |||
1285 | /*-----------------------------------------------------------------*/ | 1153 | /*-----------------------------------------------------------------*/ |
1286 | 1154 | ||
1287 | #ifdef STUB_DEBUG_FILE | 1155 | #ifdef CONFIG_DEBUG_FS |
1288 | |||
1289 | static inline void create_debug_file(struct isp116x *isp116x) | ||
1290 | { | ||
1291 | } | ||
1292 | |||
1293 | static inline void remove_debug_file(struct isp116x *isp116x) | ||
1294 | { | ||
1295 | } | ||
1296 | |||
1297 | #else | ||
1298 | |||
1299 | #include <linux/proc_fs.h> | ||
1300 | #include <linux/seq_file.h> | ||
1301 | 1156 | ||
1302 | static void dump_irq(struct seq_file *s, char *label, u16 mask) | 1157 | static void dump_irq(struct seq_file *s, char *label, u16 mask) |
1303 | { | 1158 | { |
@@ -1321,13 +1176,9 @@ static void dump_int(struct seq_file *s, char *label, u32 mask) | |||
1321 | mask & HCINT_SF ? " sof" : "", mask & HCINT_SO ? " so" : ""); | 1176 | mask & HCINT_SF ? " sof" : "", mask & HCINT_SO ? " so" : ""); |
1322 | } | 1177 | } |
1323 | 1178 | ||
1324 | static int proc_isp116x_show(struct seq_file *s, void *unused) | 1179 | static int isp116x_show_dbg(struct seq_file *s, void *unused) |
1325 | { | 1180 | { |
1326 | struct isp116x *isp116x = s->private; | 1181 | struct isp116x *isp116x = s->private; |
1327 | struct isp116x_ep *ep; | ||
1328 | struct urb *urb; | ||
1329 | unsigned i; | ||
1330 | char *str; | ||
1331 | 1182 | ||
1332 | seq_printf(s, "%s\n%s version %s\n", | 1183 | seq_printf(s, "%s\n%s version %s\n", |
1333 | isp116x_to_hcd(isp116x)->product_desc, hcd_name, | 1184 | isp116x_to_hcd(isp116x)->product_desc, hcd_name, |
@@ -1343,105 +1194,50 @@ static int proc_isp116x_show(struct seq_file *s, void *unused) | |||
1343 | } | 1194 | } |
1344 | 1195 | ||
1345 | spin_lock_irq(&isp116x->lock); | 1196 | spin_lock_irq(&isp116x->lock); |
1346 | |||
1347 | dump_irq(s, "hc_irq_enable", isp116x_read_reg16(isp116x, HCuPINTENB)); | 1197 | dump_irq(s, "hc_irq_enable", isp116x_read_reg16(isp116x, HCuPINTENB)); |
1348 | dump_irq(s, "hc_irq_status", isp116x_read_reg16(isp116x, HCuPINT)); | 1198 | dump_irq(s, "hc_irq_status", isp116x_read_reg16(isp116x, HCuPINT)); |
1349 | dump_int(s, "hc_int_enable", isp116x_read_reg32(isp116x, HCINTENB)); | 1199 | dump_int(s, "hc_int_enable", isp116x_read_reg32(isp116x, HCINTENB)); |
1350 | dump_int(s, "hc_int_status", isp116x_read_reg32(isp116x, HCINTSTAT)); | 1200 | dump_int(s, "hc_int_status", isp116x_read_reg32(isp116x, HCINTSTAT)); |
1351 | 1201 | isp116x_show_regs_seq(isp116x, s); | |
1352 | list_for_each_entry(ep, &isp116x->async, schedule) { | ||
1353 | |||
1354 | switch (ep->nextpid) { | ||
1355 | case USB_PID_IN: | ||
1356 | str = "in"; | ||
1357 | break; | ||
1358 | case USB_PID_OUT: | ||
1359 | str = "out"; | ||
1360 | break; | ||
1361 | case USB_PID_SETUP: | ||
1362 | str = "setup"; | ||
1363 | break; | ||
1364 | case USB_PID_ACK: | ||
1365 | str = "status"; | ||
1366 | break; | ||
1367 | default: | ||
1368 | str = "?"; | ||
1369 | break; | ||
1370 | }; | ||
1371 | seq_printf(s, "%p, ep%d%s, maxpacket %d:\n", ep, | ||
1372 | ep->epnum, str, ep->maxpacket); | ||
1373 | list_for_each_entry(urb, &ep->hep->urb_list, urb_list) { | ||
1374 | seq_printf(s, " urb%p, %d/%d\n", urb, | ||
1375 | urb->actual_length, | ||
1376 | urb->transfer_buffer_length); | ||
1377 | } | ||
1378 | } | ||
1379 | if (!list_empty(&isp116x->async)) | ||
1380 | seq_printf(s, "\n"); | ||
1381 | |||
1382 | seq_printf(s, "periodic size= %d\n", PERIODIC_SIZE); | ||
1383 | |||
1384 | for (i = 0; i < PERIODIC_SIZE; i++) { | ||
1385 | ep = isp116x->periodic[i]; | ||
1386 | if (!ep) | ||
1387 | continue; | ||
1388 | seq_printf(s, "%2d [%3d]:\n", i, isp116x->load[i]); | ||
1389 | |||
1390 | /* DUMB: prints shared entries multiple times */ | ||
1391 | do { | ||
1392 | seq_printf(s, " %d/%p (%sdev%d ep%d%s max %d)\n", | ||
1393 | ep->period, ep, | ||
1394 | (ep->udev->speed == | ||
1395 | USB_SPEED_FULL) ? "" : "ls ", | ||
1396 | ep->udev->devnum, ep->epnum, | ||
1397 | (ep->epnum == | ||
1398 | 0) ? "" : ((ep->nextpid == | ||
1399 | USB_PID_IN) ? "in" : "out"), | ||
1400 | ep->maxpacket); | ||
1401 | ep = ep->next; | ||
1402 | } while (ep); | ||
1403 | } | ||
1404 | spin_unlock_irq(&isp116x->lock); | 1202 | spin_unlock_irq(&isp116x->lock); |
1405 | seq_printf(s, "\n"); | 1203 | seq_printf(s, "\n"); |
1406 | 1204 | ||
1407 | return 0; | 1205 | return 0; |
1408 | } | 1206 | } |
1409 | 1207 | ||
1410 | static int proc_isp116x_open(struct inode *inode, struct file *file) | 1208 | static int isp116x_open_seq(struct inode *inode, struct file *file) |
1411 | { | 1209 | { |
1412 | return single_open(file, proc_isp116x_show, PDE(inode)->data); | 1210 | return single_open(file, isp116x_show_dbg, inode->u.generic_ip); |
1413 | } | 1211 | } |
1414 | 1212 | ||
1415 | static struct file_operations proc_ops = { | 1213 | static struct file_operations isp116x_debug_fops = { |
1416 | .open = proc_isp116x_open, | 1214 | .open = isp116x_open_seq, |
1417 | .read = seq_read, | 1215 | .read = seq_read, |
1418 | .llseek = seq_lseek, | 1216 | .llseek = seq_lseek, |
1419 | .release = single_release, | 1217 | .release = single_release, |
1420 | }; | 1218 | }; |
1421 | 1219 | ||
1422 | /* expect just one isp116x per system */ | 1220 | static int create_debug_file(struct isp116x *isp116x) |
1423 | static const char proc_filename[] = "driver/isp116x"; | ||
1424 | |||
1425 | static void create_debug_file(struct isp116x *isp116x) | ||
1426 | { | 1221 | { |
1427 | struct proc_dir_entry *pde; | 1222 | isp116x->dentry = debugfs_create_file(hcd_name, |
1428 | 1223 | S_IRUGO, NULL, isp116x, | |
1429 | pde = create_proc_entry(proc_filename, 0, NULL); | 1224 | &isp116x_debug_fops); |
1430 | if (pde == NULL) | 1225 | if (!isp116x->dentry) |
1431 | return; | 1226 | return -ENOMEM; |
1432 | 1227 | return 0; | |
1433 | pde->proc_fops = &proc_ops; | ||
1434 | pde->data = isp116x; | ||
1435 | isp116x->pde = pde; | ||
1436 | } | 1228 | } |
1437 | 1229 | ||
1438 | static void remove_debug_file(struct isp116x *isp116x) | 1230 | static void remove_debug_file(struct isp116x *isp116x) |
1439 | { | 1231 | { |
1440 | if (isp116x->pde) | 1232 | debugfs_remove(isp116x->dentry); |
1441 | remove_proc_entry(proc_filename, NULL); | ||
1442 | } | 1233 | } |
1443 | 1234 | ||
1444 | #endif | 1235 | #else |
1236 | |||
1237 | #define create_debug_file(d) 0 | ||
1238 | #define remove_debug_file(d) do{}while(0) | ||
1239 | |||
1240 | #endif /* CONFIG_DEBUG_FS */ | ||
1445 | 1241 | ||
1446 | /*-----------------------------------------------------------------*/ | 1242 | /*-----------------------------------------------------------------*/ |
1447 | 1243 | ||
@@ -1476,7 +1272,7 @@ static int isp116x_reset(struct usb_hcd *hcd) | |||
1476 | struct isp116x *isp116x = hcd_to_isp116x(hcd); | 1272 | struct isp116x *isp116x = hcd_to_isp116x(hcd); |
1477 | unsigned long t; | 1273 | unsigned long t; |
1478 | u16 clkrdy = 0; | 1274 | u16 clkrdy = 0; |
1479 | int ret = 0, timeout = 15 /* ms */ ; | 1275 | int ret, timeout = 15 /* ms */ ; |
1480 | 1276 | ||
1481 | ret = isp116x_sw_reset(isp116x); | 1277 | ret = isp116x_sw_reset(isp116x); |
1482 | if (ret) | 1278 | if (ret) |
@@ -1492,7 +1288,7 @@ static int isp116x_reset(struct usb_hcd *hcd) | |||
1492 | break; | 1288 | break; |
1493 | } | 1289 | } |
1494 | if (!clkrdy) { | 1290 | if (!clkrdy) { |
1495 | ERR("Clock not ready after 20ms\n"); | 1291 | ERR("Clock not ready after %dms\n", timeout); |
1496 | /* After sw_reset the clock won't report to be ready, if | 1292 | /* After sw_reset the clock won't report to be ready, if |
1497 | H_WAKEUP pin is high. */ | 1293 | H_WAKEUP pin is high. */ |
1498 | ERR("Please make sure that the H_WAKEUP pin is pulled low!\n"); | 1294 | ERR("Please make sure that the H_WAKEUP pin is pulled low!\n"); |
@@ -1610,12 +1406,128 @@ static int isp116x_start(struct usb_hcd *hcd) | |||
1610 | isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS); | 1406 | isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS); |
1611 | isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS); | 1407 | isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS); |
1612 | 1408 | ||
1613 | isp116x_show_regs(isp116x); | 1409 | isp116x_show_regs_log(isp116x); |
1614 | spin_unlock_irqrestore(&isp116x->lock, flags); | 1410 | spin_unlock_irqrestore(&isp116x->lock, flags); |
1615 | return 0; | 1411 | return 0; |
1616 | } | 1412 | } |
1617 | 1413 | ||
1618 | /*-----------------------------------------------------------------*/ | 1414 | #ifdef CONFIG_PM |
1415 | |||
1416 | static int isp116x_bus_suspend(struct usb_hcd *hcd) | ||
1417 | { | ||
1418 | struct isp116x *isp116x = hcd_to_isp116x(hcd); | ||
1419 | unsigned long flags; | ||
1420 | u32 val; | ||
1421 | int ret = 0; | ||
1422 | |||
1423 | spin_lock_irqsave(&isp116x->lock, flags); | ||
1424 | |||
1425 | val = isp116x_read_reg32(isp116x, HCCONTROL); | ||
1426 | switch (val & HCCONTROL_HCFS) { | ||
1427 | case HCCONTROL_USB_OPER: | ||
1428 | hcd->state = HC_STATE_QUIESCING; | ||
1429 | val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE); | ||
1430 | val |= HCCONTROL_USB_SUSPEND; | ||
1431 | if (hcd->remote_wakeup) | ||
1432 | val |= HCCONTROL_RWE; | ||
1433 | /* Wait for usb transfers to finish */ | ||
1434 | mdelay(2); | ||
1435 | isp116x_write_reg32(isp116x, HCCONTROL, val); | ||
1436 | hcd->state = HC_STATE_SUSPENDED; | ||
1437 | /* Wait for devices to suspend */ | ||
1438 | mdelay(5); | ||
1439 | case HCCONTROL_USB_SUSPEND: | ||
1440 | break; | ||
1441 | case HCCONTROL_USB_RESUME: | ||
1442 | isp116x_write_reg32(isp116x, HCCONTROL, | ||
1443 | (val & ~HCCONTROL_HCFS) | | ||
1444 | HCCONTROL_USB_RESET); | ||
1445 | case HCCONTROL_USB_RESET: | ||
1446 | ret = -EBUSY; | ||
1447 | break; | ||
1448 | default: | ||
1449 | ret = -EINVAL; | ||
1450 | } | ||
1451 | |||
1452 | spin_unlock_irqrestore(&isp116x->lock, flags); | ||
1453 | return ret; | ||
1454 | } | ||
1455 | |||
1456 | static int isp116x_bus_resume(struct usb_hcd *hcd) | ||
1457 | { | ||
1458 | struct isp116x *isp116x = hcd_to_isp116x(hcd); | ||
1459 | u32 val; | ||
1460 | |||
1461 | msleep(5); | ||
1462 | spin_lock_irq(&isp116x->lock); | ||
1463 | |||
1464 | val = isp116x_read_reg32(isp116x, HCCONTROL); | ||
1465 | switch (val & HCCONTROL_HCFS) { | ||
1466 | case HCCONTROL_USB_SUSPEND: | ||
1467 | val &= ~HCCONTROL_HCFS; | ||
1468 | val |= HCCONTROL_USB_RESUME; | ||
1469 | isp116x_write_reg32(isp116x, HCCONTROL, val); | ||
1470 | case HCCONTROL_USB_RESUME: | ||
1471 | break; | ||
1472 | case HCCONTROL_USB_OPER: | ||
1473 | spin_unlock_irq(&isp116x->lock); | ||
1474 | /* Without setting power_state here the | ||
1475 | SUSPENDED state won't be removed from | ||
1476 | sysfs/usbN/power.state as a response to remote | ||
1477 | wakeup. Maybe in the future. */ | ||
1478 | hcd->self.root_hub->dev.power.power_state = PMSG_ON; | ||
1479 | return 0; | ||
1480 | default: | ||
1481 | /* HCCONTROL_USB_RESET: this may happen, when during | ||
1482 | suspension the HC lost power. Reinitialize completely */ | ||
1483 | spin_unlock_irq(&isp116x->lock); | ||
1484 | DBG("Chip has been reset while suspended. Reinit from scratch.\n"); | ||
1485 | isp116x_reset(hcd); | ||
1486 | isp116x_start(hcd); | ||
1487 | isp116x_hub_control(hcd, SetPortFeature, | ||
1488 | USB_PORT_FEAT_POWER, 1, NULL, 0); | ||
1489 | if ((isp116x->rhdesca & RH_A_NDP) == 2) | ||
1490 | isp116x_hub_control(hcd, SetPortFeature, | ||
1491 | USB_PORT_FEAT_POWER, 2, NULL, 0); | ||
1492 | hcd->self.root_hub->dev.power.power_state = PMSG_ON; | ||
1493 | return 0; | ||
1494 | } | ||
1495 | |||
1496 | val = isp116x->rhdesca & RH_A_NDP; | ||
1497 | while (val--) { | ||
1498 | u32 stat = | ||
1499 | isp116x_read_reg32(isp116x, val ? HCRHPORT2 : HCRHPORT1); | ||
1500 | /* force global, not selective, resume */ | ||
1501 | if (!(stat & RH_PS_PSS)) | ||
1502 | continue; | ||
1503 | DBG("%s: Resuming port %d\n", __func__, val); | ||
1504 | isp116x_write_reg32(isp116x, RH_PS_POCI, val | ||
1505 | ? HCRHPORT2 : HCRHPORT1); | ||
1506 | } | ||
1507 | spin_unlock_irq(&isp116x->lock); | ||
1508 | |||
1509 | hcd->state = HC_STATE_RESUMING; | ||
1510 | msleep(20); | ||
1511 | |||
1512 | /* Go operational */ | ||
1513 | spin_lock_irq(&isp116x->lock); | ||
1514 | val = isp116x_read_reg32(isp116x, HCCONTROL); | ||
1515 | isp116x_write_reg32(isp116x, HCCONTROL, | ||
1516 | (val & ~HCCONTROL_HCFS) | HCCONTROL_USB_OPER); | ||
1517 | spin_unlock_irq(&isp116x->lock); | ||
1518 | /* see analogous comment above */ | ||
1519 | hcd->self.root_hub->dev.power.power_state = PMSG_ON; | ||
1520 | hcd->state = HC_STATE_RUNNING; | ||
1521 | |||
1522 | return 0; | ||
1523 | } | ||
1524 | |||
1525 | #else | ||
1526 | |||
1527 | #define isp116x_bus_suspend NULL | ||
1528 | #define isp116x_bus_resume NULL | ||
1529 | |||
1530 | #endif | ||
1619 | 1531 | ||
1620 | static struct hc_driver isp116x_hc_driver = { | 1532 | static struct hc_driver isp116x_hc_driver = { |
1621 | .description = hcd_name, | 1533 | .description = hcd_name, |
@@ -1745,12 +1657,19 @@ static int __init isp116x_probe(struct platform_device *pdev) | |||
1745 | } | 1657 | } |
1746 | 1658 | ||
1747 | ret = usb_add_hcd(hcd, irq, SA_INTERRUPT); | 1659 | ret = usb_add_hcd(hcd, irq, SA_INTERRUPT); |
1748 | if (ret != 0) | 1660 | if (ret) |
1749 | goto err6; | 1661 | goto err6; |
1750 | 1662 | ||
1751 | create_debug_file(isp116x); | 1663 | ret = create_debug_file(isp116x); |
1664 | if (ret) { | ||
1665 | ERR("Couldn't create debugfs entry\n"); | ||
1666 | goto err7; | ||
1667 | } | ||
1668 | |||
1752 | return 0; | 1669 | return 0; |
1753 | 1670 | ||
1671 | err7: | ||
1672 | usb_remove_hcd(hcd); | ||
1754 | err6: | 1673 | err6: |
1755 | usb_put_hcd(hcd); | 1674 | usb_put_hcd(hcd); |
1756 | err5: | 1675 | err5: |
@@ -1772,13 +1691,9 @@ static int __init isp116x_probe(struct platform_device *pdev) | |||
1772 | */ | 1691 | */ |
1773 | static int isp116x_suspend(struct platform_device *dev, pm_message_t state) | 1692 | static int isp116x_suspend(struct platform_device *dev, pm_message_t state) |
1774 | { | 1693 | { |
1775 | int ret = 0; | 1694 | VDBG("%s: state %x\n", __func__, state.event); |
1776 | |||
1777 | VDBG("%s: state %x\n", __func__, state); | ||
1778 | |||
1779 | dev->dev.power.power_state = state; | 1695 | dev->dev.power.power_state = state; |
1780 | 1696 | return 0; | |
1781 | return ret; | ||
1782 | } | 1697 | } |
1783 | 1698 | ||
1784 | /* | 1699 | /* |
@@ -1786,13 +1701,9 @@ static int isp116x_suspend(struct platform_device *dev, pm_message_t state) | |||
1786 | */ | 1701 | */ |
1787 | static int isp116x_resume(struct platform_device *dev) | 1702 | static int isp116x_resume(struct platform_device *dev) |
1788 | { | 1703 | { |
1789 | int ret = 0; | 1704 | VDBG("%s: state %x\n", __func__, dev->power.power_state.event); |
1790 | |||
1791 | VDBG("%s: state %x\n", __func__, dev->dev.power.power_state); | ||
1792 | |||
1793 | dev->dev.power.power_state = PMSG_ON; | 1705 | dev->dev.power.power_state = PMSG_ON; |
1794 | 1706 | return 0; | |
1795 | return ret; | ||
1796 | } | 1707 | } |
1797 | 1708 | ||
1798 | #else | 1709 | #else |
diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h index c6fec96785fe..a1b7c3813d3a 100644 --- a/drivers/usb/host/isp116x.h +++ b/drivers/usb/host/isp116x.h | |||
@@ -259,7 +259,7 @@ struct isp116x { | |||
259 | 259 | ||
260 | struct isp116x_platform_data *board; | 260 | struct isp116x_platform_data *board; |
261 | 261 | ||
262 | struct proc_dir_entry *pde; | 262 | struct dentry *dentry; |
263 | unsigned long stat1, stat2, stat4, stat8, stat16; | 263 | unsigned long stat1, stat2, stat4, stat8, stat16; |
264 | 264 | ||
265 | /* HC registers */ | 265 | /* HC registers */ |
@@ -450,7 +450,7 @@ static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg, | |||
450 | isp116x_write_data32(isp116x, (u32) val); | 450 | isp116x_write_data32(isp116x, (u32) val); |
451 | } | 451 | } |
452 | 452 | ||
453 | #define isp116x_show_reg(d,r) { \ | 453 | #define isp116x_show_reg_log(d,r,s) { \ |
454 | if ((r) < 0x20) { \ | 454 | if ((r) < 0x20) { \ |
455 | DBG("%-12s[%02x]: %08x\n", #r, \ | 455 | DBG("%-12s[%02x]: %08x\n", #r, \ |
456 | r, isp116x_read_reg32(d, r)); \ | 456 | r, isp116x_read_reg32(d, r)); \ |
@@ -459,35 +459,60 @@ static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg, | |||
459 | r, isp116x_read_reg16(d, r)); \ | 459 | r, isp116x_read_reg16(d, r)); \ |
460 | } \ | 460 | } \ |
461 | } | 461 | } |
462 | #define isp116x_show_reg_seq(d,r,s) { \ | ||
463 | if ((r) < 0x20) { \ | ||
464 | seq_printf(s, "%-12s[%02x]: %08x\n", #r, \ | ||
465 | r, isp116x_read_reg32(d, r)); \ | ||
466 | } else { \ | ||
467 | seq_printf(s, "%-12s[%02x]: %04x\n", #r, \ | ||
468 | r, isp116x_read_reg16(d, r)); \ | ||
469 | } \ | ||
470 | } | ||
462 | 471 | ||
463 | static inline void isp116x_show_regs(struct isp116x *isp116x) | 472 | #define isp116x_show_regs(d,type,s) { \ |
473 | isp116x_show_reg_##type(d, HCREVISION, s); \ | ||
474 | isp116x_show_reg_##type(d, HCCONTROL, s); \ | ||
475 | isp116x_show_reg_##type(d, HCCMDSTAT, s); \ | ||
476 | isp116x_show_reg_##type(d, HCINTSTAT, s); \ | ||
477 | isp116x_show_reg_##type(d, HCINTENB, s); \ | ||
478 | isp116x_show_reg_##type(d, HCFMINTVL, s); \ | ||
479 | isp116x_show_reg_##type(d, HCFMREM, s); \ | ||
480 | isp116x_show_reg_##type(d, HCFMNUM, s); \ | ||
481 | isp116x_show_reg_##type(d, HCLSTHRESH, s); \ | ||
482 | isp116x_show_reg_##type(d, HCRHDESCA, s); \ | ||
483 | isp116x_show_reg_##type(d, HCRHDESCB, s); \ | ||
484 | isp116x_show_reg_##type(d, HCRHSTATUS, s); \ | ||
485 | isp116x_show_reg_##type(d, HCRHPORT1, s); \ | ||
486 | isp116x_show_reg_##type(d, HCRHPORT2, s); \ | ||
487 | isp116x_show_reg_##type(d, HCHWCFG, s); \ | ||
488 | isp116x_show_reg_##type(d, HCDMACFG, s); \ | ||
489 | isp116x_show_reg_##type(d, HCXFERCTR, s); \ | ||
490 | isp116x_show_reg_##type(d, HCuPINT, s); \ | ||
491 | isp116x_show_reg_##type(d, HCuPINTENB, s); \ | ||
492 | isp116x_show_reg_##type(d, HCCHIPID, s); \ | ||
493 | isp116x_show_reg_##type(d, HCSCRATCH, s); \ | ||
494 | isp116x_show_reg_##type(d, HCITLBUFLEN, s); \ | ||
495 | isp116x_show_reg_##type(d, HCATLBUFLEN, s); \ | ||
496 | isp116x_show_reg_##type(d, HCBUFSTAT, s); \ | ||
497 | isp116x_show_reg_##type(d, HCRDITL0LEN, s); \ | ||
498 | isp116x_show_reg_##type(d, HCRDITL1LEN, s); \ | ||
499 | } | ||
500 | |||
501 | /* | ||
502 | Dump registers for debugfs. | ||
503 | */ | ||
504 | static inline void isp116x_show_regs_seq(struct isp116x *isp116x, | ||
505 | struct seq_file *s) | ||
506 | { | ||
507 | isp116x_show_regs(isp116x, seq, s); | ||
508 | } | ||
509 | |||
510 | /* | ||
511 | Dump registers to syslog. | ||
512 | */ | ||
513 | static inline void isp116x_show_regs_log(struct isp116x *isp116x) | ||
464 | { | 514 | { |
465 | isp116x_show_reg(isp116x, HCREVISION); | 515 | isp116x_show_regs(isp116x, log, NULL); |
466 | isp116x_show_reg(isp116x, HCCONTROL); | ||
467 | isp116x_show_reg(isp116x, HCCMDSTAT); | ||
468 | isp116x_show_reg(isp116x, HCINTSTAT); | ||
469 | isp116x_show_reg(isp116x, HCINTENB); | ||
470 | isp116x_show_reg(isp116x, HCFMINTVL); | ||
471 | isp116x_show_reg(isp116x, HCFMREM); | ||
472 | isp116x_show_reg(isp116x, HCFMNUM); | ||
473 | isp116x_show_reg(isp116x, HCLSTHRESH); | ||
474 | isp116x_show_reg(isp116x, HCRHDESCA); | ||
475 | isp116x_show_reg(isp116x, HCRHDESCB); | ||
476 | isp116x_show_reg(isp116x, HCRHSTATUS); | ||
477 | isp116x_show_reg(isp116x, HCRHPORT1); | ||
478 | isp116x_show_reg(isp116x, HCRHPORT2); | ||
479 | isp116x_show_reg(isp116x, HCHWCFG); | ||
480 | isp116x_show_reg(isp116x, HCDMACFG); | ||
481 | isp116x_show_reg(isp116x, HCXFERCTR); | ||
482 | isp116x_show_reg(isp116x, HCuPINT); | ||
483 | isp116x_show_reg(isp116x, HCuPINTENB); | ||
484 | isp116x_show_reg(isp116x, HCCHIPID); | ||
485 | isp116x_show_reg(isp116x, HCSCRATCH); | ||
486 | isp116x_show_reg(isp116x, HCITLBUFLEN); | ||
487 | isp116x_show_reg(isp116x, HCATLBUFLEN); | ||
488 | isp116x_show_reg(isp116x, HCBUFSTAT); | ||
489 | isp116x_show_reg(isp116x, HCRDITL0LEN); | ||
490 | isp116x_show_reg(isp116x, HCRDITL1LEN); | ||
491 | } | 516 | } |
492 | 517 | ||
493 | #if defined(URB_TRACE) | 518 | #if defined(URB_TRACE) |