sl811-hcd.c (288ead45fa6637e959015d055304f521cbbc0575) sl811-hcd.c (749da5f82fe33ff68dd4aa1a5e35cd9aa6246dab)
1/*
2 * SL811HS HCD (Host Controller Driver) for USB.
3 *
4 * Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
5 * Copyright (C) 2004-2005 David Brownell
6 *
7 * Periodic scheduling is based on Roman's OHCI code
8 * Copyright (C) 1999 Roman Weissgaerber

--- 76 unchanged lines hidden (view full) ---

85/*-------------------------------------------------------------------------*/
86
87static void port_power(struct sl811 *sl811, int is_on)
88{
89 struct usb_hcd *hcd = sl811_to_hcd(sl811);
90
91 /* hub is inactive unless the port is powered */
92 if (is_on) {
1/*
2 * SL811HS HCD (Host Controller Driver) for USB.
3 *
4 * Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
5 * Copyright (C) 2004-2005 David Brownell
6 *
7 * Periodic scheduling is based on Roman's OHCI code
8 * Copyright (C) 1999 Roman Weissgaerber

--- 76 unchanged lines hidden (view full) ---

85/*-------------------------------------------------------------------------*/
86
87static void port_power(struct sl811 *sl811, int is_on)
88{
89 struct usb_hcd *hcd = sl811_to_hcd(sl811);
90
91 /* hub is inactive unless the port is powered */
92 if (is_on) {
93 if (sl811->port1 & (1 << USB_PORT_FEAT_POWER))
93 if (sl811->port1 & USB_PORT_STAT_POWER)
94 return;
95
94 return;
95
96 sl811->port1 = (1 << USB_PORT_FEAT_POWER);
96 sl811->port1 = USB_PORT_STAT_POWER;
97 sl811->irq_enable = SL11H_INTMASK_INSRMV;
98 } else {
99 sl811->port1 = 0;
100 sl811->irq_enable = 0;
101 hcd->state = HC_STATE_HALT;
102 }
103 sl811->ctrl1 = 0;
104 sl811_write(sl811, SL11H_IRQ_ENABLE, 0);

--- 297 unchanged lines hidden (view full) ---

402 }
403 return ep;
404}
405
406#define MIN_JIFFIES ((msecs_to_jiffies(2) > 1) ? msecs_to_jiffies(2) : 2)
407
408static inline void start_transfer(struct sl811 *sl811)
409{
97 sl811->irq_enable = SL11H_INTMASK_INSRMV;
98 } else {
99 sl811->port1 = 0;
100 sl811->irq_enable = 0;
101 hcd->state = HC_STATE_HALT;
102 }
103 sl811->ctrl1 = 0;
104 sl811_write(sl811, SL11H_IRQ_ENABLE, 0);

--- 297 unchanged lines hidden (view full) ---

402 }
403 return ep;
404}
405
406#define MIN_JIFFIES ((msecs_to_jiffies(2) > 1) ? msecs_to_jiffies(2) : 2)
407
408static inline void start_transfer(struct sl811 *sl811)
409{
410 if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND))
410 if (sl811->port1 & USB_PORT_STAT_SUSPEND)
411 return;
412 if (sl811->active_a == NULL) {
413 sl811->active_a = start(sl811, SL811_EP_A(SL811_HOST_BUF));
414 if (sl811->active_a != NULL)
415 sl811->jiffies_a = jiffies + MIN_JIFFIES;
416 }
417#ifdef USE_B
418 if (sl811->active_b == NULL) {

--- 297 unchanged lines hidden (view full) ---

716 sl811->active_b = NULL;
717 }
718#endif
719
720 /* port status seems weird until after reset, so
721 * force the reset and make khubd clean up later.
722 */
723 if (irqstat & SL11H_INTMASK_RD)
411 return;
412 if (sl811->active_a == NULL) {
413 sl811->active_a = start(sl811, SL811_EP_A(SL811_HOST_BUF));
414 if (sl811->active_a != NULL)
415 sl811->jiffies_a = jiffies + MIN_JIFFIES;
416 }
417#ifdef USE_B
418 if (sl811->active_b == NULL) {

--- 297 unchanged lines hidden (view full) ---

716 sl811->active_b = NULL;
717 }
718#endif
719
720 /* port status seems weird until after reset, so
721 * force the reset and make khubd clean up later.
722 */
723 if (irqstat & SL11H_INTMASK_RD)
724 sl811->port1 &= ~(1 << USB_PORT_FEAT_CONNECTION);
724 sl811->port1 &= ~USB_PORT_STAT_CONNECTION;
725 else
725 else
726 sl811->port1 |= 1 << USB_PORT_FEAT_CONNECTION;
726 sl811->port1 |= USB_PORT_STAT_CONNECTION;
727
727
728 sl811->port1 |= 1 << USB_PORT_FEAT_C_CONNECTION;
728 sl811->port1 |= USB_PORT_STAT_C_CONNECTION << 16;
729
730 } else if (irqstat & SL11H_INTMASK_RD) {
729
730 } else if (irqstat & SL11H_INTMASK_RD) {
731 if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)) {
731 if (sl811->port1 & USB_PORT_STAT_SUSPEND) {
732 DBG("wakeup\n");
732 DBG("wakeup\n");
733 sl811->port1 |= 1 << USB_PORT_FEAT_C_SUSPEND;
733 sl811->port1 |= USB_PORT_STAT_C_SUSPEND << 16;
734 sl811->stat_wake++;
735 } else
736 irqstat &= ~SL11H_INTMASK_RD;
737 }
738
739 if (irqstat) {
734 sl811->stat_wake++;
735 } else
736 irqstat &= ~SL11H_INTMASK_RD;
737 }
738
739 if (irqstat) {
740 if (sl811->port1 & (1 << USB_PORT_FEAT_ENABLE))
740 if (sl811->port1 & USB_PORT_STAT_ENABLE)
741 start_transfer(sl811);
742 ret = IRQ_HANDLED;
743 if (retries--)
744 goto retry;
745 }
746
747 if (sl811->periodic_count == 0 && list_empty(&sl811->async))
748 sofirq_off(sl811);

