diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ehci-sched.c | 2 | ||||
-rw-r--r-- | drivers/usb/host/whci/asl.c | 15 | ||||
-rw-r--r-- | drivers/usb/host/whci/hcd.c | 23 | ||||
-rw-r--r-- | drivers/usb/host/whci/pzl.c | 16 | ||||
-rw-r--r-- | drivers/usb/host/whci/qset.c | 24 | ||||
-rw-r--r-- | drivers/usb/host/whci/whcd.h | 1 | ||||
-rw-r--r-- | drivers/usb/host/whci/whci-hc.h | 1 |
7 files changed, 69 insertions, 13 deletions
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index ada5d2ba297b..556d0ec0c1f8 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c | |||
@@ -323,7 +323,7 @@ static int tt_available ( | |||
323 | * already scheduled transactions | 323 | * already scheduled transactions |
324 | */ | 324 | */ |
325 | if (125 < usecs) { | 325 | if (125 < usecs) { |
326 | int ufs = (usecs / 125) - 1; | 326 | int ufs = (usecs / 125); |
327 | int i; | 327 | int i; |
328 | for (i = uframe; i < (uframe + ufs) && i < 8; i++) | 328 | for (i = uframe; i < (uframe + ufs) && i < 8; i++) |
329 | if (0 < tt_usecs[i]) { | 329 | if (0 < tt_usecs[i]) { |
diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c index 958751ccea43..c2050785a819 100644 --- a/drivers/usb/host/whci/asl.c +++ b/drivers/usb/host/whci/asl.c | |||
@@ -122,7 +122,8 @@ static uint32_t process_qset(struct whc *whc, struct whc_qset *qset) | |||
122 | process_inactive_qtd(whc, qset, td); | 122 | process_inactive_qtd(whc, qset, td); |
123 | } | 123 | } |
124 | 124 | ||
125 | update |= qset_add_qtds(whc, qset); | 125 | if (!qset->remove) |
126 | update |= qset_add_qtds(whc, qset); | ||
126 | 127 | ||
127 | done: | 128 | done: |
128 | /* | 129 | /* |
@@ -254,23 +255,29 @@ int asl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags) | |||
254 | 255 | ||
255 | spin_lock_irqsave(&whc->lock, flags); | 256 | spin_lock_irqsave(&whc->lock, flags); |
256 | 257 | ||
258 | err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); | ||
259 | if (err < 0) { | ||
260 | spin_unlock_irqrestore(&whc->lock, flags); | ||
261 | return err; | ||
262 | } | ||
263 | |||
257 | qset = get_qset(whc, urb, GFP_ATOMIC); | 264 | qset = get_qset(whc, urb, GFP_ATOMIC); |
258 | if (qset == NULL) | 265 | if (qset == NULL) |
259 | err = -ENOMEM; | 266 | err = -ENOMEM; |
260 | else | 267 | else |
261 | err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); | 268 | err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); |
262 | if (!err) { | 269 | if (!err) { |
263 | usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); | ||
264 | if (!qset->in_sw_list) | 270 | if (!qset->in_sw_list) |
265 | asl_qset_insert_begin(whc, qset); | 271 | asl_qset_insert_begin(whc, qset); |
266 | } | 272 | } else |
273 | usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); | ||
267 | 274 | ||
268 | spin_unlock_irqrestore(&whc->lock, flags); | 275 | spin_unlock_irqrestore(&whc->lock, flags); |
269 | 276 | ||
270 | if (!err) | 277 | if (!err) |
271 | queue_work(whc->workqueue, &whc->async_work); | 278 | queue_work(whc->workqueue, &whc->async_work); |
272 | 279 | ||
273 | return 0; | 280 | return err; |
274 | } | 281 | } |
275 | 282 | ||
276 | /** | 283 | /** |
diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c index 1569afd6245b..e019a5058ab8 100644 --- a/drivers/usb/host/whci/hcd.c +++ b/drivers/usb/host/whci/hcd.c | |||
@@ -186,6 +186,28 @@ static void whc_endpoint_disable(struct usb_hcd *usb_hcd, | |||
186 | } | 186 | } |
187 | } | 187 | } |
188 | 188 | ||
189 | static void whc_endpoint_reset(struct usb_hcd *usb_hcd, | ||
190 | struct usb_host_endpoint *ep) | ||
191 | { | ||
192 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | ||
193 | struct whc *whc = wusbhc_to_whc(wusbhc); | ||
194 | struct whc_qset *qset; | ||
195 | |||
196 | qset = ep->hcpriv; | ||
197 | if (qset) { | ||
198 | qset->remove = 1; | ||
199 | |||
200 | if (usb_endpoint_xfer_bulk(&ep->desc) | ||
201 | || usb_endpoint_xfer_control(&ep->desc)) | ||
202 | queue_work(whc->workqueue, &whc->async_work); | ||
203 | else | ||
204 | queue_work(whc->workqueue, &whc->periodic_work); | ||
205 | |||
206 | qset_reset(whc, qset); | ||
207 | } | ||
208 | } | ||
209 | |||
210 | |||
189 | static struct hc_driver whc_hc_driver = { | 211 | static struct hc_driver whc_hc_driver = { |
190 | .description = "whci-hcd", | 212 | .description = "whci-hcd", |
191 | .product_desc = "Wireless host controller", | 213 | .product_desc = "Wireless host controller", |
@@ -200,6 +222,7 @@ static struct hc_driver whc_hc_driver = { | |||
200 | .urb_enqueue = whc_urb_enqueue, | 222 | .urb_enqueue = whc_urb_enqueue, |
201 | .urb_dequeue = whc_urb_dequeue, | 223 | .urb_dequeue = whc_urb_dequeue, |
202 | .endpoint_disable = whc_endpoint_disable, | 224 | .endpoint_disable = whc_endpoint_disable, |
225 | .endpoint_reset = whc_endpoint_reset, | ||
203 | 226 | ||
204 | .hub_status_data = wusbhc_rh_status_data, | 227 | .hub_status_data = wusbhc_rh_status_data, |
205 | .hub_control = wusbhc_rh_control, | 228 | .hub_control = wusbhc_rh_control, |
diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c index df8b85f07092..ff4ef9e910d9 100644 --- a/drivers/usb/host/whci/pzl.c +++ b/drivers/usb/host/whci/pzl.c | |||
@@ -128,7 +128,8 @@ static enum whc_update pzl_process_qset(struct whc *whc, struct whc_qset *qset) | |||
128 | process_inactive_qtd(whc, qset, td); | 128 | process_inactive_qtd(whc, qset, td); |
129 | } | 129 | } |
130 | 130 | ||
131 | update |= qset_add_qtds(whc, qset); | 131 | if (!qset->remove) |
132 | update |= qset_add_qtds(whc, qset); | ||
132 | 133 | ||
133 | done: | 134 | done: |
134 | /* | 135 | /* |
@@ -282,23 +283,29 @@ int pzl_urb_enqueue(struct whc *whc, struct urb *urb, gfp_t mem_flags) | |||
282 | 283 | ||
283 | spin_lock_irqsave(&whc->lock, flags); | 284 | spin_lock_irqsave(&whc->lock, flags); |
284 | 285 | ||
286 | err = usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); | ||
287 | if (err < 0) { | ||
288 | spin_unlock_irqrestore(&whc->lock, flags); | ||
289 | return err; | ||
290 | } | ||
291 | |||
285 | qset = get_qset(whc, urb, GFP_ATOMIC); | 292 | qset = get_qset(whc, urb, GFP_ATOMIC); |
286 | if (qset == NULL) | 293 | if (qset == NULL) |
287 | err = -ENOMEM; | 294 | err = -ENOMEM; |
288 | else | 295 | else |
289 | err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); | 296 | err = qset_add_urb(whc, qset, urb, GFP_ATOMIC); |
290 | if (!err) { | 297 | if (!err) { |
291 | usb_hcd_link_urb_to_ep(&whc->wusbhc.usb_hcd, urb); | ||
292 | if (!qset->in_sw_list) | 298 | if (!qset->in_sw_list) |
293 | qset_insert_in_sw_list(whc, qset); | 299 | qset_insert_in_sw_list(whc, qset); |
294 | } | 300 | } else |
301 | usb_hcd_unlink_urb_from_ep(&whc->wusbhc.usb_hcd, urb); | ||
295 | 302 | ||
296 | spin_unlock_irqrestore(&whc->lock, flags); | 303 | spin_unlock_irqrestore(&whc->lock, flags); |
297 | 304 | ||
298 | if (!err) | 305 | if (!err) |
299 | queue_work(whc->workqueue, &whc->periodic_work); | 306 | queue_work(whc->workqueue, &whc->periodic_work); |
300 | 307 | ||
301 | return 0; | 308 | return err; |
302 | } | 309 | } |
303 | 310 | ||
304 | /** | 311 | /** |
@@ -353,7 +360,6 @@ void pzl_qset_delete(struct whc *whc, struct whc_qset *qset) | |||
353 | qset_delete(whc, qset); | 360 | qset_delete(whc, qset); |
354 | } | 361 | } |
355 | 362 | ||
356 | |||
357 | /** | 363 | /** |
358 | * pzl_init - initialize the periodic zone list | 364 | * pzl_init - initialize the periodic zone list |
359 | * @whc: the WHCI host controller | 365 | * @whc: the WHCI host controller |
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index 7be74314ee12..640b38fbd051 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c | |||
@@ -89,11 +89,16 @@ static void qset_fill_qh(struct whc_qset *qset, struct urb *urb) | |||
89 | QH_INFO3_TX_RATE_53_3 | 89 | QH_INFO3_TX_RATE_53_3 |
90 | | QH_INFO3_TX_PWR(0) /* 0 == max power */ | 90 | | QH_INFO3_TX_PWR(0) /* 0 == max power */ |
91 | ); | 91 | ); |
92 | |||
93 | qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); | ||
92 | } | 94 | } |
93 | 95 | ||
94 | /** | 96 | /** |
95 | * qset_clear - clear fields in a qset so it may be reinserted into a | 97 | * qset_clear - clear fields in a qset so it may be reinserted into a |
96 | * schedule | 98 | * schedule. |
99 | * | ||
100 | * The sequence number and current window are not cleared (see | ||
101 | * qset_reset()). | ||
97 | */ | 102 | */ |
98 | void qset_clear(struct whc *whc, struct whc_qset *qset) | 103 | void qset_clear(struct whc *whc, struct whc_qset *qset) |
99 | { | 104 | { |
@@ -101,9 +106,8 @@ void qset_clear(struct whc *whc, struct whc_qset *qset) | |||
101 | qset->remove = 0; | 106 | qset->remove = 0; |
102 | 107 | ||
103 | qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); | 108 | qset->qh.link = cpu_to_le32(QH_LINK_NTDS(8) | QH_LINK_T); |
104 | qset->qh.status = cpu_to_le16(QH_STATUS_ICUR(qset->td_start)); | 109 | qset->qh.status = qset->qh.status & QH_STATUS_SEQ_MASK; |
105 | qset->qh.err_count = 0; | 110 | qset->qh.err_count = 0; |
106 | qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); | ||
107 | qset->qh.scratch[0] = 0; | 111 | qset->qh.scratch[0] = 0; |
108 | qset->qh.scratch[1] = 0; | 112 | qset->qh.scratch[1] = 0; |
109 | qset->qh.scratch[2] = 0; | 113 | qset->qh.scratch[2] = 0; |
@@ -114,6 +118,20 @@ void qset_clear(struct whc *whc, struct whc_qset *qset) | |||
114 | } | 118 | } |
115 | 119 | ||
116 | /** | 120 | /** |
121 | * qset_reset - reset endpoint state in a qset. | ||
122 | * | ||
123 | * Clears the sequence number and current window. This qset must not | ||
124 | * be in the ASL or PZL. | ||
125 | */ | ||
126 | void qset_reset(struct whc *whc, struct whc_qset *qset) | ||
127 | { | ||
128 | wait_for_completion(&qset->remove_complete); | ||
129 | |||
130 | qset->qh.status &= ~QH_STATUS_SEQ_MASK; | ||
131 | qset->qh.cur_window = cpu_to_le32((1 << qset->max_burst) - 1); | ||
132 | } | ||
133 | |||
134 | /** | ||
117 | * get_qset - get the qset for an async endpoint | 135 | * get_qset - get the qset for an async endpoint |
118 | * | 136 | * |
119 | * A new qset is created if one does not already exist. | 137 | * A new qset is created if one does not already exist. |
diff --git a/drivers/usb/host/whci/whcd.h b/drivers/usb/host/whci/whcd.h index d3543a181dc9..24e94d983c5e 100644 --- a/drivers/usb/host/whci/whcd.h +++ b/drivers/usb/host/whci/whcd.h | |||
@@ -184,6 +184,7 @@ void qset_free(struct whc *whc, struct whc_qset *qset); | |||
184 | struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags); | 184 | struct whc_qset *get_qset(struct whc *whc, struct urb *urb, gfp_t mem_flags); |
185 | void qset_delete(struct whc *whc, struct whc_qset *qset); | 185 | void qset_delete(struct whc *whc, struct whc_qset *qset); |
186 | void qset_clear(struct whc *whc, struct whc_qset *qset); | 186 | void qset_clear(struct whc *whc, struct whc_qset *qset); |
187 | void qset_reset(struct whc *whc, struct whc_qset *qset); | ||
187 | int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb, | 188 | int qset_add_urb(struct whc *whc, struct whc_qset *qset, struct urb *urb, |
188 | gfp_t mem_flags); | 189 | gfp_t mem_flags); |
189 | void qset_free_std(struct whc *whc, struct whc_std *std); | 190 | void qset_free_std(struct whc *whc, struct whc_std *std); |
diff --git a/drivers/usb/host/whci/whci-hc.h b/drivers/usb/host/whci/whci-hc.h index 51df7e313b38..794dba0d0f0a 100644 --- a/drivers/usb/host/whci/whci-hc.h +++ b/drivers/usb/host/whci/whci-hc.h | |||
@@ -185,6 +185,7 @@ struct whc_qhead { | |||
185 | #define QH_STATUS_FLOW_CTRL (1 << 15) | 185 | #define QH_STATUS_FLOW_CTRL (1 << 15) |
186 | #define QH_STATUS_ICUR(i) ((i) << 5) | 186 | #define QH_STATUS_ICUR(i) ((i) << 5) |
187 | #define QH_STATUS_TO_ICUR(s) (((s) >> 5) & 0x7) | 187 | #define QH_STATUS_TO_ICUR(s) (((s) >> 5) & 0x7) |
188 | #define QH_STATUS_SEQ_MASK 0x1f | ||
188 | 189 | ||
189 | /** | 190 | /** |
190 | * usb_pipe_to_qh_type - USB core pipe type to QH transfer type | 191 | * usb_pipe_to_qh_type - USB core pipe type to QH transfer type |