[driver,device] Remove driver__default_dispatch 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 /* Forward declarations. */
39 static device__free_func device__free_dev_;
40 static device__create_pdo_func device__make_pdo_;
41
42 /**
43  * Create a new device.
44  *
45  * @ret dev             The address of a new device, or NULL for failure.
46  *
47  * This function should not be confused with a PDO creation routine, which is
48  * actually implemented for each device type.  This routine will allocate a
49  * device__type, track it in a global list, as well as populate the device
50  * with default values.
51  */
52 winvblock__lib_func struct device__type * device__create(void) {
53     struct device__type * dev;
54
55     /*
56      * Devices might be used for booting and should
57      * not be allocated from a paged memory pool.
58      */
59     dev = wv_mallocz(sizeof *dev);
60     if (dev == NULL)
61       return NULL;
62     /* Populate non-zero device defaults. */
63     dev->DriverObject = driver__obj_ptr;
64     dev->ops.create_pdo = device__make_pdo_;
65     dev->ops.free = device__free_dev_;
66
67     return dev;
68   }
69
70 /**
71  * Create a device PDO.
72  *
73  * @v dev               Points to the device that needs a PDO.
74  */
75 winvblock__lib_func PDEVICE_OBJECT STDCALL device__create_pdo(
76     IN struct device__type * dev
77   ) {
78     return dev->ops.create_pdo(dev);
79   }
80
81 /**
82  * Default PDO creation operation.
83  *
84  * @v dev               Points to the device that needs a PDO.
85  * @ret NULL            Reports failure, no matter what.
86  *
87  * This function does nothing, since it doesn't make sense to create a PDO
88  * for an unknown type of device.
89  */
90 static PDEVICE_OBJECT STDCALL device__make_pdo_(IN struct device__type * dev) {
91     DBG("No specific PDO creation operation for this device!\n");
92     return NULL;
93   }
94
95 /**
96  * Respond to a device PnP ID query.
97  *
98  * @v dev                       The device being queried for PnP IDs.
99  * @v query_type                The query type.
100  * @v buf                       Wide character, 512-element buffer for the
101  *                              ID response.
102  * @ret winvblock__uint32       The number of wide characters in the response,
103  *                              or 0 upon a failure.
104  */
105 winvblock__uint32 STDCALL device__pnp_id(
106     IN struct device__type * dev,
107     IN BUS_QUERY_ID_TYPE query_type,
108     IN OUT WCHAR (*buf)[512]
109   ) {
110     return dev->ops.pnp_id ? dev->ops.pnp_id(dev, query_type, buf) : 0;
111   }
112
113 /* An IRP handler for a PnP ID query. */
114 NTSTATUS STDCALL device__pnp_query_id(
115     IN PDEVICE_OBJECT DeviceObject,
116     IN PIRP Irp,
117     IN PIO_STACK_LOCATION Stack,
118     IN struct device__type * dev,
119     OUT winvblock__bool_ptr completion
120   ) {
121     NTSTATUS status;
122     WCHAR (*str)[512];
123     winvblock__uint32 str_len;
124
125     /* Allocate the working buffer. */
126     str = wv_mallocz(sizeof *str);
127     if (str == NULL) {
128         DBG("wv_malloc IRP_MN_QUERY_ID\n");
129         status = STATUS_INSUFFICIENT_RESOURCES;
130         goto alloc_str;
131       }
132     /* Invoke the specific device's ID query. */
133     str_len = device__pnp_id(
134         dev,
135         Stack->Parameters.QueryId.IdType,
136         str
137       );
138     if (str_len == 0) {
139         Irp->IoStatus.Information = 0;
140         status = STATUS_NOT_SUPPORTED;
141         goto alloc_info;
142       }
143     /* Allocate the return buffer. */
144     Irp->IoStatus.Information = (ULONG_PTR) wv_palloc(str_len * sizeof **str);
145     if (Irp->IoStatus.Information == 0) {
146         DBG("wv_palloc failed.\n");
147         status = STATUS_INSUFFICIENT_RESOURCES;
148         goto alloc_info;
149       }
150     /* Copy the working buffer to the return buffer. */
151     RtlCopyMemory(
152         (void *) Irp->IoStatus.Information,
153         str,
154         str_len * sizeof **str
155       );
156     status = STATUS_SUCCESS;
157
158     /* Irp->IoStatus.Information not freed. */
159     alloc_info:
160
161     wv_free(str);
162     alloc_str:
163
164     Irp->IoStatus.Status = status;
165     IoCompleteRequest(Irp, IO_NO_INCREMENT);
166     *completion = TRUE;
167     return status;
168   }
169
170 /**
171  * Close a device.
172  *
173  * @v dev               Points to the device to close.
174  */
175 winvblock__lib_func void STDCALL device__close(
176     IN struct device__type * dev
177   ) {
178     /* Call the device's close routine. */
179     dev->ops.close(dev);
180     return;
181   }
182
183 /**
184  * Delete a device.
185  *
186  * @v dev               Points to the device to delete.
187  */
188 winvblock__lib_func void STDCALL device__free(IN struct device__type * dev) {
189     /* Call the device's free routine. */
190     dev->ops.free(dev);
191   }
192
193 /**
194  * Default device deletion operation.
195  *
196  * @v dev               Points to the device to delete.
197  */
198 static void STDCALL device__free_dev_(IN struct device__type * 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 winvblock__lib_func struct device__type * device__get(PDEVICE_OBJECT dev_obj) {
209     driver__dev_ext_ptr 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 winvblock__lib_func void device__set(
224     PDEVICE_OBJECT dev_obj,
225     struct device__type * dev
226   ) {
227     driver__dev_ext_ptr dev_ext = dev_obj->DeviceExtension;
228     dev_ext->device = dev;
229     return;
230   }