[CMAKE]
[reactos.git] / drivers / usb / nt4compat / usbdriver / roothub.c
1 /**
2 * roothub.c - USB driver stack project for Windows NT 4.0
3 *
4 * Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
5 *
6 * This program/include file is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as published
8 * by the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program/include file is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program (in the main directory of the distribution, the file
18 * COPYING); if not, write to the Free Software Foundation,Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include "usbdriver.h"
23
24 //----------------------------------------------------------
25
26 BOOLEAN
27 rh_driver_destroy(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
28 {
29 LONG i;
30 PHCD hcd;
31
32 if (dev_mgr == NULL)
33 return FALSE;
34
35 for(i = 0; i < dev_mgr->hcd_count; i++)
36 {
37 hcd = dev_mgr->hcd_array[i];
38 // if( hcd->hcd_get_type( hcd ) != HCD_TYPE_UHCI )
39 // continue;
40 rh_destroy(hcd->hcd_get_root_hub(hcd));
41 }
42 return TRUE;
43 }
44
45 BOOLEAN
46 rh_driver_init(PUSB_DEV_MANAGER dev_mgr, PUSB_DRIVER pdriver)
47 {
48
49 PUSB_DEV rh;
50 PUSB_CONFIGURATION_DESC pconfig_desc;
51 PUSB_INTERFACE_DESC pif_desc;
52 PUSB_ENDPOINT_DESC pendp_desc;
53 PUSB_CONFIGURATION pconfig;
54 PUSB_INTERFACE pif;
55 PUSB_ENDPOINT pendp;
56 PHUB2_EXTENSION phub_ext;
57 NTSTATUS status;
58 PHCD hcd;
59 LONG i;
60
61 if (dev_mgr == NULL || pdriver == NULL)
62 return FALSE;
63
64 //init driver structure, no PNP table functions
65 pdriver->driver_desc.flags = USB_DRIVER_FLAG_DEV_CAPABLE;
66 pdriver->driver_desc.vendor_id = 0xffff; // USB Vendor ID
67 pdriver->driver_desc.product_id = 0xffff; // USB Product ID.
68 pdriver->driver_desc.release_num = 0xffff; // Release Number of Device
69
70 pdriver->driver_desc.config_val = 0; // Configuration Value
71 pdriver->driver_desc.if_num = 0; // Interface Number
72 pdriver->driver_desc.if_class = USB_CLASS_HUB; // Interface Class
73 pdriver->driver_desc.if_sub_class = 0; // Interface SubClass
74 pdriver->driver_desc.if_protocol = 0; // Interface Protocol
75
76 pdriver->driver_desc.driver_name = "USB root hub"; // Driver name for Name Registry
77 pdriver->driver_desc.dev_class = USB_CLASS_HUB;
78 pdriver->driver_desc.dev_sub_class = 0; // Device Subclass
79 pdriver->driver_desc.dev_protocol = 0; // Protocol Info.
80
81 //pdriver->driver_init = rh_driver_init; // initialized in dev_mgr_init_driver
82 //pdriver->driver_destroy = rh_driver_destroy;
83 pdriver->disp_tbl.version = 1; // other fields of the dispatch table is not used since rh needs no pnp
84
85 pdriver->driver_ext = 0;
86 pdriver->driver_ext_size = 0;
87
88 for(i = 0; i < dev_mgr->hcd_count; i++)
89 {
90 hcd = dev_mgr->hcd_array[i];
91 //if( hcd->hcd_get_type( hcd ) != HCD_TYPE_UHCI )
92 // continue;
93
94 if ((rh = dev_mgr_alloc_device(dev_mgr, hcd)) == NULL)
95 return FALSE;
96
97 rh->parent_dev = NULL;
98 rh->port_idx = 0;
99 rh->hcd = hcd;
100 rh->flags = USB_DEV_CLASS_ROOT_HUB | USB_DEV_STATE_CONFIGURED;
101
102 if (usb2(hcd))
103 rh->flags |= USB_DEV_FLAG_HIGH_SPEED;
104
105 rh->dev_driver = pdriver;
106
107 rh->desc_buf_size = sizeof(USB_DEVICE_DESC)
108 + sizeof(USB_CONFIGURATION_DESC)
109 + sizeof(USB_INTERFACE_DESC)
110 + sizeof(USB_ENDPOINT_DESC) + sizeof(USB_CONFIGURATION) + sizeof(HUB2_EXTENSION);
111
112 rh->desc_buf = usb_alloc_mem(NonPagedPool, rh->desc_buf_size);
113
114 if (rh->desc_buf == NULL)
115 {
116 return FALSE;
117 }
118 else
119 RtlZeroMemory(rh->desc_buf, rh->desc_buf_size);
120
121 rh->pusb_dev_desc = (PUSB_DEVICE_DESC) rh->desc_buf;
122
123 rh->pusb_dev_desc->bLength = sizeof(USB_DEVICE_DESC);
124 rh->pusb_dev_desc->bDescriptorType = USB_DT_DEVICE;
125 rh->pusb_dev_desc->bcdUSB = 0x110;
126 if (usb2(hcd))
127 rh->pusb_dev_desc->bcdUSB = 0x200;
128 rh->pusb_dev_desc->bDeviceClass = USB_CLASS_HUB;
129 rh->pusb_dev_desc->bDeviceSubClass = 0;
130 rh->pusb_dev_desc->bDeviceProtocol = 0;
131 rh->pusb_dev_desc->bMaxPacketSize0 = 8;
132 if (usb2(hcd))
133 {
134 rh->pusb_dev_desc->bDeviceProtocol = 1;
135 rh->pusb_dev_desc->bMaxPacketSize0 = 64;
136 }
137 rh->pusb_dev_desc->idVendor = 0;
138 rh->pusb_dev_desc->idProduct = 0;
139 rh->pusb_dev_desc->bcdDevice = 0x100;
140 rh->pusb_dev_desc->iManufacturer = 0;
141 rh->pusb_dev_desc->iProduct = 0;
142 rh->pusb_dev_desc->iSerialNumber = 0;
143 rh->pusb_dev_desc->bNumConfigurations = 1;
144
145 pconfig_desc = (PUSB_CONFIGURATION_DESC) & rh->desc_buf[sizeof(USB_DEVICE_DESC)];
146 pif_desc = (PUSB_INTERFACE_DESC) & pconfig_desc[1];
147 pendp_desc = (PUSB_ENDPOINT_DESC) & pif_desc[1];
148
149 pconfig_desc->bLength = sizeof(USB_CONFIGURATION_DESC);
150 pconfig_desc->bDescriptorType = USB_DT_CONFIG;
151
152 pconfig_desc->wTotalLength = sizeof(USB_CONFIGURATION_DESC)
153 + sizeof(USB_INTERFACE_DESC) + sizeof(USB_ENDPOINT_DESC);
154
155 pconfig_desc->bNumInterfaces = 1;
156 pconfig_desc->bConfigurationValue = 1;
157 pconfig_desc->iConfiguration = 0;
158 pconfig_desc->bmAttributes = 0Xe0; //self-powered and support remoke wakeup
159 pconfig_desc->MaxPower = 0;
160
161 pif_desc->bLength = sizeof(USB_INTERFACE_DESC);
162 pif_desc->bDescriptorType = USB_DT_INTERFACE;
163 pif_desc->bInterfaceNumber = 0;
164 pif_desc->bAlternateSetting = 0;
165 pif_desc->bNumEndpoints = 1;
166 pif_desc->bInterfaceClass = USB_CLASS_HUB;
167 pif_desc->bInterfaceSubClass = 0;
168 pif_desc->bInterfaceProtocol = 0;
169 pif_desc->iInterface = 0;
170
171 pendp_desc->bLength = sizeof(USB_ENDPOINT_DESC);
172 pendp_desc->bDescriptorType = USB_DT_ENDPOINT;
173 pendp_desc->bEndpointAddress = 0x81;
174 pendp_desc->bmAttributes = 0x03;
175 pendp_desc->wMaxPacketSize = 8;
176 pendp_desc->bInterval = USB_HUB_INTERVAL;
177 if (usb2(hcd))
178 pendp_desc->bInterval = 0x0c;
179
180 pconfig = rh->usb_config = (PUSB_CONFIGURATION) & pendp_desc[1];
181 rh->active_config_idx = 0;
182 pconfig->pusb_config_desc = pconfig_desc;
183 pconfig->if_count = 1;
184 pconfig->pusb_dev = rh;
185 pif = &pconfig->interf[0];
186
187 pif->endp_count = 1;
188 pendp = &pif->endp[0];
189 pif->pusb_config = pconfig;
190 pif->pusb_if_desc = pif_desc;
191
192 pif->if_ext_size = 0;
193 pif->if_ext = NULL;
194
195 phub_ext = (PHUB2_EXTENSION) & pconfig[1];
196 phub_ext->port_count = 2;
197
198 if (usb2(hcd))
199 {
200 // port count is configurable in usb2
201 hcd->hcd_dispatch(hcd, HCD_DISP_READ_PORT_COUNT, &phub_ext->port_count);
202 }
203
204 {
205 int j;
206 for(j = 0; j < phub_ext->port_count; j++)
207 {
208 psq_init(&phub_ext->port_status_queue[j]);
209 phub_ext->child_dev[j] = NULL;
210 usb_dbg_print(DBGLVL_MAXIMUM, ("rh_driver_init(): port[ %d ].flag=0x%x\n",
211 j, phub_ext->port_status_queue[j].port_flags));
212 }
213 }
214
215 phub_ext->pif = pif;
216 phub_ext->hub_desc.bLength = sizeof(USB_HUB_DESCRIPTOR);
217 phub_ext->hub_desc.bDescriptorType = USB_DT_HUB;
218 phub_ext->hub_desc.bNbrPorts = (UCHAR) phub_ext->port_count;
219 phub_ext->hub_desc.wHubCharacteristics = 0;
220 phub_ext->hub_desc.bPwrOn2PwrGood = 0;
221 phub_ext->hub_desc.bHubContrCurrent = 50;
222
223 rh->dev_ext = (PBYTE) phub_ext;
224 rh->dev_ext_size = sizeof(HUB2_EXTENSION);
225
226 rh->default_endp.flags = USB_ENDP_FLAG_DEFAULT_ENDP;
227 InitializeListHead(&rh->default_endp.urb_list);
228 rh->default_endp.pusb_if = (PUSB_INTERFACE) rh;
229 rh->default_endp.pusb_endp_desc = NULL; //???
230 rh->time_out_count = 0;
231 rh->error_count = 0;
232
233 InitializeListHead(&pendp->urb_list);
234 pendp->flags = 0;
235 pendp->pusb_endp_desc = pendp_desc;
236 pendp->pusb_if = pif;
237
238 //add to device list
239 InsertTailList(&dev_mgr->dev_list, &rh->dev_link);
240 hcd->hcd_set_root_hub(hcd, rh);
241 status = hub_start_int_request(rh);
242 pdriver->driver_ext = 0;
243 }
244 return TRUE;
245 }
246
247 //to be the reverse of what init does, we assume that the timer is now killed
248 //int is disconnected and the hub thread will not process event anymore
249 BOOLEAN
250 rh_destroy(PUSB_DEV pdev)
251 {
252 PUSB_DEV rh;
253 PUSB_DEV_MANAGER dev_mgr;
254
255 if (pdev == NULL)
256 return FALSE;
257
258 dev_mgr = dev_mgr_from_dev(pdev);
259
260 //???
261 rh = pdev->hcd->hcd_get_root_hub(pdev->hcd);
262 if (rh == pdev)
263 {
264 //free all the buf
265 dev_mgr_free_device(dev_mgr, rh);
266 //dev_mgr->root_hub = NULL;
267 }
268
269 return TRUE;
270 }
271
272 VOID
273 rh_timer_svc_int_completion(PUSB_DEV pdev, PVOID context)
274 {
275 PURB purb;
276 PHCD hcd;
277 USE_BASIC_NON_PENDING_IRQL;
278
279 if (pdev == NULL || context == NULL)
280 return;
281
282 purb = (PURB) context;
283
284 lock_dev(pdev, TRUE);
285
286 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
287 {
288 pdev->ref_count -= 2; // one for timer_svc and one for urb, for those rh requests
289 unlock_dev(pdev, TRUE);
290 usb_free_mem(purb);
291 usb_dbg_print(DBGLVL_MAXIMUM, ("rh_timer_svc_int_completion(): the dev is zomb, 0x%x\n", pdev));
292 return;
293 }
294
295 hcd = pdev->hcd;
296 if (purb->data_length < 1)
297 {
298 purb->status = STATUS_INVALID_PARAMETER;
299 unlock_dev(pdev, TRUE);
300 goto LBL_OUT;
301 }
302
303 pdev->hcd->hcd_dispatch(pdev->hcd, HCD_DISP_READ_RH_DEV_CHANGE, purb->data_buffer);
304 purb->status = STATUS_SUCCESS;
305 unlock_dev(pdev, TRUE);
306
307 LBL_OUT:
308 hcd->hcd_generic_urb_completion(purb, purb->context);
309
310 lock_dev(pdev, TRUE);
311 pdev->ref_count -= 2;
312 // one for timer_svc and one for urb, for those rh requests
313 // that completed immediately, the ref_count of the dev for
314 // that urb won't increment and for normal hub request
315 // completion, hcd_generic_urb_completion will be called
316 // by the xhci_dpc_callback, and the ref_count for the urb
317 // is maintained there. So only rh's timer-svc cares refcount
318 // when hcd_generic_urb_completion is called.
319 usb_dbg_print(DBGLVL_ULTRA, ("rh_timer_svc_int_completion(): rh's ref_count=0x%x\n", pdev->ref_count));
320 unlock_dev(pdev, TRUE);
321 usb_dbg_print(DBGLVL_ULTRA, ("rh_timer_svc_int_completion(): exitiing...\n"));
322 return;
323 }
324
325 VOID
326 rh_timer_svc_reset_port_completion(PUSB_DEV pdev, PVOID context)
327 {
328 PURB purb;
329 ULONG i;
330 PHUB2_EXTENSION hub_ext;
331 PLIST_ENTRY pthis, pnext;
332 PUSB_DEV_MANAGER dev_mgr;
333 PUSB_CTRL_SETUP_PACKET psetup;
334
335 USE_BASIC_NON_PENDING_IRQL;
336
337 if (pdev == NULL || context == NULL)
338 return;
339
340 dev_mgr = dev_mgr_from_dev(pdev); //readonly and hold ref_count
341
342 //block the rh polling
343 KeAcquireSpinLockAtDpcLevel(&dev_mgr->timer_svc_list_lock);
344 if (IsListEmpty(&dev_mgr->timer_svc_list) == FALSE)
345 {
346 ListFirst(&dev_mgr->timer_svc_list, pthis);
347 while (pthis)
348 {
349 if (((PTIMER_SVC) pthis)->pdev == pdev && ((PTIMER_SVC) pthis)->threshold == RH_INTERVAL)
350 {
351 ((PTIMER_SVC) pthis)->threshold = RH_INTERVAL + 0x800000;
352 break;
353 }
354
355 ListNext(&dev_mgr->timer_svc_list, pthis, pnext);
356 pthis = pnext;
357 }
358 }
359 KeReleaseSpinLockFromDpcLevel(&dev_mgr->timer_svc_list_lock);
360
361 purb = (PURB) context;
362 psetup = (PUSB_CTRL_SETUP_PACKET) purb->setup_packet;
363
364 lock_dev(pdev, TRUE);
365 if (dev_state(pdev) == USB_DEV_STATE_ZOMB)
366 {
367 //purb->status = STATUS_ERROR;
368 //pdev->hcd->hcd_generic_urb_completion( purb, purb->context );
369
370 pdev->ref_count -= 2;
371 unlock_dev(pdev, TRUE);
372 usb_free_mem(purb);
373 return;
374 }
375
376 i = pdev->hcd->hcd_rh_reset_port(pdev->hcd, (UCHAR) psetup->wIndex);
377
378 hub_ext = hub_ext_from_dev(pdev);
379
380 {
381 USHORT temp;
382 PUCHAR pbuf;
383 if (psetup->wIndex < 16)
384 {
385 temp = 1 << psetup->wIndex;
386 pbuf = (PUCHAR) & temp;
387 if (temp > 128)
388 pbuf++;
389 hub_ext->int_data_buf[psetup->wIndex / 8] |= *pbuf;
390 if (i == TRUE)
391 hub_ext->rh_port_status[psetup->wIndex].wPortChange |= USB_PORT_STAT_C_RESET;
392 else // notify that is not a high speed device, will lost definitely
393 hub_ext->rh_port_status[psetup->wIndex].wPortChange |= USB_PORT_STAT_C_CONNECTION;
394 }
395 }
396
397 //???how to construct port status map
398 // decrease the timer_svc ref-count
399 pdev->ref_count--;
400 unlock_dev(pdev, TRUE);
401
402 purb->status = STATUS_SUCCESS;
403 //we delegate the completion to the rh_timer_svc_int_completion.
404 //this function is equivalent to hub_start_reset_port_completion
405
406 usb_free_mem(purb);
407
408 //expire the rh polling timer
409 KeAcquireSpinLockAtDpcLevel(&dev_mgr->timer_svc_list_lock);
410 if (IsListEmpty(&dev_mgr->timer_svc_list) == FALSE)
411 {
412 ListFirst(&dev_mgr->timer_svc_list, pthis);
413 while (pthis)
414 {
415 if (((PTIMER_SVC) pthis)->pdev == pdev &&
416 ((PTIMER_SVC) pthis)->threshold == RH_INTERVAL + 0x800000)
417 {
418 ((PTIMER_SVC) pthis)->counter = RH_INTERVAL;
419 ((PTIMER_SVC) pthis)->threshold = RH_INTERVAL;
420 break;
421 }
422
423 ListNext(&dev_mgr->timer_svc_list, pthis, pnext);
424 pthis = pnext;
425 }
426 }
427 KeReleaseSpinLockFromDpcLevel(&dev_mgr->timer_svc_list_lock);
428
429 lock_dev(pdev, TRUE);
430 pdev->ref_count--;
431 unlock_dev(pdev, TRUE);
432 return;
433 }