[device] Introduce device__set function
[people/sha0/winvblock.git] / src / winvblock / device.c
1 /**
2  * Copyright (C) 2009-2010, Shao Miller <shao.miller@yrdsb.edu.on.ca>.
3  * Copyright 2006-2008, V.
4  * For WinAoE contact information, see http://winaoe.org/
5  *
6  * This file is part of WinVBlock, derived from WinAoE.
7  *
8  * WinVBlock is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * WinVBlock is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with WinVBlock.  If not, see <http://www.gnu.org/licenses/>.
20  */
21
22 /**
23  * @file
24  *
25  * Device specifics.
26  */
27
28 #include <ntddk.h>
29
30 #include "winvblock.h"
31 #include "wv_stdlib.h"
32 #include "portable.h"
33 #include "irp.h"
34 #include "driver.h"
35 #include "device.h"
36 #include "debug.h"
37
38 static LIST_ENTRY dev_list;
39 static KSPIN_LOCK dev_list_lock;
40 /* Forward declarations */
41 static device__free_func free_dev;
42 static device__create_pdo_decl (
43   make_dev_pdo
44  );
45
46 /**
47  * Initialize the global, device-common environment
48  *
49  * @ret ntstatus        STATUS_SUCCESS or the NTSTATUS for a failure
50  */
51 STDCALL NTSTATUS
52 device__init (
53   void
54  )
55 {
56   /*
57    * Initialize the global list of devices
58    */
59   InitializeListHead ( &dev_list );
60   KeInitializeSpinLock ( &dev_list_lock );
61
62   return STATUS_SUCCESS;
63 }
64
65 /**
66  * Create a new device
67  *
68  * @ret dev_ptr         The address of a new device, or NULL for failure
69  *
70  * See the header file for additional details
71  */
72 winvblock__lib_func device__type_ptr
73 device__create (
74   void
75  )
76 {
77   device__type_ptr dev_ptr;
78
79   /*
80    * Devices might be used for booting and should
81    * not be allocated from a paged memory pool
82    */
83   dev_ptr = wv_mallocz(sizeof *dev_ptr);
84   if ( dev_ptr == NULL )
85     return NULL;
86   /*
87    * Track the new device in our global list
88    */
89   ExInterlockedInsertTailList ( &dev_list, &dev_ptr->tracking,
90                                 &dev_list_lock );
91   /*
92    * Populate non-zero device defaults
93    */
94   dev_ptr->dispatch = driver__default_dispatch;
95   dev_ptr->DriverObject = driver__obj_ptr;
96   dev_ptr->ops.create_pdo = make_dev_pdo;
97   dev_ptr->ops.free = free_dev;
98
99   return dev_ptr;
100 }
101
102 /**
103  * Create a device PDO
104  *
105  * @v dev_ptr           Points to the device that needs a PDO
106  */
107 winvblock__lib_func
108 device__create_pdo_decl (
109   device__create_pdo
110  )
111 {
112   return dev_ptr->ops.create_pdo ( dev_ptr );
113 }
114
115 /**
116  * Default PDO creation operation
117  *
118  * @v dev_ptr           Points to the device that needs a PDO
119  *
120  * This function does nothing, since it doesn't make sense to create a PDO
121  * for an unknown type of device.
122  */
123 static
124 device__create_pdo_decl (
125   make_dev_pdo
126  )
127 {
128   DBG ( "No specific PDO creation operation for this device!\n" );
129   return NULL;
130 }
131
132 /**
133  * Close a device
134  *
135  * @v dev_ptr           Points to the device to close
136  */
137 winvblock__lib_func
138 device__close_decl (
139   device__close
140  )
141 {
142   /*
143    * Call the device's close routine
144    */
145   dev_ptr->ops.close ( dev_ptr );
146 }
147
148 /**
149  * Delete a device.
150  *
151  * @v dev_ptr           Points to the device to delete.
152  */
153 winvblock__lib_func void STDCALL device__free(IN device__type_ptr dev_ptr)
154   {
155     /* Call the device's free routine. */
156     dev_ptr->ops.free(dev_ptr);
157   }
158
159 /**
160  * Default device deletion operation.
161  *
162  * @v dev_ptr           Points to the device to delete.
163  */
164 static void STDCALL free_dev(IN device__type_ptr dev_ptr)
165   {
166     /*
167      * Track the device deletion in our global list.  Unfortunately,
168      * for now we have faith that a device won't be deleted twice and
169      * result in a race condition.  Something to keep in mind...
170      */
171     ExInterlockedRemoveHeadList(dev_ptr->tracking.Blink, &dev_list_lock);
172   
173     wv_free(dev_ptr);
174   }
175
176 /**
177  * Get a device from a DEVICE_OBJECT.
178  *
179  * @v dev_obj           Points to the DEVICE_OBJECT to get the device from.
180  * @ret                 Returns a pointer to the device on success, else NULL.
181  */
182 winvblock__lib_func device__type_ptr device__get(PDEVICE_OBJECT dev_obj)
183   {
184     driver__dev_ext_ptr dev_ext = dev_obj->DeviceExtension;
185     return dev_ext->device;
186   }
187
188 /**
189  * Set the device for a DEVICE_OBJECT.
190  *
191  * @v dev_obj           Points to the DEVICE_OBJECT to set the device for.
192  * @v dev               Points to the device to associate with.
193  */
194 winvblock__lib_func device__type_ptr device__set(
195     PDEVICE_OBJECT dev_obj,
196     device__type_ptr dev
197   )
198   {
199     driver__dev_ext_ptr dev_ext = dev_obj->DeviceExtension;
200     dev_ext->device = dev;
201     return;
202   }