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