diff options
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/hwa-hc.c | 104 | ||||
-rw-r--r-- | drivers/usb/host/whci/Kbuild | 1 | ||||
-rw-r--r-- | drivers/usb/host/whci/asl.c | 46 | ||||
-rw-r--r-- | drivers/usb/host/whci/debug.c | 189 | ||||
-rw-r--r-- | drivers/usb/host/whci/hcd.c | 6 | ||||
-rw-r--r-- | drivers/usb/host/whci/hw.c | 8 | ||||
-rw-r--r-- | drivers/usb/host/whci/int.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/whci/pzl.c | 49 | ||||
-rw-r--r-- | drivers/usb/host/whci/qset.c | 40 | ||||
-rw-r--r-- | drivers/usb/host/whci/whcd.h | 11 | ||||
-rw-r--r-- | drivers/usb/host/whci/whci-hc.h | 2 | ||||
-rw-r--r-- | drivers/usb/host/whci/wusb.c | 43 |
12 files changed, 305 insertions, 195 deletions
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c index 64be4d88df11..2a4d36fa70b0 100644 --- a/drivers/usb/host/hwa-hc.c +++ b/drivers/usb/host/hwa-hc.c | |||
@@ -54,7 +54,6 @@ | |||
54 | * DWA). | 54 | * DWA). |
55 | */ | 55 | */ |
56 | #include <linux/kernel.h> | 56 | #include <linux/kernel.h> |
57 | #include <linux/version.h> | ||
58 | #include <linux/init.h> | 57 | #include <linux/init.h> |
59 | #include <linux/module.h> | 58 | #include <linux/module.h> |
60 | #include <linux/workqueue.h> | 59 | #include <linux/workqueue.h> |
@@ -171,11 +170,6 @@ static int hwahc_op_start(struct usb_hcd *usb_hcd) | |||
171 | if (result < 0) | 170 | if (result < 0) |
172 | goto error_set_cluster_id; | 171 | goto error_set_cluster_id; |
173 | 172 | ||
174 | result = wa_nep_arm(&hwahc->wa, GFP_KERNEL); | ||
175 | if (result < 0) { | ||
176 | dev_err(dev, "cannot listen to notifications: %d\n", result); | ||
177 | goto error_stop; | ||
178 | } | ||
179 | usb_hcd->uses_new_polling = 1; | 173 | usb_hcd->uses_new_polling = 1; |
180 | usb_hcd->poll_rh = 1; | 174 | usb_hcd->poll_rh = 1; |
181 | usb_hcd->state = HC_STATE_RUNNING; | 175 | usb_hcd->state = HC_STATE_RUNNING; |
@@ -185,8 +179,6 @@ out: | |||
185 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | 179 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); |
186 | return result; | 180 | return result; |
187 | 181 | ||
188 | error_stop: | ||
189 | __wa_stop(&hwahc->wa); | ||
190 | error_set_cluster_id: | 182 | error_set_cluster_id: |
191 | wusb_cluster_id_put(wusbhc->cluster_id); | 183 | wusb_cluster_id_put(wusbhc->cluster_id); |
192 | error_cluster_id_get: | 184 | error_cluster_id_get: |
@@ -194,39 +186,6 @@ error_cluster_id_get: | |||
194 | 186 | ||
195 | } | 187 | } |
196 | 188 | ||
197 | /* | ||
198 | * FIXME: break this function up | ||
199 | */ | ||
200 | static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc) | ||
201 | { | ||
202 | int result; | ||
203 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
204 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
205 | |||
206 | /* Set up a Host Info WUSB Information Element */ | ||
207 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
208 | result = -ENOSPC; | ||
209 | |||
210 | result = __wa_set_feature(&hwahc->wa, WA_ENABLE); | ||
211 | if (result < 0) { | ||
212 | dev_err(dev, "error commanding HC to start: %d\n", result); | ||
213 | goto error_stop; | ||
214 | } | ||
215 | result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE); | ||
216 | if (result < 0) { | ||
217 | dev_err(dev, "error waiting for HC to start: %d\n", result); | ||
218 | goto error_stop; | ||
219 | } | ||
220 | result = 0; | ||
221 | out: | ||
222 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
223 | return result; | ||
224 | |||
225 | error_stop: | ||
226 | result = __wa_clear_feature(&hwahc->wa, WA_ENABLE); | ||
227 | goto out; | ||
228 | } | ||
229 | |||
230 | static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg) | 189 | static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg) |
231 | { | 190 | { |
232 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); | 191 | struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); |
@@ -246,18 +205,6 @@ static int hwahc_op_resume(struct usb_hcd *usb_hcd) | |||
246 | return -ENOSYS; | 205 | return -ENOSYS; |
247 | } | 206 | } |
248 | 207 | ||
249 | static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc) | ||
250 | { | ||
251 | int result; | ||
252 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
253 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
254 | |||
255 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | ||
256 | /* Nothing for now */ | ||
257 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | ||
258 | return; | ||
259 | } | ||
260 | |||
261 | /* | 208 | /* |
262 | * No need to abort pipes, as when this is called, all the children | 209 | * No need to abort pipes, as when this is called, all the children |
263 | * has been disconnected and that has done it [through | 210 | * has been disconnected and that has done it [through |
@@ -274,9 +221,6 @@ static void hwahc_op_stop(struct usb_hcd *usb_hcd) | |||
274 | 221 | ||
275 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); | 222 | d_fnstart(4, dev, "(hwahc %p)\n", hwahc); |
276 | mutex_lock(&wusbhc->mutex); | 223 | mutex_lock(&wusbhc->mutex); |
277 | wusbhc_stop(wusbhc); | ||
278 | wa_nep_disarm(&hwahc->wa); | ||
279 | result = __wa_stop(&hwahc->wa); | ||
280 | wusb_cluster_id_put(wusbhc->cluster_id); | 224 | wusb_cluster_id_put(wusbhc->cluster_id); |
281 | mutex_unlock(&wusbhc->mutex); | 225 | mutex_unlock(&wusbhc->mutex); |
282 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); | 226 | d_fnend(4, dev, "(hwahc %p) = %d\n", hwahc, result); |
@@ -325,6 +269,54 @@ static void hwahc_op_endpoint_disable(struct usb_hcd *usb_hcd, | |||
325 | rpipe_ep_disable(&hwahc->wa, ep); | 269 | rpipe_ep_disable(&hwahc->wa, ep); |
326 | } | 270 | } |
327 | 271 | ||
272 | static int __hwahc_op_wusbhc_start(struct wusbhc *wusbhc) | ||
273 | { | ||
274 | int result; | ||
275 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
276 | struct device *dev = &hwahc->wa.usb_iface->dev; | ||
277 | |||
278 | result = __wa_set_feature(&hwahc->wa, WA_ENABLE); | ||
279 | if (result < 0) { | ||
280 | dev_err(dev, "error commanding HC to start: %d\n", result); | ||
281 | goto error_stop; | ||
282 | } | ||
283 | result = __wa_wait_status(&hwahc->wa, WA_ENABLE, WA_ENABLE); | ||
284 | if (result < 0) { | ||
285 | dev_err(dev, "error waiting for HC to start: %d\n", result); | ||
286 | goto error_stop; | ||
287 | } | ||
288 | result = wa_nep_arm(&hwahc->wa, GFP_KERNEL); | ||
289 | if (result < 0) { | ||
290 | dev_err(dev, "cannot listen to notifications: %d\n", result); | ||
291 | goto error_stop; | ||
292 | } | ||
293 | return result; | ||
294 | |||
295 | error_stop: | ||
296 | __wa_clear_feature(&hwahc->wa, WA_ENABLE); | ||
297 | return result; | ||
298 | } | ||
299 | |||
300 | static void __hwahc_op_wusbhc_stop(struct wusbhc *wusbhc, int delay) | ||
301 | { | ||
302 | struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc); | ||
303 | struct wahc *wa = &hwahc->wa; | ||
304 | u8 iface_no = wa->usb_iface->cur_altsetting->desc.bInterfaceNumber; | ||
305 | int ret; | ||
306 | |||
307 | ret = usb_control_msg(wa->usb_dev, usb_sndctrlpipe(wa->usb_dev, 0), | ||
308 | WUSB_REQ_CHAN_STOP, | ||
309 | USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE, | ||
310 | delay * 1000, | ||
311 | iface_no, | ||
312 | NULL, 0, 1000 /* FIXME: arbitrary */); | ||
313 | if (ret == 0) | ||
314 | msleep(delay); | ||
315 | |||
316 | wa_nep_disarm(&hwahc->wa); | ||
317 | __wa_stop(&hwahc->wa); | ||
318 | } | ||
319 | |||
328 | /* | 320 | /* |
329 | * Set the UWB MAS allocation for the WUSB cluster | 321 | * Set the UWB MAS allocation for the WUSB cluster |
330 | * | 322 | * |
diff --git a/drivers/usb/host/whci/Kbuild b/drivers/usb/host/whci/Kbuild index 26a3871ea0f9..11e5040b8337 100644 --- a/drivers/usb/host/whci/Kbuild +++ b/drivers/usb/host/whci/Kbuild | |||
@@ -2,6 +2,7 @@ obj-$(CONFIG_USB_WHCI_HCD) += whci-hcd.o | |||
2 | 2 | ||
3 | whci-hcd-y := \ | 3 | whci-hcd-y := \ |
4 | asl.o \ | 4 | asl.o \ |
5 | debug.o \ | ||
5 | hcd.o \ | 6 | hcd.o \ |
6 | hw.o \ | 7 | hw.o \ |
7 | init.o \ | 8 | init.o \ |
diff --git a/drivers/usb/host/whci/asl.c b/drivers/usb/host/whci/asl.c index 4d7078e50572..577c0d29849d 100644 --- a/drivers/usb/host/whci/asl.c +++ b/drivers/usb/host/whci/asl.c | |||
@@ -19,32 +19,11 @@ | |||
19 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
20 | #include <linux/uwb/umc.h> | 20 | #include <linux/uwb/umc.h> |
21 | #include <linux/usb.h> | 21 | #include <linux/usb.h> |
22 | #define D_LOCAL 0 | ||
23 | #include <linux/uwb/debug.h> | ||
24 | 22 | ||
25 | #include "../../wusbcore/wusbhc.h" | 23 | #include "../../wusbcore/wusbhc.h" |
26 | 24 | ||
27 | #include "whcd.h" | 25 | #include "whcd.h" |
28 | 26 | ||
29 | #if D_LOCAL >= 4 | ||
30 | static void dump_asl(struct whc *whc, const char *tag) | ||
31 | { | ||
32 | struct device *dev = &whc->umc->dev; | ||
33 | struct whc_qset *qset; | ||
34 | |||
35 | d_printf(4, dev, "ASL %s\n", tag); | ||
36 | |||
37 | list_for_each_entry(qset, &whc->async_list, list_node) { | ||
38 | dump_qset(qset, dev); | ||
39 | } | ||
40 | } | ||
41 | #else | ||
42 | static inline void dump_asl(struct whc *whc, const char *tag) | ||
43 | { | ||
44 | } | ||
45 | #endif | ||
46 | |||
47 | |||
48 | static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset, | 27 | static void qset_get_next_prev(struct whc *whc, struct whc_qset *qset, |
49 | struct whc_qset **next, struct whc_qset **prev) | 28 | struct whc_qset **next, struct whc_qset **prev) |
50 | { | 29 | { |
@@ -179,11 +158,26 @@ void asl_stop(struct whc *whc) | |||
179 | 1000, "stop ASL"); | 158 | 1000, "stop ASL"); |
180 | } | 159 | } |
181 | 160 | ||
161 | /** | ||
162 | * asl_update - request an ASL update and wait for the hardware to be synced | ||
163 | * @whc: the WHCI HC | ||
164 | * @wusbcmd: WUSBCMD value to start the update. | ||
165 | * | ||
166 | * If the WUSB HC is inactive (i.e., the ASL is stopped) then the | ||
167 | * update must be skipped as the hardware may not respond to update | ||
168 | * requests. | ||
169 | */ | ||
182 | void asl_update(struct whc *whc, uint32_t wusbcmd) | 170 | void asl_update(struct whc *whc, uint32_t wusbcmd) |
183 | { | 171 | { |
184 | whc_write_wusbcmd(whc, wusbcmd, wusbcmd); | 172 | struct wusbhc *wusbhc = &whc->wusbhc; |
185 | wait_event(whc->async_list_wq, | 173 | |
186 | (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0); | 174 | mutex_lock(&wusbhc->mutex); |
175 | if (wusbhc->active) { | ||
176 | whc_write_wusbcmd(whc, wusbcmd, wusbcmd); | ||
177 | wait_event(whc->async_list_wq, | ||
178 | (le_readl(whc->base + WUSBCMD) & WUSBCMD_ASYNC_UPDATED) == 0); | ||
179 | } | ||
180 | mutex_unlock(&wusbhc->mutex); | ||
187 | } | 181 | } |
188 | 182 | ||
189 | /** | 183 | /** |
@@ -202,8 +196,6 @@ void scan_async_work(struct work_struct *work) | |||
202 | 196 | ||
203 | spin_lock_irq(&whc->lock); | 197 | spin_lock_irq(&whc->lock); |
204 | 198 | ||
205 | dump_asl(whc, "before processing"); | ||
206 | |||
207 | /* | 199 | /* |
208 | * Transerve the software list backwards so new qsets can be | 200 | * Transerve the software list backwards so new qsets can be |
209 | * safely inserted into the ASL without making it non-circular. | 201 | * safely inserted into the ASL without making it non-circular. |
@@ -217,8 +209,6 @@ void scan_async_work(struct work_struct *work) | |||
217 | update |= process_qset(whc, qset); | 209 | update |= process_qset(whc, qset); |
218 | } | 210 | } |
219 | 211 | ||
220 | dump_asl(whc, "after processing"); | ||
221 | |||
222 | spin_unlock_irq(&whc->lock); | 212 | spin_unlock_irq(&whc->lock); |
223 | 213 | ||
224 | if (update) { | 214 | if (update) { |
diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c new file mode 100644 index 000000000000..cf2d45946c57 --- /dev/null +++ b/drivers/usb/host/whci/debug.c | |||
@@ -0,0 +1,189 @@ | |||
1 | /* | ||
2 | * Wireless Host Controller (WHC) debug. | ||
3 | * | ||
4 | * Copyright (C) 2008 Cambridge Silicon Radio Ltd. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License version | ||
8 | * 2 as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/debugfs.h> | ||
20 | #include <linux/seq_file.h> | ||
21 | |||
22 | #include "../../wusbcore/wusbhc.h" | ||
23 | |||
24 | #include "whcd.h" | ||
25 | |||
26 | struct whc_dbg { | ||
27 | struct dentry *di_f; | ||
28 | struct dentry *asl_f; | ||
29 | struct dentry *pzl_f; | ||
30 | }; | ||
31 | |||
32 | void qset_print(struct seq_file *s, struct whc_qset *qset) | ||
33 | { | ||
34 | struct whc_std *std; | ||
35 | struct urb *urb = NULL; | ||
36 | int i; | ||
37 | |||
38 | seq_printf(s, "qset %08x\n", (u32)qset->qset_dma); | ||
39 | seq_printf(s, " -> %08x\n", (u32)qset->qh.link); | ||
40 | seq_printf(s, " info: %08x %08x %08x\n", | ||
41 | qset->qh.info1, qset->qh.info2, qset->qh.info3); | ||
42 | seq_printf(s, " sts: %04x errs: %d\n", qset->qh.status, qset->qh.err_count); | ||
43 | seq_printf(s, " TD: sts: %08x opts: %08x\n", | ||
44 | qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options); | ||
45 | |||
46 | for (i = 0; i < WHCI_QSET_TD_MAX; i++) { | ||
47 | seq_printf(s, " %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n", | ||
48 | i == qset->td_start ? 'S' : ' ', | ||
49 | i == qset->td_end ? 'E' : ' ', | ||
50 | i, qset->qtd[i].status, qset->qtd[i].options, | ||
51 | (u32)qset->qtd[i].page_list_ptr); | ||
52 | } | ||
53 | seq_printf(s, " ntds: %d\n", qset->ntds); | ||
54 | list_for_each_entry(std, &qset->stds, list_node) { | ||
55 | if (urb != std->urb) { | ||
56 | urb = std->urb; | ||
57 | seq_printf(s, " urb %p transferred: %d bytes\n", urb, | ||
58 | urb->actual_length); | ||
59 | } | ||
60 | if (std->qtd) | ||
61 | seq_printf(s, " sTD[%td]: %zu bytes @ %08x\n", | ||
62 | std->qtd - &qset->qtd[0], | ||
63 | std->len, std->num_pointers ? | ||
64 | (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); | ||
65 | else | ||
66 | seq_printf(s, " sTD[-]: %zd bytes @ %08x\n", | ||
67 | std->len, std->num_pointers ? | ||
68 | (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | static int di_print(struct seq_file *s, void *p) | ||
73 | { | ||
74 | struct whc *whc = s->private; | ||
75 | char buf[72]; | ||
76 | int d; | ||
77 | |||
78 | for (d = 0; d < whc->n_devices; d++) { | ||
79 | struct di_buf_entry *di = &whc->di_buf[d]; | ||
80 | |||
81 | bitmap_scnprintf(buf, sizeof(buf), | ||
82 | (unsigned long *)di->availability_info, UWB_NUM_MAS); | ||
83 | |||
84 | seq_printf(s, "DI[%d]\n", d); | ||
85 | seq_printf(s, " availability: %s\n", buf); | ||
86 | seq_printf(s, " %c%c key idx: %d dev addr: %d\n", | ||
87 | (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ', | ||
88 | (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ', | ||
89 | (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8, | ||
90 | (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK)); | ||
91 | } | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int asl_print(struct seq_file *s, void *p) | ||
96 | { | ||
97 | struct whc *whc = s->private; | ||
98 | struct whc_qset *qset; | ||
99 | |||
100 | list_for_each_entry(qset, &whc->async_list, list_node) { | ||
101 | qset_print(s, qset); | ||
102 | } | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static int pzl_print(struct seq_file *s, void *p) | ||
108 | { | ||
109 | struct whc *whc = s->private; | ||
110 | struct whc_qset *qset; | ||
111 | int period; | ||
112 | |||
113 | for (period = 0; period < 5; period++) { | ||
114 | seq_printf(s, "Period %d\n", period); | ||
115 | list_for_each_entry(qset, &whc->periodic_list[period], list_node) { | ||
116 | qset_print(s, qset); | ||
117 | } | ||
118 | } | ||
119 | return 0; | ||
120 | } | ||
121 | |||
122 | static int di_open(struct inode *inode, struct file *file) | ||
123 | { | ||
124 | return single_open(file, di_print, inode->i_private); | ||
125 | } | ||
126 | |||
127 | static int asl_open(struct inode *inode, struct file *file) | ||
128 | { | ||
129 | return single_open(file, asl_print, inode->i_private); | ||
130 | } | ||
131 | |||
132 | static int pzl_open(struct inode *inode, struct file *file) | ||
133 | { | ||
134 | return single_open(file, pzl_print, inode->i_private); | ||
135 | } | ||
136 | |||
137 | static struct file_operations di_fops = { | ||
138 | .open = di_open, | ||
139 | .read = seq_read, | ||
140 | .llseek = seq_lseek, | ||
141 | .release = single_release, | ||
142 | .owner = THIS_MODULE, | ||
143 | }; | ||
144 | |||
145 | static struct file_operations asl_fops = { | ||
146 | .open = asl_open, | ||
147 | .read = seq_read, | ||
148 | .llseek = seq_lseek, | ||
149 | .release = single_release, | ||
150 | .owner = THIS_MODULE, | ||
151 | }; | ||
152 | |||
153 | static struct file_operations pzl_fops = { | ||
154 | .open = pzl_open, | ||
155 | .read = seq_read, | ||
156 | .llseek = seq_lseek, | ||
157 | .release = single_release, | ||
158 | .owner = THIS_MODULE, | ||
159 | }; | ||
160 | |||
161 | void whc_dbg_init(struct whc *whc) | ||
162 | { | ||
163 | if (whc->wusbhc.pal.debugfs_dir == NULL) | ||
164 | return; | ||
165 | |||
166 | whc->dbg = kzalloc(sizeof(struct whc_dbg), GFP_KERNEL); | ||
167 | if (whc->dbg == NULL) | ||
168 | return; | ||
169 | |||
170 | whc->dbg->di_f = debugfs_create_file("di", 0444, | ||
171 | whc->wusbhc.pal.debugfs_dir, whc, | ||
172 | &di_fops); | ||
173 | whc->dbg->asl_f = debugfs_create_file("asl", 0444, | ||
174 | whc->wusbhc.pal.debugfs_dir, whc, | ||
175 | &asl_fops); | ||
176 | whc->dbg->pzl_f = debugfs_create_file("pzl", 0444, | ||
177 | whc->wusbhc.pal.debugfs_dir, whc, | ||
178 | &pzl_fops); | ||
179 | } | ||
180 | |||
181 | void whc_dbg_clean_up(struct whc *whc) | ||
182 | { | ||
183 | if (whc->dbg) { | ||
184 | debugfs_remove(whc->dbg->pzl_f); | ||
185 | debugfs_remove(whc->dbg->asl_f); | ||
186 | debugfs_remove(whc->dbg->di_f); | ||
187 | kfree(whc->dbg); | ||
188 | } | ||
189 | } | ||
diff --git a/drivers/usb/host/whci/hcd.c b/drivers/usb/host/whci/hcd.c index ef3ad4dca945..1569afd6245b 100644 --- a/drivers/usb/host/whci/hcd.c +++ b/drivers/usb/host/whci/hcd.c | |||
@@ -15,7 +15,6 @@ | |||
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | */ | 17 | */ |
18 | #include <linux/version.h> | ||
19 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
20 | #include <linux/init.h> | 19 | #include <linux/init.h> |
21 | #include <linux/uwb/umc.h> | 20 | #include <linux/uwb/umc.h> |
@@ -92,8 +91,6 @@ static void whc_stop(struct usb_hcd *usb_hcd) | |||
92 | 91 | ||
93 | mutex_lock(&wusbhc->mutex); | 92 | mutex_lock(&wusbhc->mutex); |
94 | 93 | ||
95 | wusbhc_stop(wusbhc); | ||
96 | |||
97 | /* stop HC */ | 94 | /* stop HC */ |
98 | le_writel(0, whc->base + WUSBINTR); | 95 | le_writel(0, whc->base + WUSBINTR); |
99 | whc_write_wusbcmd(whc, WUSBCMD_RUN, 0); | 96 | whc_write_wusbcmd(whc, WUSBCMD_RUN, 0); |
@@ -276,6 +273,8 @@ static int whc_probe(struct umc_dev *umc) | |||
276 | goto error_wusbhc_b_create; | 273 | goto error_wusbhc_b_create; |
277 | } | 274 | } |
278 | 275 | ||
276 | whc_dbg_init(whc); | ||
277 | |||
279 | return 0; | 278 | return 0; |
280 | 279 | ||
281 | error_wusbhc_b_create: | 280 | error_wusbhc_b_create: |
@@ -299,6 +298,7 @@ static void whc_remove(struct umc_dev *umc) | |||
299 | struct whc *whc = wusbhc_to_whc(wusbhc); | 298 | struct whc *whc = wusbhc_to_whc(wusbhc); |
300 | 299 | ||
301 | if (usb_hcd) { | 300 | if (usb_hcd) { |
301 | whc_dbg_clean_up(whc); | ||
302 | wusbhc_b_destroy(wusbhc); | 302 | wusbhc_b_destroy(wusbhc); |
303 | usb_remove_hcd(usb_hcd); | 303 | usb_remove_hcd(usb_hcd); |
304 | wusbhc_destroy(wusbhc); | 304 | wusbhc_destroy(wusbhc); |
diff --git a/drivers/usb/host/whci/hw.c b/drivers/usb/host/whci/hw.c index ac86e59c1225..d498e7203217 100644 --- a/drivers/usb/host/whci/hw.c +++ b/drivers/usb/host/whci/hw.c | |||
@@ -50,6 +50,7 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len) | |||
50 | unsigned long flags; | 50 | unsigned long flags; |
51 | dma_addr_t dma_addr; | 51 | dma_addr_t dma_addr; |
52 | int t; | 52 | int t; |
53 | int ret = 0; | ||
53 | 54 | ||
54 | mutex_lock(&whc->mutex); | 55 | mutex_lock(&whc->mutex); |
55 | 56 | ||
@@ -61,7 +62,8 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len) | |||
61 | dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n", | 62 | dev_err(&whc->umc->dev, "generic command timeout (%04x/%04x)\n", |
62 | le_readl(whc->base + WUSBGENCMDSTS), | 63 | le_readl(whc->base + WUSBGENCMDSTS), |
63 | le_readl(whc->base + WUSBGENCMDPARAMS)); | 64 | le_readl(whc->base + WUSBGENCMDPARAMS)); |
64 | return -ETIMEDOUT; | 65 | ret = -ETIMEDOUT; |
66 | goto out; | ||
65 | } | 67 | } |
66 | 68 | ||
67 | if (addr) { | 69 | if (addr) { |
@@ -80,8 +82,8 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len) | |||
80 | whc->base + WUSBGENCMDSTS); | 82 | whc->base + WUSBGENCMDSTS); |
81 | 83 | ||
82 | spin_unlock_irqrestore(&whc->lock, flags); | 84 | spin_unlock_irqrestore(&whc->lock, flags); |
83 | 85 | out: | |
84 | mutex_unlock(&whc->mutex); | 86 | mutex_unlock(&whc->mutex); |
85 | 87 | ||
86 | return 0; | 88 | return ret; |
87 | } | 89 | } |
diff --git a/drivers/usb/host/whci/int.c b/drivers/usb/host/whci/int.c index fce01174aa9b..6aae70028101 100644 --- a/drivers/usb/host/whci/int.c +++ b/drivers/usb/host/whci/int.c | |||
@@ -15,7 +15,6 @@ | |||
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | */ | 17 | */ |
18 | #include <linux/version.h> | ||
19 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
20 | #include <linux/init.h> | 19 | #include <linux/init.h> |
21 | #include <linux/uwb/umc.h> | 20 | #include <linux/uwb/umc.h> |
diff --git a/drivers/usb/host/whci/pzl.c b/drivers/usb/host/whci/pzl.c index 8d62df0c330b..2ae5abf69a6a 100644 --- a/drivers/usb/host/whci/pzl.c +++ b/drivers/usb/host/whci/pzl.c | |||
@@ -19,35 +19,11 @@ | |||
19 | #include <linux/dma-mapping.h> | 19 | #include <linux/dma-mapping.h> |
20 | #include <linux/uwb/umc.h> | 20 | #include <linux/uwb/umc.h> |
21 | #include <linux/usb.h> | 21 | #include <linux/usb.h> |
22 | #define D_LOCAL 0 | ||
23 | #include <linux/uwb/debug.h> | ||
24 | 22 | ||
25 | #include "../../wusbcore/wusbhc.h" | 23 | #include "../../wusbcore/wusbhc.h" |
26 | 24 | ||
27 | #include "whcd.h" | 25 | #include "whcd.h" |
28 | 26 | ||
29 | #if D_LOCAL >= 4 | ||
30 | static void dump_pzl(struct whc *whc, const char *tag) | ||
31 | { | ||
32 | struct device *dev = &whc->umc->dev; | ||
33 | struct whc_qset *qset; | ||
34 | int period = 0; | ||
35 | |||
36 | d_printf(4, dev, "PZL %s\n", tag); | ||
37 | |||
38 | for (period = 0; period < 5; period++) { | ||
39 | d_printf(4, dev, "Period %d\n", period); | ||
40 | list_for_each_entry(qset, &whc->periodic_list[period], list_node) { | ||
41 | dump_qset(qset, dev); | ||
42 | } | ||
43 | } | ||
44 | } | ||
45 | #else | ||
46 | static inline void dump_pzl(struct whc *whc, const char *tag) | ||
47 | { | ||
48 | } | ||
49 | #endif | ||
50 | |||
51 | static void update_pzl_pointers(struct whc *whc, int period, u64 addr) | 27 | static void update_pzl_pointers(struct whc *whc, int period, u64 addr) |
52 | { | 28 | { |
53 | switch (period) { | 29 | switch (period) { |
@@ -195,11 +171,26 @@ void pzl_stop(struct whc *whc) | |||
195 | 1000, "stop PZL"); | 171 | 1000, "stop PZL"); |
196 | } | 172 | } |
197 | 173 | ||
174 | /** | ||
175 | * pzl_update - request a PZL update and wait for the hardware to be synced | ||
176 | * @whc: the WHCI HC | ||
177 | * @wusbcmd: WUSBCMD value to start the update. | ||
178 | * | ||
179 | * If the WUSB HC is inactive (i.e., the PZL is stopped) then the | ||
180 | * update must be skipped as the hardware may not respond to update | ||
181 | * requests. | ||
182 | */ | ||
198 | void pzl_update(struct whc *whc, uint32_t wusbcmd) | 183 | void pzl_update(struct whc *whc, uint32_t wusbcmd) |
199 | { | 184 | { |
200 | whc_write_wusbcmd(whc, wusbcmd, wusbcmd); | 185 | struct wusbhc *wusbhc = &whc->wusbhc; |
201 | wait_event(whc->periodic_list_wq, | 186 | |
202 | (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0); | 187 | mutex_lock(&wusbhc->mutex); |
188 | if (wusbhc->active) { | ||
189 | whc_write_wusbcmd(whc, wusbcmd, wusbcmd); | ||
190 | wait_event(whc->periodic_list_wq, | ||
191 | (le_readl(whc->base + WUSBCMD) & WUSBCMD_PERIODIC_UPDATED) == 0); | ||
192 | } | ||
193 | mutex_unlock(&wusbhc->mutex); | ||
203 | } | 194 | } |
204 | 195 | ||
205 | static void update_pzl_hw_view(struct whc *whc) | 196 | static void update_pzl_hw_view(struct whc *whc) |
@@ -235,8 +226,6 @@ void scan_periodic_work(struct work_struct *work) | |||
235 | 226 | ||
236 | spin_lock_irq(&whc->lock); | 227 | spin_lock_irq(&whc->lock); |
237 | 228 | ||
238 | dump_pzl(whc, "before processing"); | ||
239 | |||
240 | for (period = 4; period >= 0; period--) { | 229 | for (period = 4; period >= 0; period--) { |
241 | list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) { | 230 | list_for_each_entry_safe(qset, t, &whc->periodic_list[period], list_node) { |
242 | if (!qset->in_hw_list) | 231 | if (!qset->in_hw_list) |
@@ -248,8 +237,6 @@ void scan_periodic_work(struct work_struct *work) | |||
248 | if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED)) | 237 | if (update & (WHC_UPDATE_ADDED | WHC_UPDATE_REMOVED)) |
249 | update_pzl_hw_view(whc); | 238 | update_pzl_hw_view(whc); |
250 | 239 | ||
251 | dump_pzl(whc, "after processing"); | ||
252 | |||
253 | spin_unlock_irq(&whc->lock); | 240 | spin_unlock_irq(&whc->lock); |
254 | 241 | ||
255 | if (update) { | 242 | if (update) { |
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c index 0420037d2e18..7be74314ee12 100644 --- a/drivers/usb/host/whci/qset.c +++ b/drivers/usb/host/whci/qset.c | |||
@@ -24,46 +24,6 @@ | |||
24 | 24 | ||
25 | #include "whcd.h" | 25 | #include "whcd.h" |
26 | 26 | ||
27 | void dump_qset(struct whc_qset *qset, struct device *dev) | ||
28 | { | ||
29 | struct whc_std *std; | ||
30 | struct urb *urb = NULL; | ||
31 | int i; | ||
32 | |||
33 | dev_dbg(dev, "qset %08x\n", (u32)qset->qset_dma); | ||
34 | dev_dbg(dev, " -> %08x\n", (u32)qset->qh.link); | ||
35 | dev_dbg(dev, " info: %08x %08x %08x\n", | ||
36 | qset->qh.info1, qset->qh.info2, qset->qh.info3); | ||
37 | dev_dbg(dev, " sts: %04x errs: %d\n", qset->qh.status, qset->qh.err_count); | ||
38 | dev_dbg(dev, " TD: sts: %08x opts: %08x\n", | ||
39 | qset->qh.overlay.qtd.status, qset->qh.overlay.qtd.options); | ||
40 | |||
41 | for (i = 0; i < WHCI_QSET_TD_MAX; i++) { | ||
42 | dev_dbg(dev, " %c%c TD[%d]: sts: %08x opts: %08x ptr: %08x\n", | ||
43 | i == qset->td_start ? 'S' : ' ', | ||
44 | i == qset->td_end ? 'E' : ' ', | ||
45 | i, qset->qtd[i].status, qset->qtd[i].options, | ||
46 | (u32)qset->qtd[i].page_list_ptr); | ||
47 | } | ||
48 | dev_dbg(dev, " ntds: %d\n", qset->ntds); | ||
49 | list_for_each_entry(std, &qset->stds, list_node) { | ||
50 | if (urb != std->urb) { | ||
51 | urb = std->urb; | ||
52 | dev_dbg(dev, " urb %p transferred: %d bytes\n", urb, | ||
53 | urb->actual_length); | ||
54 | } | ||
55 | if (std->qtd) | ||
56 | dev_dbg(dev, " sTD[%td]: %zu bytes @ %08x\n", | ||
57 | std->qtd - &qset->qtd[0], | ||
58 | std->len, std->num_pointers ? | ||
59 | (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); | ||
60 | else | ||
61 | dev_dbg(dev, " sTD[-]: %zd bytes @ %08x\n", | ||
62 | std->len, std->num_pointers ? | ||
63 | (u32)(std->pl_virt[0].buf_ptr) : (u32)std->dma_addr); | ||
64 | } | ||
65 | } | ||
66 | |||
67 | struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags) | 27 | struct whc_qset *qset_alloc(struct whc *whc, gfp_t mem_flags) |
68 | { | 28 | { |
69 | struct whc_qset *qset; | 29 | struct whc_qset *qset; |
diff --git a/drivers/usb/host/whci/whcd.h b/drivers/usb/host/whci/whcd.h index 1d2a53bd39fd..0f3540f04f53 100644 --- a/drivers/usb/host/whci/whcd.h +++ b/drivers/usb/host/whci/whcd.h | |||
@@ -21,6 +21,7 @@ | |||
21 | #define __WHCD_H | 21 | #define __WHCD_H |
22 | 22 | ||
23 | #include <linux/uwb/whci.h> | 23 | #include <linux/uwb/whci.h> |
24 | #include <linux/uwb/umc.h> | ||
24 | #include <linux/workqueue.h> | 25 | #include <linux/workqueue.h> |
25 | 26 | ||
26 | #include "whci-hc.h" | 27 | #include "whci-hc.h" |
@@ -28,6 +29,7 @@ | |||
28 | /* Generic command timeout. */ | 29 | /* Generic command timeout. */ |
29 | #define WHC_GENCMD_TIMEOUT_MS 100 | 30 | #define WHC_GENCMD_TIMEOUT_MS 100 |
30 | 31 | ||
32 | struct whc_dbg; | ||
31 | 33 | ||
32 | struct whc { | 34 | struct whc { |
33 | struct wusbhc wusbhc; | 35 | struct wusbhc wusbhc; |
@@ -69,6 +71,8 @@ struct whc { | |||
69 | struct list_head periodic_removed_list; | 71 | struct list_head periodic_removed_list; |
70 | wait_queue_head_t periodic_list_wq; | 72 | wait_queue_head_t periodic_list_wq; |
71 | struct work_struct periodic_work; | 73 | struct work_struct periodic_work; |
74 | |||
75 | struct whc_dbg *dbg; | ||
72 | }; | 76 | }; |
73 | 77 | ||
74 | #define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc)) | 78 | #define wusbhc_to_whc(w) (container_of((w), struct whc, wusbhc)) |
@@ -136,7 +140,7 @@ int whc_do_gencmd(struct whc *whc, u32 cmd, u32 params, void *addr, size_t len); | |||
136 | 140 | ||
137 | /* wusb.c */ | 141 | /* wusb.c */ |
138 | int whc_wusbhc_start(struct wusbhc *wusbhc); | 142 | int whc_wusbhc_start(struct wusbhc *wusbhc); |
139 | void whc_wusbhc_stop(struct wusbhc *wusbhc); | 143 | void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay); |
140 | int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, | 144 | int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, |
141 | u8 handle, struct wuie_hdr *wuie); | 145 | u8 handle, struct wuie_hdr *wuie); |
142 | int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle); | 146 | int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle); |
@@ -190,8 +194,11 @@ void process_inactive_qtd(struct whc *whc, struct whc_qset *qset, | |||
190 | struct whc_qtd *qtd); | 194 | struct whc_qtd *qtd); |
191 | enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset); | 195 | enum whc_update qset_add_qtds(struct whc *whc, struct whc_qset *qset); |
192 | void qset_remove_complete(struct whc *whc, struct whc_qset *qset); | 196 | void qset_remove_complete(struct whc *whc, struct whc_qset *qset); |
193 | void dump_qset(struct whc_qset *qset, struct device *dev); | ||
194 | void pzl_update(struct whc *whc, uint32_t wusbcmd); | 197 | void pzl_update(struct whc *whc, uint32_t wusbcmd); |
195 | void asl_update(struct whc *whc, uint32_t wusbcmd); | 198 | void asl_update(struct whc *whc, uint32_t wusbcmd); |
196 | 199 | ||
200 | /* debug.c */ | ||
201 | void whc_dbg_init(struct whc *whc); | ||
202 | void whc_dbg_clean_up(struct whc *whc); | ||
203 | |||
197 | #endif /* #ifndef __WHCD_H */ | 204 | #endif /* #ifndef __WHCD_H */ |
diff --git a/drivers/usb/host/whci/whci-hc.h b/drivers/usb/host/whci/whci-hc.h index bff1eb7a35cf..51df7e313b38 100644 --- a/drivers/usb/host/whci/whci-hc.h +++ b/drivers/usb/host/whci/whci-hc.h | |||
@@ -410,6 +410,8 @@ struct dn_buf_entry { | |||
410 | # define WUSBDNTSCTRL_SLOTS(s) ((s) << 0) | 410 | # define WUSBDNTSCTRL_SLOTS(s) ((s) << 0) |
411 | 411 | ||
412 | #define WUSBTIME 0x68 | 412 | #define WUSBTIME 0x68 |
413 | # define WUSBTIME_CHANNEL_TIME_MASK 0x00ffffff | ||
414 | |||
413 | #define WUSBBPST 0x6c | 415 | #define WUSBBPST 0x6c |
414 | #define WUSBDIBUPDATED 0x70 | 416 | #define WUSBDIBUPDATED 0x70 |
415 | 417 | ||
diff --git a/drivers/usb/host/whci/wusb.c b/drivers/usb/host/whci/wusb.c index 66e4ddcd961d..f24efdebad17 100644 --- a/drivers/usb/host/whci/wusb.c +++ b/drivers/usb/host/whci/wusb.c | |||
@@ -15,47 +15,19 @@ | |||
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | */ | 17 | */ |
18 | #include <linux/version.h> | ||
19 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
20 | #include <linux/init.h> | 19 | #include <linux/init.h> |
21 | #include <linux/uwb/umc.h> | 20 | #include <linux/uwb/umc.h> |
22 | #define D_LOCAL 1 | ||
23 | #include <linux/uwb/debug.h> | ||
24 | 21 | ||
25 | #include "../../wusbcore/wusbhc.h" | 22 | #include "../../wusbcore/wusbhc.h" |
26 | 23 | ||
27 | #include "whcd.h" | 24 | #include "whcd.h" |
28 | 25 | ||
29 | #if D_LOCAL >= 1 | ||
30 | static void dump_di(struct whc *whc, int idx) | ||
31 | { | ||
32 | struct di_buf_entry *di = &whc->di_buf[idx]; | ||
33 | struct device *dev = &whc->umc->dev; | ||
34 | char buf[128]; | ||
35 | |||
36 | bitmap_scnprintf(buf, sizeof(buf), (unsigned long *)di->availability_info, UWB_NUM_MAS); | ||
37 | |||
38 | d_printf(1, dev, "DI[%d]\n", idx); | ||
39 | d_printf(1, dev, " availability: %s\n", buf); | ||
40 | d_printf(1, dev, " %c%c key idx: %d dev addr: %d\n", | ||
41 | (di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ', | ||
42 | (di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ', | ||
43 | (di->addr_sec_info & WHC_DI_KEY_IDX_MASK) >> 8, | ||
44 | (di->addr_sec_info & WHC_DI_DEV_ADDR_MASK)); | ||
45 | } | ||
46 | #else | ||
47 | static inline void dump_di(struct whc *whc, int idx) | ||
48 | { | ||
49 | } | ||
50 | #endif | ||
51 | |||
52 | static int whc_update_di(struct whc *whc, int idx) | 26 | static int whc_update_di(struct whc *whc, int idx) |
53 | { | 27 | { |
54 | int offset = idx / 32; | 28 | int offset = idx / 32; |
55 | u32 bit = 1 << (idx % 32); | 29 | u32 bit = 1 << (idx % 32); |
56 | 30 | ||
57 | dump_di(whc, idx); | ||
58 | |||
59 | le_writel(bit, whc->base + WUSBDIBUPDATED + offset); | 31 | le_writel(bit, whc->base + WUSBDIBUPDATED + offset); |
60 | 32 | ||
61 | return whci_wait_for(&whc->umc->dev, | 33 | return whci_wait_for(&whc->umc->dev, |
@@ -64,8 +36,9 @@ static int whc_update_di(struct whc *whc, int idx) | |||
64 | } | 36 | } |
65 | 37 | ||
66 | /* | 38 | /* |
67 | * WHCI starts and stops MMCs based on there being a valid GTK so | 39 | * WHCI starts MMCs based on there being a valid GTK so these need |
68 | * these need only start/stop the asynchronous and periodic schedules. | 40 | * only start/stop the asynchronous and periodic schedules and send a |
41 | * channel stop command. | ||
69 | */ | 42 | */ |
70 | 43 | ||
71 | int whc_wusbhc_start(struct wusbhc *wusbhc) | 44 | int whc_wusbhc_start(struct wusbhc *wusbhc) |
@@ -78,12 +51,20 @@ int whc_wusbhc_start(struct wusbhc *wusbhc) | |||
78 | return 0; | 51 | return 0; |
79 | } | 52 | } |
80 | 53 | ||
81 | void whc_wusbhc_stop(struct wusbhc *wusbhc) | 54 | void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay) |
82 | { | 55 | { |
83 | struct whc *whc = wusbhc_to_whc(wusbhc); | 56 | struct whc *whc = wusbhc_to_whc(wusbhc); |
57 | u32 stop_time, now_time; | ||
58 | int ret; | ||
84 | 59 | ||
85 | pzl_stop(whc); | 60 | pzl_stop(whc); |
86 | asl_stop(whc); | 61 | asl_stop(whc); |
62 | |||
63 | now_time = le_readl(whc->base + WUSBTIME) & WUSBTIME_CHANNEL_TIME_MASK; | ||
64 | stop_time = (now_time + ((delay * 8) << 7)) & 0x00ffffff; | ||
65 | ret = whc_do_gencmd(whc, WUSBGENCMDSTS_CHAN_STOP, stop_time, NULL, 0); | ||
66 | if (ret == 0) | ||
67 | msleep(delay); | ||
87 | } | 68 | } |
88 | 69 | ||
89 | int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, | 70 | int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt, |