diff options
author | Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | 2011-10-11 01:07:40 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2011-10-13 13:41:52 -0400 |
commit | 034d7c13a79c67d3b52dd782d68e6c324613878a (patch) | |
tree | 7fb097e30b0ac121450101da3f9ddfbb8f5f60a2 /drivers/usb/renesas_usbhs | |
parent | e2eddc6103c7f00a2a1a0dfe5fac494d039b099a (diff) |
usb: gadget: renesas_usbhs: add mod_host support
This is mod_host prototype support for renesas_usbhs driver.
It doesn't support USB-Hub, and USB-DMAC for now.
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/renesas_usbhs')
-rw-r--r-- | drivers/usb/renesas_usbhs/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/mod.c | 9 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/mod.h | 15 | ||||
-rw-r--r-- | drivers/usb/renesas_usbhs/mod_host.c | 1313 |
4 files changed, 1336 insertions, 2 deletions
diff --git a/drivers/usb/renesas_usbhs/Makefile b/drivers/usb/renesas_usbhs/Makefile index ce08345fa15a..e44984d233f7 100644 --- a/drivers/usb/renesas_usbhs/Makefile +++ b/drivers/usb/renesas_usbhs/Makefile | |||
@@ -6,4 +6,5 @@ obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs.o | |||
6 | 6 | ||
7 | renesas_usbhs-y := common.o mod.o pipe.o fifo.o | 7 | renesas_usbhs-y := common.o mod.o pipe.o fifo.o |
8 | 8 | ||
9 | renesas_usbhs-$(CONFIG_USB_RENESAS_USBHS_HCD) += mod_host.o | ||
9 | renesas_usbhs-$(CONFIG_USB_RENESAS_USBHS_UDC) += mod_gadget.o | 10 | renesas_usbhs-$(CONFIG_USB_RENESAS_USBHS_UDC) += mod_gadget.o |
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index 993c2ca4f0ca..2d3b09d0d846 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c | |||
@@ -140,10 +140,14 @@ int usbhs_mod_probe(struct usbhs_priv *priv) | |||
140 | /* | 140 | /* |
141 | * install host/gadget driver | 141 | * install host/gadget driver |
142 | */ | 142 | */ |
143 | ret = usbhs_mod_gadget_probe(priv); | 143 | ret = usbhs_mod_host_probe(priv); |
144 | if (ret < 0) | 144 | if (ret < 0) |
145 | return ret; | 145 | return ret; |
146 | 146 | ||
147 | ret = usbhs_mod_gadget_probe(priv); | ||
148 | if (ret < 0) | ||
149 | goto mod_init_host_err; | ||
150 | |||
147 | /* irq settings */ | 151 | /* irq settings */ |
148 | ret = request_irq(priv->irq, usbhs_interrupt, | 152 | ret = request_irq(priv->irq, usbhs_interrupt, |
149 | 0, dev_name(dev), priv); | 153 | 0, dev_name(dev), priv); |
@@ -156,12 +160,15 @@ int usbhs_mod_probe(struct usbhs_priv *priv) | |||
156 | 160 | ||
157 | mod_init_gadget_err: | 161 | mod_init_gadget_err: |
158 | usbhs_mod_gadget_remove(priv); | 162 | usbhs_mod_gadget_remove(priv); |
163 | mod_init_host_err: | ||
164 | usbhs_mod_host_remove(priv); | ||
159 | 165 | ||
160 | return ret; | 166 | return ret; |
161 | } | 167 | } |
162 | 168 | ||
163 | void usbhs_mod_remove(struct usbhs_priv *priv) | 169 | void usbhs_mod_remove(struct usbhs_priv *priv) |
164 | { | 170 | { |
171 | usbhs_mod_host_remove(priv); | ||
165 | usbhs_mod_gadget_remove(priv); | 172 | usbhs_mod_gadget_remove(priv); |
166 | free_irq(priv->irq, priv); | 173 | free_irq(priv->irq, priv); |
167 | } | 174 | } |
diff --git a/drivers/usb/renesas_usbhs/mod.h b/drivers/usb/renesas_usbhs/mod.h index df4b61dab313..1f28ed2e9abe 100644 --- a/drivers/usb/renesas_usbhs/mod.h +++ b/drivers/usb/renesas_usbhs/mod.h | |||
@@ -139,8 +139,21 @@ void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod); | |||
139 | }) | 139 | }) |
140 | 140 | ||
141 | /* | 141 | /* |
142 | * gadget control | 142 | * host / gadget control |
143 | */ | 143 | */ |
144 | #ifdef CONFIG_USB_RENESAS_USBHS_HCD | ||
145 | extern int __devinit usbhs_mod_host_probe(struct usbhs_priv *priv); | ||
146 | extern int __devexit usbhs_mod_host_remove(struct usbhs_priv *priv); | ||
147 | #else | ||
148 | static inline int usbhs_mod_host_probe(struct usbhs_priv *priv) | ||
149 | { | ||
150 | return 0; | ||
151 | } | ||
152 | static inline void usbhs_mod_host_remove(struct usbhs_priv *priv) | ||
153 | { | ||
154 | } | ||
155 | #endif | ||
156 | |||
144 | #ifdef CONFIG_USB_RENESAS_USBHS_UDC | 157 | #ifdef CONFIG_USB_RENESAS_USBHS_UDC |
145 | extern int __devinit usbhs_mod_gadget_probe(struct usbhs_priv *priv); | 158 | extern int __devinit usbhs_mod_gadget_probe(struct usbhs_priv *priv); |
146 | extern void __devexit usbhs_mod_gadget_remove(struct usbhs_priv *priv); | 159 | extern void __devexit usbhs_mod_gadget_remove(struct usbhs_priv *priv); |
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c new file mode 100644 index 000000000000..1c603310f9f8 --- /dev/null +++ b/drivers/usb/renesas_usbhs/mod_host.c | |||
@@ -0,0 +1,1313 @@ | |||
1 | /* | ||
2 | * Renesas USB driver | ||
3 | * | ||
4 | * Copyright (C) 2011 Renesas Solutions Corp. | ||
5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
6 | * | ||
7 | * This program is distributed in the hope that it will be useful, | ||
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
10 | * GNU General Public License for more details. | ||
11 | * | ||
12 | * You should have received a copy of the GNU General Public License | ||
13 | * along with this program; if not, write to the Free Software | ||
14 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
15 | * | ||
16 | */ | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/list.h> | ||
19 | #include <linux/module.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/slab.h> | ||
22 | #include <linux/usb.h> | ||
23 | #include <linux/usb/hcd.h> | ||
24 | #include "common.h" | ||
25 | |||
26 | /* | ||
27 | *** HARDWARE LIMITATION *** | ||
28 | * | ||
29 | * 1) renesas_usbhs has a limited number of controllable devices. | ||
30 | * it can control only 9 devices in generally. | ||
31 | * see DEVADDn / DCPMAXP / PIPEMAXP. | ||
32 | * | ||
33 | * 2) renesas_usbhs pipe number is limited. | ||
34 | * the pipe will be re-used for each devices. | ||
35 | * so, software should control DATA0/1 sequence of each devices. | ||
36 | */ | ||
37 | |||
38 | |||
39 | /* | ||
40 | * image of mod_host | ||
41 | * | ||
42 | * +--------+ | ||
43 | * | udev 0 | --> it is used when set address | ||
44 | * +--------+ | ||
45 | * | ||
46 | * +--------+ pipes are reused for each uep. | ||
47 | * | udev 1 |-+- [uep 0 (dcp) ] --+ pipe will be switched when | ||
48 | * +--------+ | | target device was changed | ||
49 | * +- [uep 1 (bulk)] --|---+ +--------------+ | ||
50 | * | +--------------> | pipe0 (dcp) | | ||
51 | * +- [uep 2 (bulk)] --|---|---+ +--------------+ | ||
52 | * | | | | pipe1 (isoc) | | ||
53 | * +--------+ | | | +--------------+ | ||
54 | * | udev 2 |-+- [uep 0 (dcp) ] --+ +-- |------> | pipe2 (bulk) | | ||
55 | * +--------+ | | | | +--------------+ | ||
56 | * +- [uep 1 (int) ] --|-+ | +------> | pipe3 (bulk) | | ||
57 | * | | | | +--------------+ | ||
58 | * +--------+ | +-|---|------> | pipe4 (int) | | ||
59 | * | udev 3 |-+- [uep 0 (dcp) ] --+ | | +--------------+ | ||
60 | * +--------+ | | | | .... | | ||
61 | * +- [uep 1 (bulk)] ------+ | | .... | | ||
62 | * | | | ||
63 | * +- [uep 2 (bulk)]-----------+ | ||
64 | */ | ||
65 | |||
66 | |||
67 | /* | ||
68 | * struct | ||
69 | */ | ||
70 | struct usbhsh_pipe_info { | ||
71 | unsigned int usr_cnt; /* see usbhsh_endpoint_alloc() */ | ||
72 | }; | ||
73 | |||
74 | struct usbhsh_request { | ||
75 | struct urb *urb; | ||
76 | struct usbhs_pkt pkt; | ||
77 | struct list_head ureq_link; /* see hpriv :: ureq_link_xxx */ | ||
78 | }; | ||
79 | |||
80 | struct usbhsh_device { | ||
81 | struct usb_device *usbv; | ||
82 | struct list_head ep_list_head; /* list of usbhsh_ep */ | ||
83 | }; | ||
84 | |||
85 | struct usbhsh_ep { | ||
86 | struct usbhs_pipe *pipe; | ||
87 | struct usbhsh_device *udev; /* attached udev */ | ||
88 | struct list_head ep_list; /* list to usbhsh_device */ | ||
89 | |||
90 | int maxp; | ||
91 | }; | ||
92 | |||
93 | #define USBHSH_DEVICE_MAX 10 /* see DEVADDn / DCPMAXP / PIPEMAXP */ | ||
94 | #define USBHSH_PORT_MAX 7 /* see DEVADDn :: HUBPORT */ | ||
95 | struct usbhsh_hpriv { | ||
96 | struct usbhs_mod mod; | ||
97 | struct usbhs_pipe *dcp; | ||
98 | |||
99 | struct usbhsh_device udev[USBHSH_DEVICE_MAX]; | ||
100 | |||
101 | struct usbhsh_pipe_info *pipe_info; | ||
102 | int pipe_size; | ||
103 | |||
104 | u32 port_stat; /* USB_PORT_STAT_xxx */ | ||
105 | |||
106 | struct completion *done; | ||
107 | |||
108 | /* see usbhsh_req_alloc/free */ | ||
109 | struct list_head ureq_link_active; | ||
110 | struct list_head ureq_link_free; | ||
111 | }; | ||
112 | |||
113 | |||
114 | static const char usbhsh_hcd_name[] = "renesas_usbhs host"; | ||
115 | |||
116 | /* | ||
117 | * macro | ||
118 | */ | ||
119 | #define usbhsh_priv_to_hpriv(priv) \ | ||
120 | container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod) | ||
121 | |||
122 | #define __usbhsh_for_each_hpipe(start, pos, h, i) \ | ||
123 | for (i = start, pos = (h)->hpipe + i; \ | ||
124 | i < (h)->hpipe_size; \ | ||
125 | i++, pos = (h)->hpipe + i) | ||
126 | |||
127 | #define usbhsh_for_each_hpipe(pos, hpriv, i) \ | ||
128 | __usbhsh_for_each_hpipe(1, pos, hpriv, i) | ||
129 | |||
130 | #define usbhsh_for_each_hpipe_with_dcp(pos, hpriv, i) \ | ||
131 | __usbhsh_for_each_hpipe(0, pos, hpriv, i) | ||
132 | |||
133 | #define __usbhsh_for_each_udev(start, pos, h, i) \ | ||
134 | for (i = start, pos = (h)->udev + i; \ | ||
135 | i < USBHSH_DEVICE_MAX; \ | ||
136 | i++, pos = (h)->udev + i) | ||
137 | |||
138 | #define usbhsh_for_each_udev(pos, hpriv, i) \ | ||
139 | __usbhsh_for_each_udev(1, pos, hpriv, i) | ||
140 | |||
141 | #define usbhsh_for_each_udev_with_dev0(pos, hpriv, i) \ | ||
142 | __usbhsh_for_each_udev(0, pos, hpriv, i) | ||
143 | |||
144 | #define usbhsh_hcd_to_hpriv(h) (struct usbhsh_hpriv *)((h)->hcd_priv) | ||
145 | #define usbhsh_hcd_to_dev(h) ((h)->self.controller) | ||
146 | |||
147 | #define usbhsh_hpriv_to_priv(h) ((h)->mod.priv) | ||
148 | #define usbhsh_hpriv_to_dcp(h) ((h)->dcp) | ||
149 | #define usbhsh_hpriv_to_hcd(h) \ | ||
150 | container_of((void *)h, struct usb_hcd, hcd_priv) | ||
151 | |||
152 | #define usbhsh_ep_to_uep(u) ((u)->hcpriv) | ||
153 | #define usbhsh_uep_to_pipe(u) ((u)->pipe) | ||
154 | #define usbhsh_uep_to_udev(u) ((u)->udev) | ||
155 | #define usbhsh_urb_to_ureq(u) ((u)->hcpriv) | ||
156 | #define usbhsh_urb_to_usbv(u) ((u)->dev) | ||
157 | |||
158 | #define usbhsh_usbv_to_udev(d) dev_get_drvdata(&(d)->dev) | ||
159 | |||
160 | #define usbhsh_udev_to_usbv(h) ((h)->usbv) | ||
161 | |||
162 | #define usbhsh_pipe_info(p) ((p)->mod_private) | ||
163 | |||
164 | #define usbhsh_device_number(h, d) ((int)((d) - (h)->udev)) | ||
165 | #define usbhsh_device_nth(h, d) ((h)->udev + d) | ||
166 | #define usbhsh_device0(h) usbhsh_device_nth(h, 0) | ||
167 | |||
168 | #define usbhsh_port_stat_init(h) ((h)->port_stat = 0) | ||
169 | #define usbhsh_port_stat_set(h, s) ((h)->port_stat |= (s)) | ||
170 | #define usbhsh_port_stat_clear(h, s) ((h)->port_stat &= ~(s)) | ||
171 | #define usbhsh_port_stat_get(h) ((h)->port_stat) | ||
172 | |||
173 | #define usbhsh_pkt_to_req(p) \ | ||
174 | container_of((void *)p, struct usbhsh_request, pkt) | ||
175 | |||
176 | /* | ||
177 | * req alloc/free | ||
178 | */ | ||
179 | static void usbhsh_req_list_init(struct usbhsh_hpriv *hpriv) | ||
180 | { | ||
181 | INIT_LIST_HEAD(&hpriv->ureq_link_active); | ||
182 | INIT_LIST_HEAD(&hpriv->ureq_link_free); | ||
183 | } | ||
184 | |||
185 | static void usbhsh_req_list_quit(struct usbhsh_hpriv *hpriv) | ||
186 | { | ||
187 | struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); | ||
188 | struct device *dev = usbhsh_hcd_to_dev(hcd); | ||
189 | struct usbhsh_request *ureq, *next; | ||
190 | |||
191 | /* kfree all active ureq */ | ||
192 | list_for_each_entry_safe(ureq, next, | ||
193 | &hpriv->ureq_link_active, | ||
194 | ureq_link) { | ||
195 | dev_err(dev, "active ureq (%p) is force freed\n", ureq); | ||
196 | kfree(ureq); | ||
197 | } | ||
198 | |||
199 | /* kfree all free ureq */ | ||
200 | list_for_each_entry_safe(ureq, next, &hpriv->ureq_link_free, ureq_link) | ||
201 | kfree(ureq); | ||
202 | } | ||
203 | |||
204 | static struct usbhsh_request *usbhsh_req_alloc(struct usbhsh_hpriv *hpriv, | ||
205 | struct urb *urb, | ||
206 | gfp_t mem_flags) | ||
207 | { | ||
208 | struct usbhsh_request *ureq; | ||
209 | struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); | ||
210 | struct device *dev = usbhs_priv_to_dev(priv); | ||
211 | |||
212 | if (list_empty(&hpriv->ureq_link_free)) { | ||
213 | /* | ||
214 | * create new one if there is no free ureq | ||
215 | */ | ||
216 | ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags); | ||
217 | if (ureq) | ||
218 | INIT_LIST_HEAD(&ureq->ureq_link); | ||
219 | } else { | ||
220 | /* | ||
221 | * reuse "free" ureq if exist | ||
222 | */ | ||
223 | ureq = list_entry(hpriv->ureq_link_free.next, | ||
224 | struct usbhsh_request, | ||
225 | ureq_link); | ||
226 | if (ureq) | ||
227 | list_del_init(&ureq->ureq_link); | ||
228 | } | ||
229 | |||
230 | if (!ureq) { | ||
231 | dev_err(dev, "ureq alloc fail\n"); | ||
232 | return NULL; | ||
233 | } | ||
234 | |||
235 | usbhs_pkt_init(&ureq->pkt); | ||
236 | |||
237 | /* | ||
238 | * push it to "active" list | ||
239 | */ | ||
240 | list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_active); | ||
241 | ureq->urb = urb; | ||
242 | |||
243 | return ureq; | ||
244 | } | ||
245 | |||
246 | static void usbhsh_req_free(struct usbhsh_hpriv *hpriv, | ||
247 | struct usbhsh_request *ureq) | ||
248 | { | ||
249 | struct usbhs_pkt *pkt = &ureq->pkt; | ||
250 | |||
251 | usbhs_pkt_init(pkt); | ||
252 | |||
253 | /* | ||
254 | * removed from "active" list, | ||
255 | * and push it to "free" list | ||
256 | */ | ||
257 | ureq->urb = NULL; | ||
258 | list_del_init(&ureq->ureq_link); | ||
259 | list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_free); | ||
260 | } | ||
261 | |||
262 | /* | ||
263 | * device control | ||
264 | */ | ||
265 | |||
266 | static int usbhsh_device_has_endpoint(struct usbhsh_device *udev) | ||
267 | { | ||
268 | return !list_empty(&udev->ep_list_head); | ||
269 | } | ||
270 | |||
271 | static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv, | ||
272 | struct urb *urb) | ||
273 | { | ||
274 | struct usbhsh_device *udev = NULL; | ||
275 | struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); | ||
276 | struct device *dev = usbhsh_hcd_to_dev(hcd); | ||
277 | struct usb_device *usbv = usbhsh_urb_to_usbv(urb); | ||
278 | struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); | ||
279 | int i; | ||
280 | |||
281 | /* | ||
282 | * device 0 | ||
283 | */ | ||
284 | if (0 == usb_pipedevice(urb->pipe)) { | ||
285 | udev = usbhsh_device0(hpriv); | ||
286 | goto usbhsh_device_find; | ||
287 | } | ||
288 | |||
289 | /* | ||
290 | * find unused device | ||
291 | */ | ||
292 | usbhsh_for_each_udev(udev, hpriv, i) { | ||
293 | if (usbhsh_udev_to_usbv(udev)) | ||
294 | continue; | ||
295 | goto usbhsh_device_find; | ||
296 | } | ||
297 | |||
298 | dev_err(dev, "no free usbhsh_device\n"); | ||
299 | |||
300 | return NULL; | ||
301 | |||
302 | usbhsh_device_find: | ||
303 | if (usbhsh_device_has_endpoint(udev)) | ||
304 | dev_warn(dev, "udev have old endpoint\n"); | ||
305 | |||
306 | /* uep will be attached */ | ||
307 | INIT_LIST_HEAD(&udev->ep_list_head); | ||
308 | |||
309 | /* | ||
310 | * usbhsh_usbv_to_udev() | ||
311 | * usbhsh_udev_to_usbv() | ||
312 | * will be enable | ||
313 | */ | ||
314 | dev_set_drvdata(&usbv->dev, udev); | ||
315 | udev->usbv = usbv; | ||
316 | |||
317 | /* set device config */ | ||
318 | usbhs_set_device_speed(priv, | ||
319 | usbhsh_device_number(hpriv, udev), | ||
320 | usbhsh_device_number(hpriv, udev), | ||
321 | 0, /* FIXME no parent */ | ||
322 | usbv->speed); | ||
323 | |||
324 | dev_dbg(dev, "%s [%d](%p)\n", __func__, | ||
325 | usbhsh_device_number(hpriv, udev), udev); | ||
326 | |||
327 | return udev; | ||
328 | } | ||
329 | |||
330 | static void usbhsh_device_free(struct usbhsh_hpriv *hpriv, | ||
331 | struct usbhsh_device *udev) | ||
332 | { | ||
333 | struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); | ||
334 | struct device *dev = usbhsh_hcd_to_dev(hcd); | ||
335 | struct usb_device *usbv = usbhsh_udev_to_usbv(udev); | ||
336 | |||
337 | dev_dbg(dev, "%s [%d](%p)\n", __func__, | ||
338 | usbhsh_device_number(hpriv, udev), udev); | ||
339 | |||
340 | if (usbhsh_device_has_endpoint(udev)) | ||
341 | dev_warn(dev, "udev still have endpoint\n"); | ||
342 | |||
343 | /* | ||
344 | * usbhsh_usbv_to_udev() | ||
345 | * usbhsh_udev_to_usbv() | ||
346 | * will be disable | ||
347 | */ | ||
348 | dev_set_drvdata(&usbv->dev, NULL); | ||
349 | udev->usbv = NULL; | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * end-point control | ||
354 | */ | ||
355 | struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv, | ||
356 | struct usbhsh_device *udev, | ||
357 | struct usb_host_endpoint *ep, | ||
358 | gfp_t mem_flags) | ||
359 | { | ||
360 | struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); | ||
361 | struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); | ||
362 | struct usbhsh_ep *uep; | ||
363 | struct usbhsh_pipe_info *info; | ||
364 | struct usbhs_pipe *pipe, *best_pipe; | ||
365 | struct device *dev = usbhsh_hcd_to_dev(hcd); | ||
366 | struct usb_endpoint_descriptor *desc = &ep->desc; | ||
367 | int type, i; | ||
368 | unsigned int min_usr; | ||
369 | |||
370 | uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); | ||
371 | if (!uep) { | ||
372 | dev_err(dev, "usbhsh_ep alloc fail\n"); | ||
373 | return NULL; | ||
374 | } | ||
375 | type = usb_endpoint_type(desc); | ||
376 | |||
377 | /* | ||
378 | * find best pipe for endpoint | ||
379 | * see | ||
380 | * HARDWARE LIMITATION | ||
381 | */ | ||
382 | min_usr = ~0; | ||
383 | best_pipe = NULL; | ||
384 | usbhs_for_each_pipe_with_dcp(pipe, priv, i) { | ||
385 | if (!usbhs_pipe_type_is(pipe, type)) | ||
386 | continue; | ||
387 | |||
388 | info = usbhsh_pipe_info(pipe); | ||
389 | |||
390 | if (min_usr > info->usr_cnt) { | ||
391 | min_usr = info->usr_cnt; | ||
392 | best_pipe = pipe; | ||
393 | } | ||
394 | } | ||
395 | |||
396 | if (unlikely(!best_pipe)) { | ||
397 | dev_err(dev, "couldn't find best pipe\n"); | ||
398 | kfree(uep); | ||
399 | return NULL; | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * init uep | ||
404 | */ | ||
405 | uep->pipe = best_pipe; | ||
406 | uep->maxp = usb_endpoint_maxp(desc); | ||
407 | usbhsh_uep_to_udev(uep) = udev; | ||
408 | usbhsh_ep_to_uep(ep) = uep; | ||
409 | |||
410 | /* | ||
411 | * update pipe user count | ||
412 | */ | ||
413 | info = usbhsh_pipe_info(best_pipe); | ||
414 | info->usr_cnt++; | ||
415 | |||
416 | /* init this endpoint, and attach it to udev */ | ||
417 | INIT_LIST_HEAD(&uep->ep_list); | ||
418 | list_add_tail(&uep->ep_list, &udev->ep_list_head); | ||
419 | |||
420 | /* | ||
421 | * usbhs_pipe_config_update() should be called after | ||
422 | * usbhs_device_config() | ||
423 | * see | ||
424 | * DCPMAXP/PIPEMAXP | ||
425 | */ | ||
426 | usbhs_pipe_config_update(uep->pipe, | ||
427 | usbhsh_device_number(hpriv, udev), | ||
428 | usb_endpoint_num(desc), | ||
429 | uep->maxp); | ||
430 | |||
431 | dev_dbg(dev, "%s [%d-%s](%p)\n", __func__, | ||
432 | usbhsh_device_number(hpriv, udev), | ||
433 | usbhs_pipe_name(pipe), uep); | ||
434 | |||
435 | return uep; | ||
436 | } | ||
437 | |||
438 | void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv, | ||
439 | struct usb_host_endpoint *ep) | ||
440 | { | ||
441 | struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); | ||
442 | struct device *dev = usbhs_priv_to_dev(priv); | ||
443 | struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep); | ||
444 | struct usbhsh_device *udev = usbhsh_uep_to_udev(uep); | ||
445 | struct usbhsh_pipe_info *info; | ||
446 | |||
447 | if (!uep) | ||
448 | return; | ||
449 | |||
450 | dev_dbg(dev, "%s [%d-%s](%p)\n", __func__, | ||
451 | usbhsh_device_number(hpriv, udev), | ||
452 | usbhs_pipe_name(uep->pipe), uep); | ||
453 | |||
454 | info = usbhsh_pipe_info(uep->pipe); | ||
455 | info->usr_cnt--; | ||
456 | |||
457 | /* remove this endpoint from udev */ | ||
458 | list_del_init(&uep->ep_list); | ||
459 | |||
460 | usbhsh_uep_to_udev(uep) = NULL; | ||
461 | usbhsh_ep_to_uep(ep) = NULL; | ||
462 | |||
463 | kfree(uep); | ||
464 | } | ||
465 | |||
466 | /* | ||
467 | * queue push/pop | ||
468 | */ | ||
469 | static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) | ||
470 | { | ||
471 | struct usbhsh_request *ureq = usbhsh_pkt_to_req(pkt); | ||
472 | struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); | ||
473 | struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); | ||
474 | struct urb *urb = ureq->urb; | ||
475 | struct device *dev = usbhs_priv_to_dev(priv); | ||
476 | |||
477 | dev_dbg(dev, "%s\n", __func__); | ||
478 | |||
479 | if (!urb) { | ||
480 | dev_warn(dev, "pkt doesn't have urb\n"); | ||
481 | return; | ||
482 | } | ||
483 | |||
484 | urb->actual_length = pkt->actual; | ||
485 | usbhsh_req_free(hpriv, ureq); | ||
486 | usbhsh_urb_to_ureq(urb) = NULL; | ||
487 | |||
488 | usb_hcd_unlink_urb_from_ep(hcd, urb); | ||
489 | usb_hcd_giveback_urb(hcd, urb, 0); | ||
490 | } | ||
491 | |||
492 | static int usbhsh_queue_push(struct usb_hcd *hcd, | ||
493 | struct usbhs_pipe *pipe, | ||
494 | struct urb *urb) | ||
495 | { | ||
496 | struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb); | ||
497 | struct usbhs_pkt *pkt = &ureq->pkt; | ||
498 | struct device *dev = usbhsh_hcd_to_dev(hcd); | ||
499 | void *buf; | ||
500 | int len; | ||
501 | |||
502 | if (usb_pipeisoc(urb->pipe)) { | ||
503 | dev_err(dev, "pipe iso is not supported now\n"); | ||
504 | return -EIO; | ||
505 | } | ||
506 | |||
507 | if (usb_pipein(urb->pipe)) | ||
508 | pipe->handler = &usbhs_fifo_pio_pop_handler; | ||
509 | else | ||
510 | pipe->handler = &usbhs_fifo_pio_push_handler; | ||
511 | |||
512 | buf = (void *)(urb->transfer_buffer + urb->actual_length); | ||
513 | len = urb->transfer_buffer_length - urb->actual_length; | ||
514 | |||
515 | dev_dbg(dev, "%s\n", __func__); | ||
516 | usbhs_pkt_push(pipe, pkt, usbhsh_queue_done, | ||
517 | buf, len, (urb->transfer_flags & URB_ZERO_PACKET)); | ||
518 | usbhs_pkt_start(pipe); | ||
519 | |||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | /* | ||
524 | * DCP setup stage | ||
525 | */ | ||
526 | static int usbhsh_is_request_address(struct urb *urb) | ||
527 | { | ||
528 | struct usb_ctrlrequest *cmd; | ||
529 | |||
530 | cmd = (struct usb_ctrlrequest *)urb->setup_packet; | ||
531 | |||
532 | if ((DeviceOutRequest == cmd->bRequestType << 8) && | ||
533 | (USB_REQ_SET_ADDRESS == cmd->bRequest)) | ||
534 | return 1; | ||
535 | else | ||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | static void usbhsh_setup_stage_packet_push(struct usbhsh_hpriv *hpriv, | ||
540 | struct urb *urb, | ||
541 | struct usbhs_pipe *pipe) | ||
542 | { | ||
543 | struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); | ||
544 | struct usb_ctrlrequest req; | ||
545 | struct device *dev = usbhs_priv_to_dev(priv); | ||
546 | |||
547 | /* | ||
548 | * wait setup packet ACK | ||
549 | * see | ||
550 | * usbhsh_irq_setup_ack() | ||
551 | * usbhsh_irq_setup_err() | ||
552 | */ | ||
553 | DECLARE_COMPLETION(done); | ||
554 | hpriv->done = &done; | ||
555 | |||
556 | /* copy original request */ | ||
557 | memcpy(&req, urb->setup_packet, sizeof(struct usb_ctrlrequest)); | ||
558 | |||
559 | /* | ||
560 | * renesas_usbhs can not use original usb address. | ||
561 | * see HARDWARE LIMITATION. | ||
562 | * modify usb address here. | ||
563 | */ | ||
564 | if (usbhsh_is_request_address(urb)) { | ||
565 | /* FIXME */ | ||
566 | req.wValue = 1; | ||
567 | dev_dbg(dev, "create new address - %d\n", req.wValue); | ||
568 | } | ||
569 | |||
570 | /* set request */ | ||
571 | usbhs_usbreq_set_val(priv, &req); | ||
572 | |||
573 | /* | ||
574 | * wait setup packet ACK | ||
575 | */ | ||
576 | wait_for_completion(&done); | ||
577 | hpriv->done = NULL; | ||
578 | |||
579 | dev_dbg(dev, "%s done\n", __func__); | ||
580 | } | ||
581 | |||
582 | /* | ||
583 | * DCP data stage | ||
584 | */ | ||
585 | static void usbhsh_data_stage_packet_done(struct usbhs_priv *priv, | ||
586 | struct usbhs_pkt *pkt) | ||
587 | { | ||
588 | struct usbhsh_request *ureq = usbhsh_pkt_to_req(pkt); | ||
589 | struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); | ||
590 | struct urb *urb = ureq->urb; | ||
591 | |||
592 | /* this ureq was connected to urb when usbhsh_urb_enqueue() */ | ||
593 | |||
594 | usbhsh_req_free(hpriv, ureq); | ||
595 | usbhsh_urb_to_ureq(urb) = NULL; | ||
596 | } | ||
597 | |||
598 | static void usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv, | ||
599 | struct urb *urb, | ||
600 | struct usbhs_pipe *pipe) | ||
601 | { | ||
602 | struct usbhsh_request *ureq; | ||
603 | struct usbhs_pkt *pkt; | ||
604 | |||
605 | /* | ||
606 | * FIXME | ||
607 | * | ||
608 | * data stage uses ureq which is connected to urb | ||
609 | * see usbhsh_urb_enqueue() :: alloc new request. | ||
610 | * it will be freed in usbhsh_data_stage_packet_done() | ||
611 | */ | ||
612 | ureq = usbhsh_urb_to_ureq(urb); | ||
613 | pkt = &ureq->pkt; | ||
614 | |||
615 | if (usb_pipein(urb->pipe)) | ||
616 | pipe->handler = &usbhs_dcp_data_stage_in_handler; | ||
617 | else | ||
618 | pipe->handler = &usbhs_dcp_data_stage_out_handler; | ||
619 | |||
620 | usbhs_pkt_push(pipe, pkt, | ||
621 | usbhsh_data_stage_packet_done, | ||
622 | urb->transfer_buffer, | ||
623 | urb->transfer_buffer_length, | ||
624 | (urb->transfer_flags & URB_ZERO_PACKET)); | ||
625 | } | ||
626 | |||
627 | /* | ||
628 | * DCP status stage | ||
629 | */ | ||
630 | static void usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv, | ||
631 | struct urb *urb, | ||
632 | struct usbhs_pipe *pipe) | ||
633 | { | ||
634 | struct usbhsh_request *ureq; | ||
635 | struct usbhs_pkt *pkt; | ||
636 | |||
637 | /* | ||
638 | * FIXME | ||
639 | * | ||
640 | * status stage uses allocated ureq. | ||
641 | * it will be freed on usbhsh_queue_done() | ||
642 | */ | ||
643 | ureq = usbhsh_req_alloc(hpriv, urb, GFP_KERNEL); | ||
644 | pkt = &ureq->pkt; | ||
645 | |||
646 | if (usb_pipein(urb->pipe)) | ||
647 | pipe->handler = &usbhs_dcp_status_stage_in_handler; | ||
648 | else | ||
649 | pipe->handler = &usbhs_dcp_status_stage_out_handler; | ||
650 | |||
651 | usbhs_pkt_push(pipe, pkt, | ||
652 | usbhsh_queue_done, | ||
653 | NULL, | ||
654 | urb->transfer_buffer_length, | ||
655 | 0); | ||
656 | } | ||
657 | |||
658 | static int usbhsh_dcp_queue_push(struct usb_hcd *hcd, | ||
659 | struct usbhsh_hpriv *hpriv, | ||
660 | struct usbhs_pipe *pipe, | ||
661 | struct urb *urb) | ||
662 | { | ||
663 | struct device *dev = usbhsh_hcd_to_dev(hcd); | ||
664 | |||
665 | dev_dbg(dev, "%s\n", __func__); | ||
666 | |||
667 | /* | ||
668 | * setup stage | ||
669 | * | ||
670 | * usbhsh_send_setup_stage_packet() wait SACK/SIGN | ||
671 | */ | ||
672 | usbhsh_setup_stage_packet_push(hpriv, urb, pipe); | ||
673 | |||
674 | /* | ||
675 | * data stage | ||
676 | * | ||
677 | * It is pushed only when urb has buffer. | ||
678 | */ | ||
679 | if (urb->transfer_buffer_length) | ||
680 | usbhsh_data_stage_packet_push(hpriv, urb, pipe); | ||
681 | |||
682 | /* | ||
683 | * status stage | ||
684 | */ | ||
685 | usbhsh_status_stage_packet_push(hpriv, urb, pipe); | ||
686 | |||
687 | /* | ||
688 | * start pushed packets | ||
689 | */ | ||
690 | usbhs_pkt_start(pipe); | ||
691 | |||
692 | return 0; | ||
693 | } | ||
694 | |||
695 | /* | ||
696 | * dma map functions | ||
697 | */ | ||
698 | static int usbhsh_dma_map_ctrl(struct usbhs_pkt *pkt, int map) | ||
699 | { | ||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | /* | ||
704 | * for hc_driver | ||
705 | */ | ||
706 | static int usbhsh_host_start(struct usb_hcd *hcd) | ||
707 | { | ||
708 | return 0; | ||
709 | } | ||
710 | |||
711 | static void usbhsh_host_stop(struct usb_hcd *hcd) | ||
712 | { | ||
713 | } | ||
714 | |||
715 | static int usbhsh_urb_enqueue(struct usb_hcd *hcd, | ||
716 | struct urb *urb, | ||
717 | gfp_t mem_flags) | ||
718 | { | ||
719 | struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); | ||
720 | struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); | ||
721 | struct device *dev = usbhs_priv_to_dev(priv); | ||
722 | struct usb_device *usbv = usbhsh_urb_to_usbv(urb); | ||
723 | struct usb_host_endpoint *ep = urb->ep; | ||
724 | struct usbhsh_request *ureq; | ||
725 | struct usbhsh_device *udev, *new_udev = NULL; | ||
726 | struct usbhs_pipe *pipe; | ||
727 | struct usbhsh_ep *uep; | ||
728 | |||
729 | int ret; | ||
730 | |||
731 | dev_dbg(dev, "%s (%s)\n", | ||
732 | __func__, usb_pipein(urb->pipe) ? "in" : "out"); | ||
733 | |||
734 | ret = usb_hcd_link_urb_to_ep(hcd, urb); | ||
735 | if (ret) | ||
736 | goto usbhsh_urb_enqueue_error_not_linked; | ||
737 | |||
738 | /* | ||
739 | * get udev | ||
740 | */ | ||
741 | udev = usbhsh_usbv_to_udev(usbv); | ||
742 | if (!udev) { | ||
743 | new_udev = usbhsh_device_alloc(hpriv, urb); | ||
744 | if (!new_udev) | ||
745 | goto usbhsh_urb_enqueue_error_not_linked; | ||
746 | |||
747 | udev = new_udev; | ||
748 | } | ||
749 | |||
750 | /* | ||
751 | * get uep | ||
752 | */ | ||
753 | uep = usbhsh_ep_to_uep(ep); | ||
754 | if (!uep) { | ||
755 | uep = usbhsh_endpoint_alloc(hpriv, udev, ep, mem_flags); | ||
756 | if (!uep) | ||
757 | goto usbhsh_urb_enqueue_error_free_device; | ||
758 | } | ||
759 | pipe = usbhsh_uep_to_pipe(uep); | ||
760 | |||
761 | /* | ||
762 | * alloc new request | ||
763 | */ | ||
764 | ureq = usbhsh_req_alloc(hpriv, urb, mem_flags); | ||
765 | if (unlikely(!ureq)) { | ||
766 | ret = -ENOMEM; | ||
767 | goto usbhsh_urb_enqueue_error_free_endpoint; | ||
768 | } | ||
769 | usbhsh_urb_to_ureq(urb) = ureq; | ||
770 | |||
771 | /* | ||
772 | * push packet | ||
773 | */ | ||
774 | if (usb_pipecontrol(urb->pipe)) | ||
775 | usbhsh_dcp_queue_push(hcd, hpriv, pipe, urb); | ||
776 | else | ||
777 | usbhsh_queue_push(hcd, pipe, urb); | ||
778 | |||
779 | return 0; | ||
780 | |||
781 | usbhsh_urb_enqueue_error_free_endpoint: | ||
782 | usbhsh_endpoint_free(hpriv, ep); | ||
783 | usbhsh_urb_enqueue_error_free_device: | ||
784 | if (new_udev) | ||
785 | usbhsh_device_free(hpriv, new_udev); | ||
786 | usbhsh_urb_enqueue_error_not_linked: | ||
787 | |||
788 | dev_dbg(dev, "%s error\n", __func__); | ||
789 | |||
790 | return ret; | ||
791 | } | ||
792 | |||
793 | static int usbhsh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) | ||
794 | { | ||
795 | struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); | ||
796 | struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb); | ||
797 | |||
798 | if (ureq) { | ||
799 | usbhsh_req_free(hpriv, ureq); | ||
800 | usbhsh_urb_to_ureq(urb) = NULL; | ||
801 | } | ||
802 | |||
803 | return 0; | ||
804 | } | ||
805 | |||
806 | static void usbhsh_endpoint_disable(struct usb_hcd *hcd, | ||
807 | struct usb_host_endpoint *ep) | ||
808 | { | ||
809 | struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep); | ||
810 | struct usbhsh_device *udev; | ||
811 | struct usbhsh_hpriv *hpriv; | ||
812 | |||
813 | /* | ||
814 | * this function might be called manytimes by same hcd/ep | ||
815 | * in-endpoitn == out-endpoint if ep == dcp. | ||
816 | */ | ||
817 | if (!uep) | ||
818 | return; | ||
819 | |||
820 | udev = usbhsh_uep_to_udev(uep); | ||
821 | hpriv = usbhsh_hcd_to_hpriv(hcd); | ||
822 | |||
823 | usbhsh_endpoint_free(hpriv, ep); | ||
824 | ep->hcpriv = NULL; | ||
825 | |||
826 | /* | ||
827 | * if there is no endpoint, | ||
828 | * free device | ||
829 | */ | ||
830 | if (!usbhsh_device_has_endpoint(udev)) | ||
831 | usbhsh_device_free(hpriv, udev); | ||
832 | } | ||
833 | |||
834 | static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf) | ||
835 | { | ||
836 | struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); | ||
837 | struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); | ||
838 | struct device *dev = usbhs_priv_to_dev(priv); | ||
839 | int roothub_id = 1; /* only 1 root hub */ | ||
840 | |||
841 | /* | ||
842 | * does port stat was changed ? | ||
843 | * check USB_PORT_STAT_C_xxx << 16 | ||
844 | */ | ||
845 | if (usbhsh_port_stat_get(hpriv) & 0xFFFF0000) | ||
846 | *buf = (1 << roothub_id); | ||
847 | else | ||
848 | *buf = 0; | ||
849 | |||
850 | dev_dbg(dev, "%s (%02x)\n", __func__, *buf); | ||
851 | |||
852 | return !!(*buf); | ||
853 | } | ||
854 | |||
855 | static int __usbhsh_hub_hub_feature(struct usbhsh_hpriv *hpriv, | ||
856 | u16 typeReq, u16 wValue, | ||
857 | u16 wIndex, char *buf, u16 wLength) | ||
858 | { | ||
859 | struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); | ||
860 | struct device *dev = usbhs_priv_to_dev(priv); | ||
861 | |||
862 | switch (wValue) { | ||
863 | case C_HUB_OVER_CURRENT: | ||
864 | case C_HUB_LOCAL_POWER: | ||
865 | dev_dbg(dev, "%s :: C_HUB_xx\n", __func__); | ||
866 | return 0; | ||
867 | } | ||
868 | |||
869 | return -EPIPE; | ||
870 | } | ||
871 | |||
872 | static int __usbhsh_hub_port_feature(struct usbhsh_hpriv *hpriv, | ||
873 | u16 typeReq, u16 wValue, | ||
874 | u16 wIndex, char *buf, u16 wLength) | ||
875 | { | ||
876 | struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); | ||
877 | struct device *dev = usbhs_priv_to_dev(priv); | ||
878 | int enable = (typeReq == SetPortFeature); | ||
879 | int speed, i, timeout = 128; | ||
880 | int roothub_id = 1; /* only 1 root hub */ | ||
881 | |||
882 | /* common error */ | ||
883 | if (wIndex > roothub_id || wLength != 0) | ||
884 | return -EPIPE; | ||
885 | |||
886 | /* check wValue */ | ||
887 | switch (wValue) { | ||
888 | case USB_PORT_FEAT_POWER: | ||
889 | usbhs_vbus_ctrl(priv, enable); | ||
890 | dev_dbg(dev, "%s :: USB_PORT_FEAT_POWER\n", __func__); | ||
891 | break; | ||
892 | |||
893 | case USB_PORT_FEAT_ENABLE: | ||
894 | case USB_PORT_FEAT_SUSPEND: | ||
895 | case USB_PORT_FEAT_C_ENABLE: | ||
896 | case USB_PORT_FEAT_C_SUSPEND: | ||
897 | case USB_PORT_FEAT_C_CONNECTION: | ||
898 | case USB_PORT_FEAT_C_OVER_CURRENT: | ||
899 | case USB_PORT_FEAT_C_RESET: | ||
900 | dev_dbg(dev, "%s :: USB_PORT_FEAT_xxx\n", __func__); | ||
901 | break; | ||
902 | |||
903 | case USB_PORT_FEAT_RESET: | ||
904 | if (!enable) | ||
905 | break; | ||
906 | |||
907 | usbhsh_port_stat_clear(hpriv, | ||
908 | USB_PORT_STAT_HIGH_SPEED | | ||
909 | USB_PORT_STAT_LOW_SPEED); | ||
910 | |||
911 | usbhs_bus_send_reset(priv); | ||
912 | msleep(20); | ||
913 | usbhs_bus_send_sof_enable(priv); | ||
914 | |||
915 | for (i = 0; i < timeout ; i++) { | ||
916 | switch (usbhs_bus_get_speed(priv)) { | ||
917 | case USB_SPEED_LOW: | ||
918 | speed = USB_PORT_STAT_LOW_SPEED; | ||
919 | goto got_usb_bus_speed; | ||
920 | case USB_SPEED_HIGH: | ||
921 | speed = USB_PORT_STAT_HIGH_SPEED; | ||
922 | goto got_usb_bus_speed; | ||
923 | case USB_SPEED_FULL: | ||
924 | speed = 0; | ||
925 | goto got_usb_bus_speed; | ||
926 | } | ||
927 | |||
928 | msleep(20); | ||
929 | } | ||
930 | return -EPIPE; | ||
931 | |||
932 | got_usb_bus_speed: | ||
933 | usbhsh_port_stat_set(hpriv, speed); | ||
934 | usbhsh_port_stat_set(hpriv, USB_PORT_STAT_ENABLE); | ||
935 | |||
936 | dev_dbg(dev, "%s :: USB_PORT_FEAT_RESET (speed = %d)\n", | ||
937 | __func__, speed); | ||
938 | |||
939 | /* status change is not needed */ | ||
940 | return 0; | ||
941 | |||
942 | default: | ||
943 | return -EPIPE; | ||
944 | } | ||
945 | |||
946 | /* set/clear status */ | ||
947 | if (enable) | ||
948 | usbhsh_port_stat_set(hpriv, (1 << wValue)); | ||
949 | else | ||
950 | usbhsh_port_stat_clear(hpriv, (1 << wValue)); | ||
951 | |||
952 | return 0; | ||
953 | } | ||
954 | |||
955 | static int __usbhsh_hub_get_status(struct usbhsh_hpriv *hpriv, | ||
956 | u16 typeReq, u16 wValue, | ||
957 | u16 wIndex, char *buf, u16 wLength) | ||
958 | { | ||
959 | struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); | ||
960 | struct usb_hub_descriptor *desc = (struct usb_hub_descriptor *)buf; | ||
961 | struct device *dev = usbhs_priv_to_dev(priv); | ||
962 | int roothub_id = 1; /* only 1 root hub */ | ||
963 | |||
964 | switch (typeReq) { | ||
965 | case GetHubStatus: | ||
966 | dev_dbg(dev, "%s :: GetHubStatus\n", __func__); | ||
967 | |||
968 | *buf = 0x00; | ||
969 | break; | ||
970 | |||
971 | case GetPortStatus: | ||
972 | if (wIndex != roothub_id) | ||
973 | return -EPIPE; | ||
974 | |||
975 | dev_dbg(dev, "%s :: GetPortStatus\n", __func__); | ||
976 | *(__le32 *)buf = cpu_to_le32(usbhsh_port_stat_get(hpriv)); | ||
977 | break; | ||
978 | |||
979 | case GetHubDescriptor: | ||
980 | desc->bDescriptorType = 0x29; | ||
981 | desc->bHubContrCurrent = 0; | ||
982 | desc->bNbrPorts = roothub_id; | ||
983 | desc->bDescLength = 9; | ||
984 | desc->bPwrOn2PwrGood = 0; | ||
985 | desc->wHubCharacteristics = cpu_to_le16(0x0011); | ||
986 | desc->u.hs.DeviceRemovable[0] = (roothub_id << 1); | ||
987 | desc->u.hs.DeviceRemovable[1] = ~0; | ||
988 | dev_dbg(dev, "%s :: GetHubDescriptor\n", __func__); | ||
989 | break; | ||
990 | } | ||
991 | |||
992 | return 0; | ||
993 | } | ||
994 | |||
995 | static int usbhsh_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | ||
996 | u16 wIndex, char *buf, u16 wLength) | ||
997 | { | ||
998 | struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd); | ||
999 | struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); | ||
1000 | struct device *dev = usbhs_priv_to_dev(priv); | ||
1001 | int ret = -EPIPE; | ||
1002 | |||
1003 | switch (typeReq) { | ||
1004 | |||
1005 | /* Hub Feature */ | ||
1006 | case ClearHubFeature: | ||
1007 | case SetHubFeature: | ||
1008 | ret = __usbhsh_hub_hub_feature(hpriv, typeReq, | ||
1009 | wValue, wIndex, buf, wLength); | ||
1010 | break; | ||
1011 | |||
1012 | /* Port Feature */ | ||
1013 | case SetPortFeature: | ||
1014 | case ClearPortFeature: | ||
1015 | ret = __usbhsh_hub_port_feature(hpriv, typeReq, | ||
1016 | wValue, wIndex, buf, wLength); | ||
1017 | break; | ||
1018 | |||
1019 | /* Get status */ | ||
1020 | case GetHubStatus: | ||
1021 | case GetPortStatus: | ||
1022 | case GetHubDescriptor: | ||
1023 | ret = __usbhsh_hub_get_status(hpriv, typeReq, | ||
1024 | wValue, wIndex, buf, wLength); | ||
1025 | break; | ||
1026 | } | ||
1027 | |||
1028 | dev_dbg(dev, "typeReq = %x, ret = %d, port_stat = %x\n", | ||
1029 | typeReq, ret, usbhsh_port_stat_get(hpriv)); | ||
1030 | |||
1031 | return ret; | ||
1032 | } | ||
1033 | |||
1034 | static struct hc_driver usbhsh_driver = { | ||
1035 | .description = usbhsh_hcd_name, | ||
1036 | .hcd_priv_size = sizeof(struct usbhsh_hpriv), | ||
1037 | |||
1038 | /* | ||
1039 | * generic hardware linkage | ||
1040 | */ | ||
1041 | .flags = HCD_USB2, | ||
1042 | |||
1043 | .start = usbhsh_host_start, | ||
1044 | .stop = usbhsh_host_stop, | ||
1045 | |||
1046 | /* | ||
1047 | * managing i/o requests and associated device resources | ||
1048 | */ | ||
1049 | .urb_enqueue = usbhsh_urb_enqueue, | ||
1050 | .urb_dequeue = usbhsh_urb_dequeue, | ||
1051 | .endpoint_disable = usbhsh_endpoint_disable, | ||
1052 | |||
1053 | /* | ||
1054 | * root hub | ||
1055 | */ | ||
1056 | .hub_status_data = usbhsh_hub_status_data, | ||
1057 | .hub_control = usbhsh_hub_control, | ||
1058 | }; | ||
1059 | |||
1060 | /* | ||
1061 | * interrupt functions | ||
1062 | */ | ||
1063 | static int usbhsh_irq_attch(struct usbhs_priv *priv, | ||
1064 | struct usbhs_irq_state *irq_state) | ||
1065 | { | ||
1066 | struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); | ||
1067 | struct device *dev = usbhs_priv_to_dev(priv); | ||
1068 | |||
1069 | dev_dbg(dev, "device attached\n"); | ||
1070 | |||
1071 | usbhsh_port_stat_set(hpriv, USB_PORT_STAT_CONNECTION); | ||
1072 | usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16); | ||
1073 | |||
1074 | return 0; | ||
1075 | } | ||
1076 | |||
1077 | static int usbhsh_irq_dtch(struct usbhs_priv *priv, | ||
1078 | struct usbhs_irq_state *irq_state) | ||
1079 | { | ||
1080 | struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); | ||
1081 | struct device *dev = usbhs_priv_to_dev(priv); | ||
1082 | |||
1083 | dev_dbg(dev, "device detached\n"); | ||
1084 | |||
1085 | usbhsh_port_stat_clear(hpriv, USB_PORT_STAT_CONNECTION); | ||
1086 | usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16); | ||
1087 | |||
1088 | return 0; | ||
1089 | } | ||
1090 | |||
1091 | static int usbhsh_irq_setup_ack(struct usbhs_priv *priv, | ||
1092 | struct usbhs_irq_state *irq_state) | ||
1093 | { | ||
1094 | struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); | ||
1095 | struct device *dev = usbhs_priv_to_dev(priv); | ||
1096 | |||
1097 | dev_dbg(dev, "setup packet OK\n"); | ||
1098 | |||
1099 | if (unlikely(!hpriv->done)) | ||
1100 | dev_err(dev, "setup ack happen without necessary data\n"); | ||
1101 | else | ||
1102 | complete(hpriv->done); /* see usbhsh_urb_enqueue() */ | ||
1103 | |||
1104 | return 0; | ||
1105 | } | ||
1106 | |||
1107 | static int usbhsh_irq_setup_err(struct usbhs_priv *priv, | ||
1108 | struct usbhs_irq_state *irq_state) | ||
1109 | { | ||
1110 | struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); | ||
1111 | struct device *dev = usbhs_priv_to_dev(priv); | ||
1112 | |||
1113 | dev_dbg(dev, "setup packet Err\n"); | ||
1114 | |||
1115 | if (unlikely(!hpriv->done)) | ||
1116 | dev_err(dev, "setup err happen without necessary data\n"); | ||
1117 | else | ||
1118 | complete(hpriv->done); /* see usbhsh_urb_enqueue() */ | ||
1119 | |||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | /* | ||
1124 | * module start/stop | ||
1125 | */ | ||
1126 | static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv) | ||
1127 | { | ||
1128 | struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); | ||
1129 | struct usbhsh_pipe_info *pipe_info = hpriv->pipe_info; | ||
1130 | struct usbhs_pipe *pipe; | ||
1131 | u32 *pipe_type = usbhs_get_dparam(priv, pipe_type); | ||
1132 | int pipe_size = usbhs_get_dparam(priv, pipe_size); | ||
1133 | int old_type, dir_in, i; | ||
1134 | |||
1135 | /* init all pipe */ | ||
1136 | old_type = USB_ENDPOINT_XFER_CONTROL; | ||
1137 | for (i = 0; i < pipe_size; i++) { | ||
1138 | pipe_info[i].usr_cnt = 0; | ||
1139 | |||
1140 | /* | ||
1141 | * data "output" will be finished as soon as possible, | ||
1142 | * but there is no guaranty at data "input" case. | ||
1143 | * | ||
1144 | * "input" needs "standby" pipe. | ||
1145 | * So, "input" direction pipe > "output" direction pipe | ||
1146 | * is good idea. | ||
1147 | * | ||
1148 | * 1st USB_ENDPOINT_XFER_xxx will be output direction, | ||
1149 | * and the other will be input direction here. | ||
1150 | * | ||
1151 | * ex) | ||
1152 | * ... | ||
1153 | * USB_ENDPOINT_XFER_ISOC -> dir out | ||
1154 | * USB_ENDPOINT_XFER_ISOC -> dir in | ||
1155 | * USB_ENDPOINT_XFER_BULK -> dir out | ||
1156 | * USB_ENDPOINT_XFER_BULK -> dir in | ||
1157 | * USB_ENDPOINT_XFER_BULK -> dir in | ||
1158 | * ... | ||
1159 | */ | ||
1160 | dir_in = (pipe_type[i] == old_type); | ||
1161 | old_type = pipe_type[i]; | ||
1162 | |||
1163 | if (USB_ENDPOINT_XFER_CONTROL == pipe_type[i]) { | ||
1164 | pipe = usbhs_dcp_malloc(priv); | ||
1165 | usbhsh_hpriv_to_dcp(hpriv) = pipe; | ||
1166 | } else { | ||
1167 | pipe = usbhs_pipe_malloc(priv, | ||
1168 | pipe_type[i], | ||
1169 | dir_in); | ||
1170 | } | ||
1171 | |||
1172 | pipe->mod_private = pipe_info + i; | ||
1173 | } | ||
1174 | } | ||
1175 | |||
1176 | static int usbhsh_start(struct usbhs_priv *priv) | ||
1177 | { | ||
1178 | struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); | ||
1179 | struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); | ||
1180 | struct usbhs_mod *mod = usbhs_mod_get_current(priv); | ||
1181 | struct device *dev = usbhs_priv_to_dev(priv); | ||
1182 | int ret; | ||
1183 | |||
1184 | /* add hcd */ | ||
1185 | ret = usb_add_hcd(hcd, 0, 0); | ||
1186 | if (ret < 0) | ||
1187 | return 0; | ||
1188 | |||
1189 | /* | ||
1190 | * pipe initialize and enable DCP | ||
1191 | */ | ||
1192 | usbhs_pipe_init(priv, | ||
1193 | usbhsh_dma_map_ctrl); | ||
1194 | usbhs_fifo_init(priv); | ||
1195 | usbhsh_pipe_init_for_host(priv); | ||
1196 | |||
1197 | /* | ||
1198 | * system config enble | ||
1199 | * - HI speed | ||
1200 | * - host | ||
1201 | * - usb module | ||
1202 | */ | ||
1203 | usbhs_sys_hispeed_ctrl(priv, 1); | ||
1204 | usbhs_sys_host_ctrl(priv, 1); | ||
1205 | usbhs_sys_usb_ctrl(priv, 1); | ||
1206 | |||
1207 | /* | ||
1208 | * enable irq callback | ||
1209 | */ | ||
1210 | mod->irq_attch = usbhsh_irq_attch; | ||
1211 | mod->irq_dtch = usbhsh_irq_dtch; | ||
1212 | mod->irq_sack = usbhsh_irq_setup_ack; | ||
1213 | mod->irq_sign = usbhsh_irq_setup_err; | ||
1214 | usbhs_irq_callback_update(priv, mod); | ||
1215 | |||
1216 | dev_dbg(dev, "start host\n"); | ||
1217 | |||
1218 | return ret; | ||
1219 | } | ||
1220 | |||
1221 | static int usbhsh_stop(struct usbhs_priv *priv) | ||
1222 | { | ||
1223 | struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); | ||
1224 | struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); | ||
1225 | struct device *dev = usbhs_priv_to_dev(priv); | ||
1226 | |||
1227 | usb_remove_hcd(hcd); | ||
1228 | |||
1229 | /* disable sys */ | ||
1230 | usbhs_sys_hispeed_ctrl(priv, 0); | ||
1231 | usbhs_sys_host_ctrl(priv, 0); | ||
1232 | usbhs_sys_usb_ctrl(priv, 0); | ||
1233 | |||
1234 | dev_dbg(dev, "quit host\n"); | ||
1235 | |||
1236 | return 0; | ||
1237 | } | ||
1238 | |||
1239 | int __devinit usbhs_mod_host_probe(struct usbhs_priv *priv) | ||
1240 | { | ||
1241 | struct usbhsh_hpriv *hpriv; | ||
1242 | struct usb_hcd *hcd; | ||
1243 | struct usbhsh_pipe_info *pipe_info; | ||
1244 | struct usbhsh_device *udev; | ||
1245 | struct device *dev = usbhs_priv_to_dev(priv); | ||
1246 | int pipe_size = usbhs_get_dparam(priv, pipe_size); | ||
1247 | int i; | ||
1248 | |||
1249 | /* initialize hcd */ | ||
1250 | hcd = usb_create_hcd(&usbhsh_driver, dev, usbhsh_hcd_name); | ||
1251 | if (!hcd) { | ||
1252 | dev_err(dev, "Failed to create hcd\n"); | ||
1253 | return -ENOMEM; | ||
1254 | } | ||
1255 | |||
1256 | pipe_info = kzalloc(sizeof(*pipe_info) * pipe_size, GFP_KERNEL); | ||
1257 | if (!pipe_info) { | ||
1258 | dev_err(dev, "Could not allocate pipe_info\n"); | ||
1259 | goto usbhs_mod_host_probe_err; | ||
1260 | } | ||
1261 | |||
1262 | /* | ||
1263 | * CAUTION | ||
1264 | * | ||
1265 | * There is no guarantee that it is possible to access usb module here. | ||
1266 | * Don't accesses to it. | ||
1267 | * The accesse will be enable after "usbhsh_start" | ||
1268 | */ | ||
1269 | |||
1270 | hpriv = usbhsh_hcd_to_hpriv(hcd); | ||
1271 | |||
1272 | /* | ||
1273 | * register itself | ||
1274 | */ | ||
1275 | usbhs_mod_register(priv, &hpriv->mod, USBHS_HOST); | ||
1276 | |||
1277 | /* init hpriv */ | ||
1278 | hpriv->mod.name = "host"; | ||
1279 | hpriv->mod.start = usbhsh_start; | ||
1280 | hpriv->mod.stop = usbhsh_stop; | ||
1281 | hpriv->pipe_info = pipe_info; | ||
1282 | hpriv->pipe_size = pipe_size; | ||
1283 | hpriv->done = NULL; | ||
1284 | usbhsh_req_list_init(hpriv); | ||
1285 | usbhsh_port_stat_init(hpriv); | ||
1286 | |||
1287 | /* init all device */ | ||
1288 | usbhsh_for_each_udev_with_dev0(udev, hpriv, i) { | ||
1289 | udev->usbv = NULL; | ||
1290 | INIT_LIST_HEAD(&udev->ep_list_head); | ||
1291 | } | ||
1292 | |||
1293 | dev_info(dev, "host probed\n"); | ||
1294 | |||
1295 | return 0; | ||
1296 | |||
1297 | usbhs_mod_host_probe_err: | ||
1298 | usb_put_hcd(hcd); | ||
1299 | |||
1300 | return -ENOMEM; | ||
1301 | } | ||
1302 | |||
1303 | int __devexit usbhs_mod_host_remove(struct usbhs_priv *priv) | ||
1304 | { | ||
1305 | struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv); | ||
1306 | struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); | ||
1307 | |||
1308 | usbhsh_req_list_quit(hpriv); | ||
1309 | |||
1310 | usb_put_hcd(hcd); | ||
1311 | |||
1312 | return 0; | ||
1313 | } | ||