1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel Streaming 4 * FILE: drivers/wdm/audio/backpln/portcls/api.cpp 5 * PURPOSE: Port Class driver / DriverEntry and IRP handlers 6 * PROGRAMMER: Andrew Greenwood 7 * Johannes Anderwald 8 * HISTORY: 9 * 27 Jan 07 Created 10 */ 11 12 #include "private.hpp" 13 14 #ifndef YDEBUG 15 #define NDEBUG 16 #endif 17 18 #include <debug.h> 19 20 // 21 // This is called from DriverEntry so that PortCls can take care of some 22 // IRPs and map some others to the main KS driver. In most cases this will 23 // be the first function called by an audio driver. 24 // 25 // First 2 parameters are from DriverEntry. 26 // 27 // The AddDevice parameter is a driver-supplied pointer to a function which 28 // typically then calls PcAddAdapterDevice (see below.) 29 // 30 NTSTATUS 31 NTAPI 32 PcInitializeAdapterDriver( 33 IN PDRIVER_OBJECT DriverObject, 34 IN PUNICODE_STRING RegistryPathName, 35 IN PDRIVER_ADD_DEVICE AddDevice) 36 { 37 DPRINT("PcInitializeAdapterDriver\n"); 38 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 39 40 // Our IRP handlers 41 DPRINT("Setting IRP handlers\n"); 42 DriverObject->MajorFunction[IRP_MJ_CREATE] = PcDispatchIrp; 43 DriverObject->MajorFunction[IRP_MJ_PNP] = PcDispatchIrp; 44 DriverObject->MajorFunction[IRP_MJ_POWER] = PcDispatchIrp; 45 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = PcDispatchIrp; 46 DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = PcDispatchIrp; 47 48 // The driver-supplied AddDevice 49 DriverObject->DriverExtension->AddDevice = AddDevice; 50 51 // KS handles these 52 DPRINT("Setting KS function handlers\n"); 53 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CLOSE); 54 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_DEVICE_CONTROL); 55 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_FLUSH_BUFFERS); 56 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_QUERY_SECURITY); 57 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_READ); 58 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_SET_SECURITY); 59 KsSetMajorFunctionHandler(DriverObject, IRP_MJ_WRITE); 60 61 DPRINT("PortCls has finished initializing the adapter driver\n"); 62 63 return STATUS_SUCCESS; 64 } 65 66 // 67 // Typically called by a driver's AddDevice function, which is set when 68 // calling PcInitializeAdapterDriver. This performs some common driver 69 // operations, such as creating a device extension. 70 // 71 // The StartDevice parameter is a driver-supplied function which gets 72 // called in response to IRP_MJ_PNP / IRP_MN_START_DEVICE. 73 // 74 NTSTATUS 75 NTAPI 76 PcAddAdapterDevice( 77 IN PDRIVER_OBJECT DriverObject, 78 IN PDEVICE_OBJECT PhysicalDeviceObject, 79 IN PCPFNSTARTDEVICE StartDevice, 80 IN ULONG MaxObjects, 81 IN ULONG DeviceExtensionSize) 82 { 83 NTSTATUS status = STATUS_UNSUCCESSFUL; 84 PDEVICE_OBJECT fdo; 85 PDEVICE_OBJECT PrevDeviceObject; 86 PPCLASS_DEVICE_EXTENSION portcls_ext = NULL; 87 88 DPRINT("PcAddAdapterDevice called\n"); 89 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 90 91 if (!DriverObject || !PhysicalDeviceObject || !StartDevice) 92 { 93 return STATUS_INVALID_PARAMETER; 94 } 95 96 // check if the DeviceExtensionSize is provided 97 if ( DeviceExtensionSize < PORT_CLASS_DEVICE_EXTENSION_SIZE ) 98 { 99 // driver does not need a device extension 100 if ( DeviceExtensionSize != 0 ) 101 { 102 // DeviceExtensionSize must be zero 103 return STATUS_INVALID_PARAMETER; 104 } 105 // set size to our extension size 106 DeviceExtensionSize = PORT_CLASS_DEVICE_EXTENSION_SIZE; 107 } 108 109 // create the device 110 status = IoCreateDevice(DriverObject, 111 DeviceExtensionSize, 112 NULL, 113 FILE_DEVICE_KS, 114 FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, 115 FALSE, 116 &fdo); 117 118 if (!NT_SUCCESS(status)) 119 { 120 DPRINT("IoCreateDevice() failed with status 0x%08lx\n", status); 121 return status; 122 } 123 124 // Obtain the new device extension 125 portcls_ext = (PPCLASS_DEVICE_EXTENSION) fdo->DeviceExtension; 126 // initialize the device extension 127 RtlZeroMemory(portcls_ext, DeviceExtensionSize); 128 // allocate create item 129 portcls_ext->CreateItems = (PKSOBJECT_CREATE_ITEM)AllocateItem(NonPagedPool, MaxObjects * sizeof(KSOBJECT_CREATE_ITEM), TAG_PORTCLASS); 130 131 if (!portcls_ext->CreateItems) 132 { 133 // not enough resources 134 status = STATUS_INSUFFICIENT_RESOURCES; 135 goto cleanup; 136 } 137 138 // store max subdevice count 139 portcls_ext->MaxSubDevices = MaxObjects; 140 // store the physical device object 141 portcls_ext->PhysicalDeviceObject = PhysicalDeviceObject; 142 // set up the start device function 143 portcls_ext->StartDevice = StartDevice; 144 // initialize timer lock 145 KeInitializeSpinLock(&portcls_ext->TimerListLock); 146 // initialize timer list 147 InitializeListHead(&portcls_ext->TimerList); 148 // initialize io timer 149 IoInitializeTimer(fdo, PcIoTimerRoutine, NULL); 150 // start the io timer 151 IoStartTimer(fdo); 152 153 // set io flags 154 fdo->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE; 155 // clear initializing flag 156 fdo->Flags &= ~ DO_DEVICE_INITIALIZING; 157 158 // allocate the device header 159 status = KsAllocateDeviceHeader(&portcls_ext->KsDeviceHeader, MaxObjects, portcls_ext->CreateItems); 160 // did we succeed 161 if (!NT_SUCCESS(status)) 162 { 163 goto cleanup; 164 } 165 166 // attach device to device stack 167 PrevDeviceObject = IoAttachDeviceToDeviceStack(fdo, PhysicalDeviceObject); 168 // did we succeed 169 if (PrevDeviceObject) 170 { 171 // store the device object in the device header 172 //KsSetDevicePnpBaseObject(portcls_ext->KsDeviceHeader, fdo, PrevDeviceObject); 173 portcls_ext->PrevDeviceObject = PrevDeviceObject; 174 } 175 else 176 { 177 // return error code 178 status = STATUS_UNSUCCESSFUL; 179 goto cleanup; 180 } 181 182 // register shutdown notification 183 IoRegisterShutdownNotification(PhysicalDeviceObject); 184 185 return status; 186 187 cleanup: 188 189 if (portcls_ext->KsDeviceHeader) 190 { 191 // free the device header 192 KsFreeDeviceHeader(portcls_ext->KsDeviceHeader); 193 } 194 195 if (portcls_ext->CreateItems) 196 { 197 // free previously allocated create items 198 FreeItem(portcls_ext->CreateItems, TAG_PORTCLASS); 199 } 200 201 // delete created fdo 202 IoDeleteDevice(fdo); 203 204 205 return status; 206 } 207 208 NTSTATUS 209 NTAPI 210 PcRegisterSubdevice( 211 IN PDEVICE_OBJECT DeviceObject, 212 IN PWCHAR Name, 213 IN PUNKNOWN Unknown) 214 { 215 PPCLASS_DEVICE_EXTENSION DeviceExt; 216 NTSTATUS Status; 217 ISubdevice *SubDevice; 218 UNICODE_STRING SymbolicLinkName; 219 PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor; 220 ULONG Index; 221 UNICODE_STRING RefName; 222 PSYMBOLICLINK_ENTRY SymEntry; 223 224 DPRINT("PcRegisterSubdevice DeviceObject %p Name %S Unknown %p\n", DeviceObject, Name, Unknown); 225 226 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 227 228 // check if all parameters are valid 229 if (!DeviceObject || !Name || !Unknown) 230 { 231 DPRINT("PcRegisterSubdevice invalid parameter\n"); 232 return STATUS_INVALID_PARAMETER; 233 } 234 235 // get device extension 236 DeviceExt = (PPCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension; 237 238 if (!DeviceExt) 239 { 240 // should not happen 241 DbgBreakPoint(); 242 return STATUS_UNSUCCESSFUL; 243 } 244 245 // look up our undocumented interface 246 Status = Unknown->QueryInterface(IID_ISubdevice, (LPVOID*)&SubDevice); 247 if (!NT_SUCCESS(Status)) 248 { 249 DPRINT("No ISubdevice interface\n"); 250 // the provided port driver doesnt support ISubdevice 251 return STATUS_INVALID_PARAMETER; 252 } 253 254 // get the subdevice descriptor 255 Status = SubDevice->GetDescriptor(&SubDeviceDescriptor); 256 if (!NT_SUCCESS(Status)) 257 { 258 DPRINT("Failed to get subdevice descriptor %x\n", Status); 259 SubDevice->Release(); 260 return STATUS_UNSUCCESSFUL; 261 } 262 263 // add an create item to the device header 264 Status = KsAddObjectCreateItemToDeviceHeader(DeviceExt->KsDeviceHeader, PcCreateItemDispatch, (PVOID)SubDevice, Name, NULL); 265 if (!NT_SUCCESS(Status)) 266 { 267 // failed to attach 268 SubDevice->Release(); 269 DPRINT("KsAddObjectCreateItemToDeviceHeader failed with %x\n", Status); 270 return Status; 271 } 272 273 // initialize reference string 274 RtlInitUnicodeString(&RefName, Name); 275 RtlInitUnicodeString(&SubDeviceDescriptor->RefString, Name); 276 277 for(Index = 0; Index < SubDeviceDescriptor->InterfaceCount; Index++) 278 { 279 // FIXME 280 // check if reference string with that name already exists 281 282 Status = IoRegisterDeviceInterface(DeviceExt->PhysicalDeviceObject, 283 &SubDeviceDescriptor->Interfaces[Index], 284 &RefName, 285 &SymbolicLinkName); 286 287 if (NT_SUCCESS(Status)) 288 { 289 // activate device interface 290 IoSetDeviceInterfaceState(&SymbolicLinkName, TRUE); 291 // allocate symbolic link entry 292 SymEntry = (PSYMBOLICLINK_ENTRY)AllocateItem(NonPagedPool, sizeof(SYMBOLICLINK_ENTRY), TAG_PORTCLASS); 293 if (SymEntry) 294 { 295 // initialize symbolic link item 296 RtlInitUnicodeString(&SymEntry->SymbolicLink, SymbolicLinkName.Buffer); 297 // store item 298 InsertTailList(&SubDeviceDescriptor->SymbolicLinkList, &SymEntry->Entry); 299 } 300 else 301 { 302 // allocating failed 303 RtlFreeUnicodeString(&SymbolicLinkName); 304 } 305 } 306 } 307 308 // release SubDevice reference 309 SubDevice->Release(); 310 311 return STATUS_SUCCESS; 312 } 313