b39d2965035d06e6ba4b3905214e41d400400b68
[mirror/winof/.git] / core / bus / kernel / bus_driver.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  * Copyright (c) 2006 Mellanox Technologies.  All rights reserved.\r
4  *\r
5  * This software is available to you under the OpenIB.org BSD license\r
6  * below:\r
7  *\r
8  *     Redistribution and use in source and binary forms, with or\r
9  *     without modification, are permitted provided that the following\r
10  *     conditions are met:\r
11  *\r
12  *      - Redistributions of source code must retain the above\r
13  *        copyright notice, this list of conditions and the following\r
14  *        disclaimer.\r
15  *\r
16  *      - Redistributions in binary form must reproduce the above\r
17  *        copyright notice, this list of conditions and the following\r
18  *        disclaimer in the documentation and/or other materials\r
19  *        provided with the distribution.\r
20  *\r
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
22  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
24  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
25  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
26  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
27  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
28  * SOFTWARE.\r
29  *\r
30  * $Id$\r
31  */\r
32 \r
33 \r
34 /*\r
35  * Provides the driver entry points for the InfiniBand Bus Driver.\r
36  */\r
37 \r
38 #include <complib/cl_types.h>\r
39 #include "bus_driver.h"\r
40 #include "bus_pnp.h"\r
41 #include "al_mgr.h"\r
42 #include "al_dev.h"\r
43 #include "al_debug.h"\r
44 #include <complib/cl_init.h>\r
45 #include "iba/ipoib_ifc.h"\r
46 \r
47 #if defined(EVENT_TRACING)\r
48 #ifdef offsetof\r
49 #undef offsetof\r
50 #endif\r
51 #include "bus_driver.tmh"\r
52 #endif\r
53 \r
54 #ifdef WINIB\r
55 #define DEFAULT_NODE_DESC       "Mellanox Windows® Host"\r
56 #else\r
57 #define DEFAULT_NODE_DESC       "OpenIB Windows® Host"\r
58 #endif\r
59 /* pkey array to be read */\r
60 pkey_array_t  g_pkeys;\r
61 \r
62 char    node_desc[IB_NODE_DESCRIPTION_SIZE];\r
63 \r
64 bus_globals_t   bus_globals = {\r
65         BUS_DBG_ERROR,\r
66         TRUE,\r
67         NULL,\r
68         NULL\r
69 };\r
70 \r
71 static void\r
72 __read_machine_name( void );\r
73 \r
74 static NTSTATUS\r
75 __read_registry(\r
76         IN                              UNICODE_STRING* const           p_Param_Path );\r
77 \r
78 static NTSTATUS\r
79 bus_drv_open(\r
80         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
81         IN                              IRP                                                     *p_irp );\r
82 \r
83 static NTSTATUS\r
84 bus_drv_cleanup(\r
85         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
86         IN                              IRP                                                     *p_irp );\r
87 \r
88 static NTSTATUS\r
89 bus_drv_close(\r
90         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
91         IN                              IRP                                                     *p_irp );\r
92 \r
93 static NTSTATUS\r
94 bus_drv_ioctl(\r
95         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
96         IN                              IRP                                                     *p_irp );\r
97 \r
98 /***f* InfiniBand Bus Driver/bus_drv_sysctl\r
99 * NAME\r
100 *       bus_drv_sysctl\r
101 *\r
102 * DESCRIPTION\r
103 *       Entry point for handling WMI IRPs.\r
104 *\r
105 * SYNOPSIS\r
106 */\r
107 static NTSTATUS\r
108 bus_drv_sysctl(\r
109         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
110         IN                              IRP                                                     *p_irp );\r
111 /**********/\r
112 \r
113 static void\r
114 bus_drv_unload(\r
115         IN                              DRIVER_OBJECT                           *p_driver_obj );\r
116 \r
117 NTSTATUS\r
118 DriverEntry(\r
119         IN                              DRIVER_OBJECT                           *p_driver_obj,\r
120         IN                              UNICODE_STRING                          *p_registry_path );\r
121 \r
122 \r
123 #ifdef ALLOC_PRAGMA\r
124 #pragma alloc_text (INIT, DriverEntry)\r
125 #pragma alloc_text (INIT, __read_machine_name)\r
126 #pragma alloc_text (INIT, __read_registry)\r
127 #pragma alloc_text (PAGE, bus_drv_unload)\r
128 #pragma alloc_text (PAGE, bus_drv_open)\r
129 #pragma alloc_text (PAGE, bus_drv_close)\r
130 #pragma alloc_text (PAGE, bus_drv_ioctl)\r
131 #pragma alloc_text (PAGE_PNP, bus_drv_sysctl)\r
132 #endif\r
133 \r
134 \r
135 static void\r
136 __read_machine_name( void )\r
137 {\r
138         NTSTATUS                                        status;\r
139         /* Remember the terminating entry in the table below. */\r
140         RTL_QUERY_REGISTRY_TABLE        table[2];\r
141         UNICODE_STRING                          hostNamePath;\r
142         UNICODE_STRING                          hostNameW;\r
143         ANSI_STRING                                     hostName;\r
144 \r
145         BUS_ENTER( BUS_DBG_DRV );\r
146 \r
147         /* Get the host name. */\r
148         RtlInitUnicodeString( &hostNamePath, L"ComputerName\\ComputerName" );\r
149         RtlInitUnicodeString( &hostNameW, NULL );\r
150 \r
151         /*\r
152          * Clear the table.  This clears all the query callback pointers,\r
153          * and sets up the terminating table entry.\r
154          */\r
155         cl_memclr( table, sizeof(table) );\r
156         cl_memclr( node_desc, sizeof(node_desc) );\r
157 \r
158         /* Setup the table entries. */\r
159         table[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;\r
160         table[0].Name = L"ComputerName";\r
161         table[0].EntryContext = &hostNameW;\r
162         table[0].DefaultType = REG_SZ;\r
163         table[0].DefaultData = &hostNameW;\r
164         table[0].DefaultLength = 0;\r
165 \r
166         /* Have at it! */\r
167         status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL, \r
168                 hostNamePath.Buffer, table, NULL, NULL );\r
169         if( NT_SUCCESS( status ) )\r
170         {\r
171                 /* Convert the UNICODE host name to UTF-8 (ASCII). */\r
172                 hostName.Length = 0;\r
173                 hostName.MaximumLength = sizeof(node_desc);\r
174                 hostName.Buffer = node_desc;\r
175                 status = RtlUnicodeStringToAnsiString( &hostName, &hostNameW, FALSE );\r
176                 RtlFreeUnicodeString( &hostNameW );\r
177         }\r
178         else\r
179         {\r
180                 BUS_TRACE(BUS_DBG_ERROR , ("Failed to get host name.\n") );\r
181                 /* Use the default name... */\r
182                 RtlStringCbCopyNA( node_desc, sizeof(node_desc),\r
183                         DEFAULT_NODE_DESC, sizeof(DEFAULT_NODE_DESC) );\r
184         }\r
185 }\r
186 /************************************************************************************\r
187 * name  :       __prepare_pKey_array\r
188 *           parses registry string and exrtacts pkey value(s) from it.\r
189 *                       pkey pattern is 0xABCD\r
190 * input :       UNICODE_STRING *str\r
191 * output:       pkey_array\r
192 * return:       uint16_t number of pkey(s) found\r
193 *************************************************************************************/\r
194 static uint16_t __prepare_pKey_array(IN const UNICODE_STRING *str, OUT uint16_t *pkey_array)\r
195 {\r
196         uint16_t i, num_pKeys, cur_pkey_length;\r
197         NTSTATUS status;\r
198         ANSI_STRING ansi_str;\r
199         static const uint16_t PATTERN_LENGTH = 6;\r
200         BUS_ENTER( BUS_DBG_DRV );\r
201 \r
202         CL_ASSERT(pkey_array);\r
203         CL_ASSERT(str);\r
204 \r
205         num_pKeys = 0;\r
206     cur_pkey_length = 0;\r
207 \r
208         status = RtlUnicodeStringToAnsiString(&ansi_str,str,TRUE);\r
209         if(! NT_SUCCESS(status))\r
210         {\r
211                 BUS_TRACE(BUS_DBG_ERROR ,\r
212                 ("RtlUnicodeStringToAnsiString returned 0x%.8x\n", status) );\r
213                 return 0;\r
214         }\r
215         \r
216         for (i = 0; (i < ansi_str.MaximumLength) && (num_pKeys < MAX_NUM_PKEY) ; i++)\r
217     {\r
218                 switch(ansi_str.Buffer[i])\r
219                 {\r
220                 case '0':\r
221                         cur_pkey_length++;\r
222                         if (((i+1) < ansi_str.Length) && ( ( ansi_str.Buffer[i+1] == 'x') || ( ansi_str.Buffer[i+1] == 'X')))\r
223                                 break;\r
224                         else\r
225                         {\r
226                                 pkey_array[num_pKeys] = \\r
227                                 (pkey_array[num_pKeys] << 4)| 0;\r
228                                 break;\r
229                         }\r
230 \r
231                 case 'x':\r
232                 case 'X':\r
233                         cur_pkey_length++;\r
234                         break;\r
235 \r
236                 case ',':\r
237                         if(cur_pkey_length == PATTERN_LENGTH)\r
238                         {\r
239                                 cur_pkey_length = 0;\r
240                                 num_pKeys++;\r
241                         }\r
242                         break;\r
243 \r
244                 case 'A':\r
245                 case 'a':\r
246                         pkey_array[num_pKeys] = \\r
247                         (pkey_array[num_pKeys] << 4)| 0xA;\r
248                         cur_pkey_length++;\r
249                         break;\r
250 \r
251                 case 'B':\r
252                 case 'b':\r
253                         pkey_array[num_pKeys] = \\r
254                         (pkey_array[num_pKeys] << 4)| 0xB;\r
255                         cur_pkey_length++;\r
256                         break;\r
257 \r
258                 case 'C':\r
259                 case 'c':\r
260                         pkey_array[num_pKeys] = \\r
261                         (pkey_array[num_pKeys] << 4)| 0xC;\r
262                         cur_pkey_length++;\r
263                         break;\r
264 \r
265                 case 'D':\r
266                 case 'd':\r
267                         pkey_array[num_pKeys] = \\r
268                         (pkey_array[num_pKeys] << 4)| 0xD;\r
269                         cur_pkey_length++;\r
270                         break;\r
271 \r
272                 case 'E':\r
273                 case 'e':\r
274                         pkey_array[num_pKeys] = \\r
275                         (pkey_array[num_pKeys] << 4)| 0xE;\r
276                         cur_pkey_length++;\r
277                         break;\r
278 \r
279                 case 'F':\r
280                 case 'f':\r
281                         pkey_array[num_pKeys] = \\r
282                         (pkey_array[num_pKeys] << 4)| 0xF;\r
283                         cur_pkey_length++;\r
284                         break;\r
285 \r
286                 case '1':\r
287                 case '2':\r
288                 case '3':\r
289                 case '4':\r
290                 case '5':\r
291                 case '6':\r
292                 case '7':\r
293                 case '8':\r
294                 case '9':\r
295                         pkey_array[num_pKeys] = \\r
296                         (pkey_array[num_pKeys] << 4)| (ansi_str.Buffer[i] - '0');\r
297                         cur_pkey_length++;\r
298                         break;\r
299                         \r
300                 case '\0':\r
301                         if(cur_pkey_length == PATTERN_LENGTH)\r
302                         {\r
303                                 cur_pkey_length = 0;\r
304                                 num_pKeys++;\r
305                         }\r
306                         else\r
307                         {\r
308                                 RtlFreeAnsiString(&ansi_str);\r
309                                 return num_pKeys;\r
310                         }\r
311                         break;\r
312 \r
313                 default:\r
314                         break;\r
315 \r
316                 }\r
317         }\r
318 \r
319     RtlFreeAnsiString(&ansi_str);\r
320         BUS_EXIT( BUS_DBG_DRV );\r
321         return num_pKeys;\r
322 }\r
323 static NTSTATUS\r
324 __read_registry(\r
325         IN                              UNICODE_STRING* const           p_registry_path )\r
326 {\r
327         NTSTATUS                                        status;\r
328         /* Remember the terminating entry in the table below. */\r
329         RTL_QUERY_REGISTRY_TABLE        table[10];\r
330         UNICODE_STRING                          param_path;\r
331         UNICODE_STRING                          pkeyString;\r
332         UNICODE_STRING                          empty_string;\r
333 \r
334         BUS_ENTER( BUS_DBG_DRV );\r
335 \r
336         __read_machine_name();\r
337 \r
338         RtlInitUnicodeString( &empty_string,NULL);\r
339         RtlInitUnicodeString( &param_path, NULL );\r
340         param_path.MaximumLength = p_registry_path->Length + \r
341                 sizeof(L"\\Parameters");\r
342         param_path.Buffer = cl_zalloc( param_path.MaximumLength );\r
343         if( !param_path.Buffer )\r
344         {\r
345                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
346                         ("Failed to allocate parameters path buffer.\n") );\r
347                 return STATUS_INSUFFICIENT_RESOURCES;\r
348         }\r
349 \r
350         RtlAppendUnicodeStringToString( &param_path, p_registry_path );\r
351         RtlAppendUnicodeToString( &param_path, L"\\Parameters" );\r
352         RtlInitUnicodeString( &pkeyString, NULL );\r
353     pkeyString.MaximumLength = 1024*sizeof(WCHAR);\r
354     pkeyString.Buffer = cl_zalloc( pkeyString.MaximumLength );\r
355     if( !pkeyString.Buffer )\r
356         {\r
357                 cl_free(param_path.Buffer);\r
358                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
359                       ("Failed to allocate parameters path pkeyString.\n") );\r
360         return STATUS_INSUFFICIENT_RESOURCES;\r
361     }\r
362 \r
363         cl_memclr(&g_pkeys,sizeof(pkey_array_t));\r
364 \r
365         /*\r
366          * Clear the table.  This clears all the query callback pointers,\r
367          * and sets up the terminating table entry.\r
368          */\r
369         cl_memclr( table, sizeof(table) );\r
370 \r
371         /* Setup the table entries. */\r
372         table[0].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
373         table[0].Name = L"ReportPortNIC";\r
374         table[0].EntryContext = &bus_globals.b_report_port_nic;\r
375         table[0].DefaultType = REG_DWORD;\r
376         table[0].DefaultData = &bus_globals.b_report_port_nic;\r
377         table[0].DefaultLength = sizeof(ULONG);\r
378 \r
379         table[1].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
380         table[1].Name = L"DebugFlags";\r
381         table[1].EntryContext = &bus_globals.dbg_lvl;\r
382         table[1].DefaultType = REG_DWORD;\r
383         table[1].DefaultData = &bus_globals.dbg_lvl;\r
384         table[1].DefaultLength = sizeof(ULONG);\r
385 \r
386         table[2].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
387         table[2].Name = L"IbalDebugLevel";\r
388         table[2].EntryContext = &g_al_dbg_level;\r
389         table[2].DefaultType = REG_DWORD;\r
390         table[2].DefaultData = &g_al_dbg_level;\r
391         table[2].DefaultLength = sizeof(ULONG);\r
392 \r
393         table[3].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
394         table[3].Name = L"IbalDebugFlags";\r
395         table[3].EntryContext = &g_al_dbg_flags;\r
396         table[3].DefaultType = REG_DWORD;\r
397         table[3].DefaultData = &g_al_dbg_flags;\r
398         table[3].DefaultLength = sizeof(ULONG);\r
399         \r
400 \r
401         table[4].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
402         table[4].Name = L"SmiPollInterval";\r
403         table[4].EntryContext = &g_smi_poll_interval;\r
404         table[4].DefaultType = REG_DWORD;\r
405         table[4].DefaultData = &g_smi_poll_interval;\r
406         table[4].DefaultLength = sizeof(ULONG);\r
407 \r
408         table[5].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
409         table[5].Name = L"IocQueryTimeout";\r
410         table[5].EntryContext = &g_ioc_query_timeout;\r
411         table[5].DefaultType = REG_DWORD;\r
412         table[5].DefaultData = &g_ioc_query_timeout;\r
413         table[5].DefaultLength = sizeof(ULONG);\r
414 \r
415         table[6].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
416         table[6].Name = L"IocQueryRetries";\r
417         table[6].EntryContext = &g_ioc_query_retries;\r
418         table[6].DefaultType = REG_DWORD;\r
419         table[6].DefaultData = &g_ioc_query_retries;\r
420         table[6].DefaultLength = sizeof(ULONG);\r
421 \r
422         table[7].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
423         table[7].Name = L"IocPollInterval";\r
424         table[7].EntryContext = &g_ioc_poll_interval;\r
425         table[7].DefaultType = REG_DWORD;\r
426         table[7].DefaultData = &g_ioc_poll_interval;\r
427         table[7].DefaultLength = sizeof(ULONG);\r
428 \r
429         table[8].Flags = RTL_QUERY_REGISTRY_DIRECT;\r
430         table[8].Name = L"PartitionKey";\r
431         table[8].EntryContext = &pkeyString;\r
432         table[8].DefaultType  = REG_SZ;\r
433         table[8].DefaultData  = &empty_string;\r
434         table[8].DefaultLength = 0;\r
435         /* Have at it! */\r
436         status = RtlQueryRegistryValues( RTL_REGISTRY_ABSOLUTE, \r
437                 param_path.Buffer, table, NULL, NULL );\r
438         if (NT_SUCCESS(status))\r
439                         g_pkeys.pkey_num = __prepare_pKey_array(&pkeyString, (uint16_t*)g_pkeys.pkey_array);\r
440 #if DBG\r
441         if( g_al_dbg_flags & AL_DBG_ERR )\r
442                 g_al_dbg_flags |= CL_DBG_ERROR;\r
443 #endif\r
444 \r
445         BUS_TRACE(BUS_DBG_DRV ,\r
446                         ("debug level %d debug flags 0x%.8x\n",\r
447                         g_al_dbg_level,\r
448                         g_al_dbg_flags));\r
449 \r
450         cl_free( pkeyString.Buffer );\r
451         cl_free( param_path.Buffer );\r
452         BUS_EXIT( BUS_DBG_DRV );\r
453         return status;\r
454 }\r
455 \r
456 \r
457 static NTSTATUS\r
458 bus_drv_open(\r
459         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
460         IN                              IRP                                                     *p_irp )\r
461 {\r
462         BUS_ENTER( BUS_DBG_DRV );\r
463 \r
464         UNUSED_PARAM( p_dev_obj );\r
465 \r
466         CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );\r
467 \r
468         /* We always succeed file handles creation. */\r
469         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
470         p_irp->IoStatus.Information = 0;\r
471         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
472 \r
473         BUS_EXIT( BUS_DBG_DRV );\r
474         return STATUS_SUCCESS;\r
475 }\r
476 \r
477 \r
478 static NTSTATUS\r
479 bus_drv_cleanup(\r
480         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
481         IN                              IRP                                                     *p_irp )\r
482 {\r
483         NTSTATUS                        status;\r
484 \r
485         BUS_ENTER( BUS_DBG_DRV );\r
486 \r
487         UNUSED_PARAM( p_dev_obj );\r
488 \r
489         CL_ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );\r
490 \r
491         /*\r
492          * Note that we don't acquire the remove and stop lock on close to allow\r
493          * applications to close the device when the locks are already held.\r
494          */\r
495         status = cl_to_ntstatus( al_dev_close( p_irp ) );\r
496 \r
497         /* Complete the IRP. */\r
498         p_irp->IoStatus.Status = status;\r
499         p_irp->IoStatus.Information = 0;\r
500         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
501 \r
502         BUS_EXIT( BUS_DBG_DRV );\r
503         return status;\r
504 }\r
505 \r
506 \r
507 static NTSTATUS\r
508 bus_drv_close(\r
509         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
510         IN                              IRP                                                     *p_irp )\r
511 {\r
512         UNUSED_PARAM( p_dev_obj );\r
513 \r
514         p_irp->IoStatus.Status = STATUS_SUCCESS;\r
515         p_irp->IoStatus.Information = 0;\r
516         IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
517 \r
518         return STATUS_SUCCESS;\r
519 }\r
520 \r
521 \r
522 static NTSTATUS\r
523 bus_drv_ioctl(\r
524         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
525         IN                              IRP                                                     *p_irp )\r
526 {\r
527         NTSTATUS                        status;\r
528         bus_fdo_ext_t           *p_ext;\r
529         PIO_STACK_LOCATION      p_io_stack;\r
530 \r
531         BUS_ENTER( BUS_DBG_DRV );\r
532 \r
533         /* Get the extension. */\r
534         p_ext = p_dev_obj->DeviceExtension;\r
535 \r
536         /* Get the stack location. */\r
537         p_io_stack = IoGetCurrentIrpStackLocation( p_irp );\r
538 \r
539         /* Acquire the stop lock. */\r
540         status = IoAcquireRemoveLock( &p_ext->cl_ext.stop_lock, p_irp );\r
541         if( !NT_SUCCESS( status ) )\r
542         {\r
543                 p_irp->IoStatus.Status = status;\r
544                 p_irp->IoStatus.Information = 0;\r
545                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
546                 BUS_EXIT( BUS_DBG_DRV );\r
547                 return status;\r
548         }\r
549 \r
550         /* Acquire the remove lock. */\r
551         status = IoAcquireRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
552         if( !NT_SUCCESS( status ) )\r
553         {\r
554                 IoReleaseRemoveLock( &p_ext->cl_ext.stop_lock, p_irp );\r
555                 p_irp->IoStatus.Status = status;\r
556                 p_irp->IoStatus.Information = 0;\r
557                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
558                 BUS_EXIT( BUS_DBG_DRV );\r
559                 return status;\r
560         }\r
561         \r
562         status = cl_to_ntstatus( al_dev_ioctl( p_irp ) );\r
563         \r
564         /* Only pass down if not handled and not PDO device. */\r
565         if( status == STATUS_INVALID_DEVICE_REQUEST && p_ext->cl_ext.p_next_do )\r
566         {\r
567                 IoSkipCurrentIrpStackLocation( p_irp );\r
568                 status = IoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
569         }\r
570 \r
571         /* Release the remove and stop locks. */\r
572         IoReleaseRemoveLock( &p_ext->cl_ext.remove_lock, p_irp );\r
573         IoReleaseRemoveLock( &p_ext->cl_ext.stop_lock, p_irp );\r
574 \r
575         BUS_EXIT( BUS_DBG_DRV );\r
576         return status;\r
577 }\r
578 \r
579 cl_status_t\r
580 bus_add_pkey(cl_ioctl_handle_t                  h_ioctl)\r
581 {\r
582         cl_status_t                             status;\r
583         pkey_array_t                            *pkeys;\r
584         PIO_STACK_LOCATION                      pIoStack;\r
585 \r
586         BUS_ENTER( BUS_DBG_DRV );\r
587 \r
588         pIoStack = IoGetCurrentIrpStackLocation(h_ioctl);\r
589         if ( (! h_ioctl->AssociatedIrp.SystemBuffer) || \r
590                  pIoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof (pkey_array_t))\r
591     {\r
592                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
593                         ("Invalid parameters.\n") );\r
594                 return CL_INVALID_PARAMETER;\r
595         }\r
596 \r
597         pkeys =  (pkey_array_t*)h_ioctl->AssociatedIrp.SystemBuffer;\r
598 \r
599         /* create additional pdo */\r
600         status = port_mgr_pkey_add(pkeys);\r
601         if (! NT_SUCCESS(status))\r
602         {\r
603                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
604                         ("port_mgr_pkey_add returned %08x.\n", status) );\r
605         }\r
606 \r
607         BUS_EXIT( BUS_DBG_DRV );\r
608         return status;\r
609 }\r
610 \r
611 static NTSTATUS\r
612 bus_drv_sysctl(\r
613         IN                              DEVICE_OBJECT                           *p_dev_obj,\r
614         IN                              IRP                                                     *p_irp )\r
615 {\r
616         NTSTATUS                status;\r
617         bus_fdo_ext_t   *p_ext;\r
618 \r
619         BUS_ENTER( BUS_DBG_DRV );\r
620 \r
621         CL_ASSERT( p_dev_obj );\r
622         CL_ASSERT( p_irp );\r
623 \r
624         p_ext = p_dev_obj->DeviceExtension;\r
625 \r
626         if( p_ext->cl_ext.p_next_do )\r
627         {\r
628                 IoSkipCurrentIrpStackLocation( p_irp );\r
629                 status = IoCallDriver( p_ext->cl_ext.p_next_do, p_irp );\r
630         }\r
631         else\r
632         {\r
633                 status = p_irp->IoStatus.Status;\r
634                 IoCompleteRequest( p_irp, IO_NO_INCREMENT );\r
635         }\r
636 \r
637         BUS_EXIT( BUS_DBG_DRV );\r
638         return status;\r
639 }\r
640 \r
641 \r
642 static void\r
643 bus_drv_unload(\r
644         IN                              DRIVER_OBJECT                           *p_driver_obj )\r
645 {\r
646         UNICODE_STRING           dos_name;\r
647         UNUSED_PARAM( p_driver_obj );\r
648 \r
649         BUS_ENTER( BUS_DBG_DRV );\r
650         \r
651         RtlInitUnicodeString( &dos_name, L"\\DosDevices\\Global\\ibal" );\r
652         IoDeleteSymbolicLink( &dos_name );\r
653 \r
654         CL_DEINIT;\r
655 \r
656 #if defined(EVENT_TRACING)\r
657         WPP_CLEANUP(p_driver_obj);\r
658 #endif\r
659 \r
660         BUS_EXIT( BUS_DBG_DRV );\r
661         \r
662 }\r
663 \r
664 \r
665 NTSTATUS\r
666 DriverEntry(\r
667         IN                              DRIVER_OBJECT                           *p_driver_obj,\r
668         IN                              UNICODE_STRING                          *p_registry_path )\r
669 {\r
670         NTSTATUS                        status;\r
671 \r
672         BUS_ENTER( BUS_DBG_DRV );\r
673 \r
674 #if defined(EVENT_TRACING)\r
675         WPP_INIT_TRACING(p_driver_obj ,p_registry_path);\r
676 #endif\r
677 \r
678         status = CL_INIT;\r
679         if( !NT_SUCCESS(status) )\r
680         {\r
681                 BUS_TRACE_EXIT( BUS_DBG_ERROR,\r
682                         ("cl_init returned %08X.\n", status) );\r
683                 return status;\r
684         }\r
685 \r
686         /* Store the driver object pointer in the global parameters. */\r
687         bus_globals.p_driver_obj = p_driver_obj;\r
688 \r
689         /* Get the registry values. */\r
690         status = __read_registry( p_registry_path );\r
691         if( !NT_SUCCESS(status) )\r
692         {\r
693                 CL_DEINIT;\r
694                 BUS_TRACE_EXIT( BUS_DBG_ERROR, \r
695                         ("__read_registry returned %08x.\n", status) );\r
696                 return status;\r
697         }\r
698 \r
699         /* Setup the entry points. */\r
700         p_driver_obj->MajorFunction[IRP_MJ_CREATE] = bus_drv_open;\r
701         p_driver_obj->MajorFunction[IRP_MJ_CLEANUP] = bus_drv_cleanup;\r
702         p_driver_obj->MajorFunction[IRP_MJ_CLOSE] = bus_drv_close;\r
703         p_driver_obj->MajorFunction[IRP_MJ_PNP] = cl_pnp;\r
704         p_driver_obj->MajorFunction[IRP_MJ_POWER] = cl_power;\r
705         p_driver_obj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = bus_drv_ioctl;\r
706         p_driver_obj->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = bus_drv_sysctl;\r
707         p_driver_obj->DriverUnload = bus_drv_unload;\r
708         p_driver_obj->DriverExtension->AddDevice = bus_add_device;\r
709 \r
710         BUS_EXIT( BUS_DBG_DRV );\r
711         return STATUS_SUCCESS;\r
712 }\r