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