[driver] Rename driver__obj_ptr to WvDriverObj
[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 "driver.h"
34 #include "device.h"
35 #include "debug.h"
36
37 /* Forward declarations. */
38 static WV_F_DEV_FREE WvDevFreeDev_;
39 static WV_F_DEV_CREATE_PDO WvDevMakePdo_;
40
41 /**
42  * Initialize device defaults.
43  *
44  * @v dev               Points to the device to initialize with defaults.
45  */
46 winvblock__lib_func void WvDevInit(WV_SP_DEV_T dev) {
47     RtlZeroMemory(dev, sizeof *dev);
48     /* Populate non-zero device defaults. */
49     dev->DriverObject = WvDriverObj;
50     dev->Ops.CreatePdo = WvDevMakePdo_;
51     dev->Ops.Free = WvDevFreeDev_;
52   }
53
54 /**
55  * Create a new device.
56  *
57  * @ret dev             The address of a new device, or NULL for failure.
58  *
59  * This function should not be confused with a PDO creation routine, which is
60  * actually implemented for each device type.  This routine will allocate a
61  * WV_DEV_T and populate the device with default values.
62  */
63 winvblock__lib_func WV_SP_DEV_T WvDevCreate(void) {
64     WV_SP_DEV_T dev;
65
66     /*
67      * Devices might be used for booting and should
68      * not be allocated from a paged memory pool.
69      */
70     dev = wv_malloc(sizeof *dev);
71     if (dev == NULL)
72       return NULL;
73
74     WvDevInit(dev);
75     return dev;
76   }
77
78 /**
79  * Create a device PDO.
80  *
81  * @v dev               Points to the device that needs a PDO.
82  */
83 winvblock__lib_func PDEVICE_OBJECT STDCALL WvDevCreatePdo(IN WV_SP_DEV_T dev) {
84     return dev->Ops.CreatePdo(dev);
85   }
86
87 /**
88  * Default PDO creation operation.
89  *
90  * @v dev               Points to the device that needs a PDO.
91  * @ret NULL            Reports failure, no matter what.
92  *
93  * This function does nothing, since it doesn't make sense to create a PDO
94  * for an unknown type of device.
95  */
96 static PDEVICE_OBJECT STDCALL WvDevMakePdo_(IN WV_SP_DEV_T dev) {
97     DBG("No specific PDO creation operation for this device!\n");
98     return NULL;
99   }
100
101 /**
102  * Respond to a device PnP ID query.
103  *
104  * @v dev                       The device being queried for PnP IDs.
105  * @v query_type                The query type.
106  * @v buf                       Wide character, 512-element buffer for the
107  *                              ID response.
108  * @ret winvblock__uint32       The number of wide characters in the response,
109  *                              or 0 upon a failure.
110  */
111 winvblock__uint32 STDCALL WvDevPnpId(
112     IN WV_SP_DEV_T dev,
113     IN BUS_QUERY_ID_TYPE query_type,
114     IN OUT WCHAR (*buf)[512]
115   ) {
116     return dev->Ops.PnpId ? dev->Ops.PnpId(dev, query_type, buf) : 0;
117   }
118
119 /* An IRP handler for a PnP ID query. */
120 NTSTATUS STDCALL WvDevPnpQueryId(IN WV_SP_DEV_T dev, IN PIRP irp) {
121     NTSTATUS status;
122     WCHAR (*str)[512];
123     winvblock__uint32 str_len;
124     PIO_STACK_LOCATION io_stack_loc = IoGetCurrentIrpStackLocation(irp);
125
126     /* Allocate the working buffer. */
127     str = wv_mallocz(sizeof *str);
128     if (str == NULL) {
129         DBG("wv_malloc IRP_MN_QUERY_ID\n");
130         status = STATUS_INSUFFICIENT_RESOURCES;
131         goto alloc_str;
132       }
133     /* Invoke the specific device's ID query. */
134     str_len = WvDevPnpId(
135         dev,
136         io_stack_loc->Parameters.QueryId.IdType,
137         str
138       );
139     if (str_len == 0) {
140         irp->IoStatus.Information = 0;
141         status = STATUS_NOT_SUPPORTED;
142         goto alloc_info;
143       }
144     /* Allocate the return buffer. */
145     irp->IoStatus.Information = (ULONG_PTR) wv_palloc(str_len * sizeof **str);
146     if (irp->IoStatus.Information == 0) {
147         DBG("wv_palloc failed.\n");
148         status = STATUS_INSUFFICIENT_RESOURCES;
149         goto alloc_info;
150       }
151     /* Copy the working buffer to the return buffer. */
152     RtlCopyMemory(
153         (void *) irp->IoStatus.Information,
154         str,
155         str_len * sizeof **str
156       );
157     status = STATUS_SUCCESS;
158
159     /* irp->IoStatus.Information not freed. */
160     alloc_info:
161
162     wv_free(str);
163     alloc_str:
164
165     return driver__complete_irp(irp, irp->IoStatus.Information, status);
166   }
167
168 /**
169  * Close a device.
170  *
171  * @v dev               Points to the device to close.
172  */
173 winvblock__lib_func void STDCALL WvDevClose(IN WV_SP_DEV_T dev) {
174     /* Call the device's close routine. */
175     dev->Ops.Close(dev);
176     return;
177   }
178
179 /**
180  * Delete a device.
181  *
182  * @v dev               Points to the device to delete.
183  */
184 winvblock__lib_func void STDCALL WvDevFree(IN WV_SP_DEV_T dev) {
185     /* Call the device's free routine. */
186     dev->Ops.Free(dev);
187   }
188
189 /**
190  * Default device deletion operation.
191  *
192  * @v dev               Points to the device to delete.
193  */
194 static void STDCALL WvDevFreeDev_(IN WV_SP_DEV_T dev) {
195     wv_free(dev);
196   }
197
198 /**
199  * Get a device from a DEVICE_OBJECT.
200  *
201  * @v dev_obj           Points to the DEVICE_OBJECT to get the device from.
202  * @ret                 Returns a pointer to the device on success, else NULL.
203  */
204 winvblock__lib_func WV_SP_DEV_T WvDevFromDevObj(PDEVICE_OBJECT dev_obj) {
205     driver__dev_ext_ptr dev_ext;
206
207     if (!dev_obj)
208       return NULL;
209     dev_ext = dev_obj->DeviceExtension;
210     return dev_ext->device;
211   }
212
213 /**
214  * Set the device for a DEVICE_OBJECT.
215  *
216  * @v dev_obj           Points to the DEVICE_OBJECT to set the device for.
217  * @v dev               Points to the device to associate with.
218  */
219 winvblock__lib_func void WvDevForDevObj(PDEVICE_OBJECT dev_obj, WV_SP_DEV_T dev) {
220     driver__dev_ext_ptr dev_ext = dev_obj->DeviceExtension;
221     dev_ext->device = dev;
222     return;
223   }