--- 65 unchanged lines hidden (view full) ---

814
815 /* avoid all allocations within spinlocks */
816 if (!hep->hcpriv)
817 ep = kzalloc(sizeof *ep, mem_flags);
818
819 spin_lock_irqsave(&sl811->lock, flags);
820
821 /* don't submit to a dead or disabled port */
741 start_transfer(sl811);
742 ret = IRQ_HANDLED;
743 if (retries--)
744 goto retry;
745 }
746
747 if (sl811->periodic_count == 0 && list_empty(&sl811->async))
748 sofirq_off(sl811);

--- 65 unchanged lines hidden (view full) ---

814
815 /* avoid all allocations within spinlocks */
816 if (!hep->hcpriv)
817 ep = kzalloc(sizeof *ep, mem_flags);
818
819 spin_lock_irqsave(&sl811->lock, flags);
820
821 /* don't submit to a dead or disabled port */
822 if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE))
822 if (!(sl811->port1 & USB_PORT_STAT_ENABLE)
823 || !HC_IS_RUNNING(hcd->state)) {
824 retval = -ENODEV;
825 kfree(ep);
826 goto fail_not_linked;
827 }
828 retval = usb_hcd_link_urb_to_ep(hcd, urb);
829 if (retval) {
830 kfree(ep);

--- 283 unchanged lines hidden (view full) ---

1114
1115static void
1116sl811h_timer(unsigned long _sl811)
1117{
1118 struct sl811 *sl811 = (void *) _sl811;
1119 unsigned long flags;
1120 u8 irqstat;
1121 u8 signaling = sl811->ctrl1 & SL11H_CTL1MASK_FORCE;
823 || !HC_IS_RUNNING(hcd->state)) {
824 retval = -ENODEV;
825 kfree(ep);
826 goto fail_not_linked;
827 }
828 retval = usb_hcd_link_urb_to_ep(hcd, urb);
829 if (retval) {
830 kfree(ep);

--- 283 unchanged lines hidden (view full) ---

1114
1115static void
1116sl811h_timer(unsigned long _sl811)
1117{
1118 struct sl811 *sl811 = (void *) _sl811;
1119 unsigned long flags;
1120 u8 irqstat;
1121 u8 signaling = sl811->ctrl1 & SL11H_CTL1MASK_FORCE;
1122 const u32 mask = (1 << USB_PORT_FEAT_CONNECTION)
1123 | (1 << USB_PORT_FEAT_ENABLE)
1122 const u32 mask = USB_PORT_STAT_CONNECTION
1123 | USB_PORT_STAT_ENABLE
1124 | USB_PORT_STAT_LOW_SPEED;
1125
1126 spin_lock_irqsave(&sl811->lock, flags);
1127
1128 /* stop special signaling */
1129 sl811->ctrl1 &= ~SL11H_CTL1MASK_FORCE;
1130 sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
1131 udelay(3);
1132
1133 irqstat = sl811_read(sl811, SL11H_IRQ_STATUS);
1134
1135 switch (signaling) {
1136 case SL11H_CTL1MASK_SE0:
1137 DBG("end reset\n");
1124 | USB_PORT_STAT_LOW_SPEED;
1125
1126 spin_lock_irqsave(&sl811->lock, flags);
1127
1128 /* stop special signaling */
1129 sl811->ctrl1 &= ~SL11H_CTL1MASK_FORCE;
1130 sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
1131 udelay(3);
1132
1133 irqstat = sl811_read(sl811, SL11H_IRQ_STATUS);
1134
1135 switch (signaling) {
1136 case SL11H_CTL1MASK_SE0:
1137 DBG("end reset\n");
1138 sl811->port1 = (1 << USB_PORT_FEAT_C_RESET)
1139 | (1 << USB_PORT_FEAT_POWER);
1138 sl811->port1 = (USB_PORT_STAT_C_RESET << 16)
1139 | USB_PORT_STAT_POWER;
1140 sl811->ctrl1 = 0;
1141 /* don't wrongly ack RD */
1142 if (irqstat & SL11H_INTMASK_INSRMV)
1143 irqstat &= ~SL11H_INTMASK_RD;
1144 break;
1145 case SL11H_CTL1MASK_K:
1146 DBG("end resume\n");
1140 sl811->ctrl1 = 0;
1141 /* don't wrongly ack RD */
1142 if (irqstat & SL11H_INTMASK_INSRMV)
1143 irqstat &= ~SL11H_INTMASK_RD;
1144 break;
1145 case SL11H_CTL1MASK_K:
1146 DBG("end resume\n");
1147 sl811->port1 &= ~(1 << USB_PORT_FEAT_SUSPEND);
1147 sl811->port1 &= ~USB_PORT_STAT_SUSPEND;
1148 break;
1149 default:
1150 DBG("odd timer signaling: %02x\n", signaling);
1151 break;
1152 }
1153 sl811_write(sl811, SL11H_IRQ_STATUS, irqstat);
1154
1155 if (irqstat & SL11H_INTMASK_RD) {
1156 /* usbcore nukes all pending transactions on disconnect */
1148 break;
1149 default:
1150 DBG("odd timer signaling: %02x\n", signaling);
1151 break;
1152 }
1153 sl811_write(sl811, SL11H_IRQ_STATUS, irqstat);
1154
1155 if (irqstat & SL11H_INTMASK_RD) {
1156 /* usbcore nukes all pending transactions on disconnect */
1157 if (sl811->port1 & (1 << USB_PORT_FEAT_CONNECTION))
1158 sl811->port1 |= (1 << USB_PORT_FEAT_C_CONNECTION)
1159 | (1 << USB_PORT_FEAT_C_ENABLE);
1157 if (sl811->port1 & USB_PORT_STAT_CONNECTION)
1158 sl811->port1 |= (USB_PORT_STAT_C_CONNECTION << 16)
1159 | (USB_PORT_STAT_C_ENABLE << 16);
1160 sl811->port1 &= ~mask;
1161 sl811->irq_enable = SL11H_INTMASK_INSRMV;
1162 } else {
1163 sl811->port1 |= mask;
1164 if (irqstat & SL11H_INTMASK_DP)
1165 sl811->port1 &= ~USB_PORT_STAT_LOW_SPEED;
1166 sl811->irq_enable = SL11H_INTMASK_INSRMV | SL11H_INTMASK_RD;
1167 }
1168
1160 sl811->port1 &= ~mask;
1161 sl811->irq_enable = SL11H_INTMASK_INSRMV;
1162 } else {
1163 sl811->port1 |= mask;
1164 if (irqstat & SL11H_INTMASK_DP)
1165 sl811->port1 &= ~USB_PORT_STAT_LOW_SPEED;
1166 sl811->irq_enable = SL11H_INTMASK_INSRMV | SL11H_INTMASK_RD;
1167 }
1168
1169 if (sl811->port1 & (1 << USB_PORT_FEAT_CONNECTION)) {
1169 if (sl811->port1 & USB_PORT_STAT_CONNECTION) {
1170 u8 ctrl2 = SL811HS_CTL2_INIT;
1171
1172 sl811->irq_enable |= SL11H_INTMASK_DONE_A;
1173#ifdef USE_B
1174 sl811->irq_enable |= SL11H_INTMASK_DONE_B;
1175#endif
1176 if (sl811->port1 & USB_PORT_STAT_LOW_SPEED) {
1177 sl811->ctrl1 |= SL11H_CTL1MASK_LSPD;

--- 50 unchanged lines hidden (view full) ---

1228 }
1229 break;
1230 case ClearPortFeature:
1231 if (wIndex != 1 || wLength != 0)
1232 goto error;
1233
1234 switch (wValue) {
1235 case USB_PORT_FEAT_ENABLE:
1170 u8 ctrl2 = SL811HS_CTL2_INIT;
1171
1172 sl811->irq_enable |= SL11H_INTMASK_DONE_A;
1173#ifdef USE_B
1174 sl811->irq_enable |= SL11H_INTMASK_DONE_B;
1175#endif
1176 if (sl811->port1 & USB_PORT_STAT_LOW_SPEED) {
1177 sl811->ctrl1 |= SL11H_CTL1MASK_LSPD;

--- 50 unchanged lines hidden (view full) ---

1228 }
1229 break;
1230 case ClearPortFeature:
1231 if (wIndex != 1 || wLength != 0)
1232 goto error;
1233
1234 switch (wValue) {
1235 case USB_PORT_FEAT_ENABLE:
1236 sl811->port1 &= (1 << USB_PORT_FEAT_POWER);
1236 sl811->port1 &= USB_PORT_STAT_POWER;
1237 sl811->ctrl1 = 0;
1238 sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
1239 sl811->irq_enable = SL11H_INTMASK_INSRMV;
1240 sl811_write(sl811, SL11H_IRQ_ENABLE,
1241 sl811->irq_enable);
1242 break;
1243 case USB_PORT_FEAT_SUSPEND:
1237 sl811->ctrl1 = 0;
1238 sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
1239 sl811->irq_enable = SL11H_INTMASK_INSRMV;
1240 sl811_write(sl811, SL11H_IRQ_ENABLE,
1241 sl811->irq_enable);
1242 break;
1243 case USB_PORT_FEAT_SUSPEND:
1244 if (!(sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND)))
1244 if (!(sl811->port1 & USB_PORT_STAT_SUSPEND))
1245 break;
1246
1247 /* 20 msec of resume/K signaling, other irqs blocked */
1248 DBG("start resume...\n");
1249 sl811->irq_enable = 0;
1250 sl811_write(sl811, SL11H_IRQ_ENABLE,
1251 sl811->irq_enable);
1252 sl811->ctrl1 |= SL11H_CTL1MASK_K;

--- 32 unchanged lines hidden (view full) ---

1285#endif
1286 DBG("GetPortStatus %08x\n", sl811->port1);
1287 break;
1288 case SetPortFeature:
1289 if (wIndex != 1 || wLength != 0)
1290 goto error;
1291 switch (wValue) {
1292 case USB_PORT_FEAT_SUSPEND:
1245 break;
1246
1247 /* 20 msec of resume/K signaling, other irqs blocked */
1248 DBG("start resume...\n");
1249 sl811->irq_enable = 0;
1250 sl811_write(sl811, SL11H_IRQ_ENABLE,
1251 sl811->irq_enable);
1252 sl811->ctrl1 |= SL11H_CTL1MASK_K;

--- 32 unchanged lines hidden (view full) ---

1285#endif
1286 DBG("GetPortStatus %08x\n", sl811->port1);
1287 break;
1288 case SetPortFeature:
1289 if (wIndex != 1 || wLength != 0)
1290 goto error;
1291 switch (wValue) {
1292 case USB_PORT_FEAT_SUSPEND:
1293 if (sl811->port1 & (1 << USB_PORT_FEAT_RESET))
1293 if (sl811->port1 & USB_PORT_STAT_RESET)
1294 goto error;
1294 goto error;
1295 if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE)))
1295 if (!(sl811->port1 & USB_PORT_STAT_ENABLE))
1296 goto error;
1297
1298 DBG("suspend...\n");
1299 sl811->ctrl1 &= ~SL11H_CTL1MASK_SOF_ENA;
1300 sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
1301 break;
1302 case USB_PORT_FEAT_POWER:
1303 port_power(sl811, 1);
1304 break;
1305 case USB_PORT_FEAT_RESET:
1296 goto error;
1297
1298 DBG("suspend...\n");
1299 sl811->ctrl1 &= ~SL11H_CTL1MASK_SOF_ENA;
1300 sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
1301 break;
1302 case USB_PORT_FEAT_POWER:
1303 port_power(sl811, 1);
1304 break;
1305 case USB_PORT_FEAT_RESET:
1306 if (sl811->port1 & (1 << USB_PORT_FEAT_SUSPEND))
1306 if (sl811->port1 & USB_PORT_STAT_SUSPEND)
1307 goto error;
1307 goto error;
1308 if (!(sl811->port1 & (1 << USB_PORT_FEAT_POWER)))
1308 if (!(sl811->port1 & USB_PORT_STAT_POWER))
1309 break;
1310
1311 /* 50 msec of reset/SE0 signaling, irqs blocked */
1312 sl811->irq_enable = 0;
1313 sl811_write(sl811, SL11H_IRQ_ENABLE,
1314 sl811->irq_enable);
1315 sl811->ctrl1 = SL11H_CTL1MASK_SE0;
1316 sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
1309 break;
1310
1311 /* 50 msec of reset/SE0 signaling, irqs blocked */
1312 sl811->irq_enable = 0;
1313 sl811_write(sl811, SL11H_IRQ_ENABLE,
1314 sl811->irq_enable);
1315 sl811->ctrl1 = SL11H_CTL1MASK_SE0;
1316 sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
1317 sl811->port1 |= (1 << USB_PORT_FEAT_RESET);
1317 sl811->port1 |= USB_PORT_STAT_RESET;
1318 mod_timer(&sl811->timer, jiffies
1319 + msecs_to_jiffies(50));
1320 break;
1321 default:
1322 goto error;
1323 }
1324 sl811->port1 |= 1 << wValue;
1325 break;

--- 512 unchanged lines hidden ---
1318 mod_timer(&sl811->timer, jiffies
1319 + msecs_to_jiffies(50));
1320 break;
1321 default:
1322 goto error;
1323 }
1324 sl811->port1 |= 1 << wValue;
1325 break;

--- 512 unchanged lines hidden ---