2 * compdrv.c - USB driver stack project for Windows NT 4.0
4 * Copyright (c) 2002-2004 Zhiming mypublic99@yahoo.com
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.
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.
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
22 //this driver is part of the dev manager responsible to manage if device
23 #include "usbdriver.h"
25 VOID
compdev_set_cfg_completion(PURB purb
, PVOID context
);
26 VOID
compdev_select_driver(PUSB_DEV_MANAGER dev_mgr
, DEV_HANDLE dev_handle
);
27 BOOLEAN
compdev_connect(PDEV_CONNECT_DATA param
, DEV_HANDLE dev_handle
);
28 BOOLEAN
compdev_stop(PUSB_DEV_MANAGER dev_mgr
, DEV_HANDLE dev_handle
);
29 BOOLEAN
compdev_disconnect(PUSB_DEV_MANAGER dev_mgr
, DEV_HANDLE dev_handle
);
32 compdev_driver_init(PUSB_DEV_MANAGER dev_mgr
, PUSB_DRIVER pdriver
)
34 if (dev_mgr
== NULL
|| pdriver
== NULL
)
37 pdriver
->driver_desc
.flags
= USB_DRIVER_FLAG_DEV_CAPABLE
;
38 pdriver
->driver_desc
.vendor_id
= 0xffff; // USB Vendor ID
39 pdriver
->driver_desc
.product_id
= 0xffff; // USB Product ID.
40 pdriver
->driver_desc
.release_num
= 0x100; // Release Number of Device
42 pdriver
->driver_desc
.config_val
= 0; // Configuration Value
43 pdriver
->driver_desc
.if_num
= 0; // Interface Number
44 pdriver
->driver_desc
.if_class
= 0; // Interface Class
45 pdriver
->driver_desc
.if_sub_class
= 0; // Interface SubClass
46 pdriver
->driver_desc
.if_protocol
= 0; // Interface Protocol
48 pdriver
->driver_desc
.driver_name
= "USB composit dev driver"; // Driver name for Name Registry
49 pdriver
->driver_desc
.dev_class
= USB_CLASS_PER_INTERFACE
;
50 pdriver
->driver_desc
.dev_sub_class
= 0; // Device Subclass
51 pdriver
->driver_desc
.dev_protocol
= 0; // Protocol Info.
53 //we have no extra data sturcture currently
54 pdriver
->driver_ext
= NULL
;
55 pdriver
->driver_ext_size
= 0;
57 pdriver
->disp_tbl
.version
= 1;
58 pdriver
->disp_tbl
.dev_connect
= compdev_connect
;
59 pdriver
->disp_tbl
.dev_disconnect
= compdev_disconnect
;
60 pdriver
->disp_tbl
.dev_stop
= compdev_stop
;
61 pdriver
->disp_tbl
.dev_reserved
= NULL
;
67 compdev_driver_destroy(PUSB_DEV_MANAGER dev_mgr
, PUSB_DRIVER pdriver
)
69 UNREFERENCED_PARAMETER(dev_mgr
);
70 UNREFERENCED_PARAMETER(pdriver
);
75 compdev_connect(PDEV_CONNECT_DATA param
, DEV_HANDLE dev_handle
)
78 PUSB_CTRL_SETUP_PACKET psetup
;
82 PUSB_CONFIGURATION_DESC pconfig_desc
;
83 PUSB_INTERFACE_DESC pif_desc
;
84 PUSB_DEV_MANAGER dev_mgr
;
86 if (param
== NULL
|| dev_handle
== 0)
89 dev_mgr
= param
->dev_mgr
;
91 // let's set the configuration
92 purb
= usb_alloc_mem(NonPagedPool
, sizeof(URB
));
96 buf
= usb_alloc_mem(NonPagedPool
, 512);
99 usb_dbg_print(DBGLVL_MAXIMUM
, ("compdev_connect(): can not alloc buf\n"));
104 // before we set the configuration, let's search to find if there
105 // exist interfaces we supported
106 psetup
= (PUSB_CTRL_SETUP_PACKET
) (purb
)->setup_packet
;
108 purb
->endp_handle
= dev_handle
| 0xffff;
109 purb
->data_buffer
= buf
;
110 purb
->data_length
= 512;
111 purb
->completion
= NULL
; // this is an immediate request, no completion required
112 purb
->context
= NULL
;
114 psetup
->bmRequestType
= 0x80;
115 psetup
->bRequest
= USB_REQ_GET_DESCRIPTOR
;
116 psetup
->wValue
= USB_DT_CONFIG
<< 8;
118 psetup
->wLength
= 512;
120 status
= usb_submit_urb(dev_mgr
, purb
);
121 if (status
== STATUS_PENDING
)
129 // let's scan the interfacs for those we recognize
130 pconfig_desc
= (PUSB_CONFIGURATION_DESC
) buf
;
131 if (pconfig_desc
->wTotalLength
> 512)
135 usb_dbg_print(DBGLVL_MAXIMUM
, ("compdev_connect(): error, bad configuration desc\n"));
139 pif_desc
= (PUSB_INTERFACE_DESC
) & pconfig_desc
[1];
140 for(i
= 0, credit
= 0; i
< (LONG
) pconfig_desc
->bNumInterfaces
; i
++)
142 for(j
= 0; j
< DEVMGR_MAX_DRIVERS
; j
++)
144 credit
= dev_mgr_score_driver_for_if(dev_mgr
, &dev_mgr
->driver_list
[j
], pif_desc
);
151 if (usb_skip_if_and_altif((PUCHAR
*) & pif_desc
))
155 i
= pconfig_desc
->bConfigurationValue
;
161 usb_dbg_print(DBGLVL_MAXIMUM
, ("compdev_connect(): oops..., no supported interface found\n"));
165 //set the configuration
167 purb
->endp_handle
= dev_handle
| 0xffff;
168 purb
->data_buffer
= NULL
;
169 purb
->data_length
= 0;
170 purb
->completion
= compdev_set_cfg_completion
;
171 purb
->context
= dev_mgr
;
172 purb
->reference
= (ULONG
) param
->pdriver
;
173 psetup
->bmRequestType
= 0;
174 psetup
->bRequest
= USB_REQ_SET_CONFIGURATION
;
175 psetup
->wValue
= (USHORT
) i
;
179 usb_dbg_print(DBGLVL_MAXIMUM
, ("compdev_connect(): start config the device, cfgval=%d\n", i
));
180 status
= usb_submit_urb(dev_mgr
, purb
);
182 if (status
!= STATUS_PENDING
)
186 if (status
== STATUS_SUCCESS
)
196 compdev_event_select_if_driver(PUSB_DEV pdev
, ULONG event
, ULONG context
, ULONG param
)
198 PUSB_DEV_MANAGER dev_mgr
;
199 DEV_HANDLE dev_handle
;
201 UNREFERENCED_PARAMETER(param
);
202 UNREFERENCED_PARAMETER(context
);
203 UNREFERENCED_PARAMETER(event
);
209 // RtlZeroMemory( &cd, sizeof( cd ) );
211 dev_mgr
= dev_mgr_from_dev(pdev
);
212 dev_handle
= usb_make_handle(pdev
->dev_id
, 0, 0);
213 compdev_select_driver(dev_mgr
, dev_handle
);
218 compdev_post_event_select_driver(PUSB_DEV_MANAGER dev_mgr
, DEV_HANDLE dev_handle
)
223 USE_BASIC_NON_PENDING_IRQL
;
225 if (dev_mgr
== NULL
|| dev_handle
== 0)
228 if (usb_query_and_lock_dev(dev_mgr
, dev_handle
, &pdev
) != STATUS_SUCCESS
)
231 KeAcquireSpinLockAtDpcLevel(&dev_mgr
->event_list_lock
);
232 lock_dev(pdev
, TRUE
);
234 if (dev_state(pdev
) == USB_DEV_STATE_ZOMB
)
240 pevent
= alloc_event(&dev_mgr
->event_pool
, 1);
246 pevent
->flags
= USB_EVENT_FLAG_ACTIVE
;
247 pevent
->event
= USB_EVENT_DEFAULT
;
251 pevent
->pnext
= 0; //vertical queue for serialized operation
252 pevent
->process_event
= compdev_event_select_if_driver
;
253 pevent
->process_queue
= event_list_default_process_queue
;
255 InsertTailList(&dev_mgr
->event_list
, &pevent
->event_link
);
256 KeSetEvent(&dev_mgr
->wake_up_event
, 0, FALSE
); // wake up the dev_mgr_thread
261 unlock_dev(pdev
, TRUE
);
262 KeReleaseSpinLockFromDpcLevel(&dev_mgr
->event_list_lock
);
263 usb_unlock_dev(pdev
);
268 compdev_set_cfg_completion(PURB purb
, PVOID context
)
270 DEV_HANDLE dev_handle
;
271 PUSB_DEV_MANAGER dev_mgr
;
275 USE_BASIC_NON_PENDING_IRQL
;
277 if (purb
== NULL
|| context
== NULL
)
280 dev_handle
= purb
->endp_handle
& ~0xffff;
281 dev_mgr
= (PUSB_DEV_MANAGER
) context
;
282 pdriver
= (PUSB_DRIVER
) purb
->reference
;
284 if (purb
->status
!= STATUS_SUCCESS
)
294 status
= usb_query_and_lock_dev(dev_mgr
, dev_handle
, &pdev
);
295 if (status
!= STATUS_SUCCESS
)
297 usb_unlock_dev(pdev
);
300 // safe to release the pdev ref since we are in urb completion
301 usb_unlock_dev(pdev
);
303 lock_dev(pdev
, TRUE
);
304 if (dev_state(pdev
) >= USB_DEV_STATE_BEFORE_ZOMB
)
306 unlock_dev(pdev
, TRUE
);
310 if (dev_mgr_set_driver(dev_mgr
, dev_handle
, pdriver
, pdev
) == FALSE
)
313 //transit the state to configured
314 pdev
->flags
&= ~USB_DEV_STATE_MASK
;
315 pdev
->flags
|= USB_DEV_STATE_CONFIGURED
;
316 unlock_dev(pdev
, TRUE
);
319 // we change to use our thread for driver choosing. it will reduce
320 // the race condition when different pnp event comes simultaneously
322 usb_dbg_print(DBGLVL_MAXIMUM
, ("compdev_set_cfg_completion(): start select driver for the dev\n"));
323 compdev_post_event_select_driver(dev_mgr
, dev_handle
);
329 compdev_select_driver(PUSB_DEV_MANAGER dev_mgr
, DEV_HANDLE dev_handle
)
332 LONG i
, j
, k
, credit
;
336 PUSB_DRIVER pcand
, ptemp_drv
;
338 PUSB_CTRL_SETUP_PACKET psetup
;
339 PUSB_INTERFACE_DESC pif_desc
;
340 PUSB_CONFIGURATION_DESC pconfig_desc
;
343 usb_dbg_print(DBGLVL_MAXIMUM
, ("compdev_select_driver(): entering...\n"));
345 dev_id
= dev_handle
>> 16;
347 buf
= usb_alloc_mem(NonPagedPool
, 512);
352 // now let's get the descs, one configuration
354 psetup
= (PUSB_CTRL_SETUP_PACKET
) urb
.setup_packet
;
355 urb
.endp_handle
= dev_handle
| 0xffff;
356 urb
.data_buffer
= buf
;
357 urb
.data_length
= 512;
358 urb
.completion
= NULL
; // this is an immediate request, no completion required
361 psetup
->bmRequestType
= 0x80;
362 psetup
->bRequest
= USB_REQ_GET_DESCRIPTOR
;
363 psetup
->wValue
= USB_DT_CONFIG
<< 8;
365 psetup
->wLength
= 512;
367 status
= usb_submit_urb(dev_mgr
, &urb
);
368 if (status
== STATUS_PENDING
)
373 // let's scan the interfaces for those we recognize
374 pconfig_desc
= (PUSB_CONFIGURATION_DESC
) buf
;
375 if (pconfig_desc
->wTotalLength
> 512)
378 usb_dbg_print(DBGLVL_MAXIMUM
, ("compdev_select_driver(): error, bad configuration desc\n"));
381 pif_desc
= (PUSB_INTERFACE_DESC
) & pconfig_desc
[1];
383 if (usb_query_and_lock_dev(dev_mgr
, dev_handle
, &pdev
) != STATUS_SUCCESS
)
386 usb_dbg_print(DBGLVL_MAXIMUM
, ("compdev_select_driver(): error, dev does not exist\n"));
390 usb_dbg_print(DBGLVL_MAXIMUM
, ("compdev_select_driver(): got %d interfaces\n",
391 (LONG
)pconfig_desc
->bNumInterfaces
));
393 for(i
= 0; i
< (LONG
) pconfig_desc
->bNumInterfaces
; i
++)
395 for(j
= 0, credit
= 0, pcand
= NULL
; j
< DEVMGR_MAX_DRIVERS
; j
++)
397 ptemp_drv
= &dev_mgr
->driver_list
[j
];
398 k
= dev_mgr_score_driver_for_if(dev_mgr
, ptemp_drv
, pif_desc
);
400 credit
= k
, pcand
= ptemp_drv
;
406 DEV_CONNECT_DATA param
;
408 if (pcand
->disp_tbl
.dev_connect
)
410 param
.dev_mgr
= dev_mgr
;
411 param
.pdriver
= pcand
;
412 param
.dev_handle
= 0;
413 param
.if_desc
= pif_desc
;
414 pcand
->disp_tbl
.dev_connect(¶m
, usb_make_handle(dev_id
, i
, 0));
417 if (usb_skip_if_and_altif((PUCHAR
*) & pif_desc
) == FALSE
)
422 usb_unlock_dev(pdev
);
433 compdev_stop(PUSB_DEV_MANAGER dev_mgr
, DEV_HANDLE dev_handle
)
441 if (dev_mgr
== NULL
|| dev_handle
== 0)
445 dev_id
= dev_handle
>> 16;
446 status
= usb_query_and_lock_dev(dev_mgr
, dev_handle
, &pdev
);
449 if (pdev
->usb_config
)
451 for(i
= 0; i
< pdev
->usb_config
->if_count
; i
++)
453 if ((pdrv
= pdev
->usb_config
->interf
[i
].pif_drv
))
455 pdrv
->disp_tbl
.dev_stop(dev_mgr
, usb_make_handle(dev_id
, i
, 0));
460 if (status
== STATUS_SUCCESS
)
462 usb_unlock_dev(pdev
);
468 compdev_disconnect(PUSB_DEV_MANAGER dev_mgr
, DEV_HANDLE dev_handle
)
476 if (dev_mgr
== NULL
|| dev_handle
== 0)
480 dev_id
= dev_handle
>> 16;
481 status
= usb_query_and_lock_dev(dev_mgr
, dev_handle
, &pdev
);
484 if (pdev
->usb_config
)
486 for(i
= 0; i
< pdev
->usb_config
->if_count
; i
++)
488 if ((pdrv
= pdev
->usb_config
->interf
[i
].pif_drv
))
490 pdrv
->disp_tbl
.dev_disconnect(dev_mgr
, usb_make_handle(dev_id
, i
, 0));
495 if (status
== STATUS_SUCCESS
)
497 usb_unlock_dev(pdev
);
503 // dev_mgr_set_driver seems to be dangeous since compdev, gendrv and hub and
504 // umss use it to set the driver while there may exist race condition when the
505 // dev_mgr_disconnect_dev is called. If the driver is set and the
506 // disconnect_dev cut in immediately, the stop or disconnect may not function
507 // well. Now hub and compdev's set dev_mgr_set_driver are ok.
509 // another danger comes from umss's dev irp processing. This may confuse the device
510 // when the disk is being read or written, and at the same time dmgrdisp's dispatch
511 // route irp request to the device a control request.