dxd - dynax driver framework 3.0.1d223
cross platform open source driver development framework
Loading...
Searching...
No Matches
Kick off

Basics

A driver is a composition of framework layers around the product's device description. The description is one table:

#include "version.h"
#include <dx_stream_desc.h>
namespace myproduct{
typedef dx::stream::desc<dx::usb::endpoint, 2, 1, 1, 1, 1, 1> desc; // the target type, then the capacities: streams, pins, clock settings, clocks, configurations, sources
constexpr desc models[]{
{.version= DX_VERSION32, .vendor{.name= "My Company"}, .model{.name= "My Product", .id= DX_USB_PID_MODEL}, .bus= dx::stream::bus::usb,
.clocks= 1, .clock{{.settings= 1, .setting{{.name= "Internal"}}, .defaults{.samplerate= 48000, .iosize{.hw_ticks= 5, .hw_min_ticks= 1, .hw_max_ticks= 32}}, .resolution= 1000}},
.streams= 2, .stream{
{.target{.address= 0x02, .interface= 1, .setting= 1}, .group= 1, .configurations= 1, .config{{.channels= 2, .wordlength= 3, .clock{.domain= 1, .sync{.reference= true}}}},
.pins= 1, .pin{{.name= "Out", .format{.audio= true, .resolution= 24, .size= 3}, .plug= dx::stream::plug::line, .channels= 2}}},
{.target{.address= 0x81, .interface= 1, .setting= 1}, .group= 1, .configurations= 1, .config{{.channels= 2, .wordlength= 3, .clock{.domain= 1, .sync{.reference= true}}}},
.pins= 1, .pin{{.name= "In", .format{.audio= true, .resolution= 24, .size= 3}, .plug= dx::stream::plug::line, .channels= 2}}}}},
{.version= DX_VERSION32, .vendor{.name= "My Company"}, .model{.name= "My Class Compliant Product", .id= DX_USB_PID_MODEL2}, .bus= dx::stream::bus::usb}, // no streams: configured from the class descriptors
};
}
#define DX_VERSION32
Definition dx_macros.h:77
@ usb
Definition dx_stream.h:430
@ line
Definition dx_stream.h:506
device streaming interface descriptor
Definition dx_stream.h:651

A model without streams is a class compliant USB audio device: dx::usb::audio::configure() builds its clocks, streams and pins from the configuration descriptor, in user mode and in the kernel alike.

The kernel driver (Windows)

A PortCls audio adapter over a USB device, every audio pin a WaveRT subdevice:

#include "version.h"
#include <dxd_usb_stream.h>
#include "drv.h"
extern "C" int _fltused= 0x9875;
namespace myproduct{
class device: public licensed, public dxd::portcls::device<dxd::usb::stream::device<dxd::adapter::device, myproduct::desc>>{
dxd::os_result boot() override {return dxd::ok;} // a firmware handshake ahead of the configuration, if the device needs one
dxd::os_result launch() override{
try(status= super::launch());
if(!check(desc.firmware.serial)) // no license: the adapter publishes no subdevice
return dxd::ok;
for(const auto& model: models)
if(model.model.id== idProduct){
if(model.streams)
desc= model; // the table describes the device
else{
desc.version= model.version; // the class descriptors did, the table names it
desc.vendor= model.vendor;
desc.model= model.model;
}
break;
}
ports= desc.enumerate();
catch:
return status;
}
public:
using super::super;
};
class adapter: public dxd::adapter{
device* create(::DEVICE_OBJECT* object, ::DEVICE_OBJECT* pdo, ::DEVICE_OBJECT* bus) override {return ::new myproduct::device{*this, object, pdo, bus};}
public:
adapter(::DRIVER_OBJECT* driver, ::UNICODE_STRING* registry, const wchar_t* name, const dxd::guid& guid): dxd::adapter{driver, registry, name, guid} {ports= myproduct::device::capacity;}
};
}
extern "C" ::NTSTATUS DriverEntry(::DRIVER_OBJECT* driver, ::UNICODE_STRING* registry){
return dxd::create<myproduct::adapter>(driver, registry, DX_LSTRINGIFY(DX_PRODUCT), dxd::guid(dxd::wdm::unicode<>(DX_LSTRINGIFY({DX_PRODUCT_GUID}))));
}
Definition wdk/dxd_platform.h:192
the adapter device's WaveRT endpoints over its streaming device's rings
Definition dxd_portcls_audio.h:1374
WDM unicode string helper.
Definition dxd_wdm.h:41
#define DX_LSTRINGIFY(x)
Definition dx_macros.h:36
promoted super
Definition dx_pipe.h:154
dx::stream::desc< target, 2, 2 > desc
Definition dx_coremidi_device.h:33
bus
Definition dx_stream.h:426
std::string name()
Definition macOS/dx_sync.h:231
dx::virtuel::driver< device<> > driver
Definition dx_virtual_stream_device.h:207
::IOReturn os_result
defining platform abstract type os_result for IOKit driver
Definition driverkit/dxd_platform.h:49
@ ok
Definition driverkit/dxd_platform.h:51
::NTSTATUS create(::DRIVER_OBJECT *wdm_driver, ::UNICODE_STRING *registry, const wchar_t *name=L"", dxd::guid guid=0)
Definition wdk/dxd_platform.h:278
char serial[0x40]
empty when the device has none
Definition dx_stream.h:669
uint32_t version
Definition dx_stream.h:652
struct dx::stream::desc::name_id model
uint32_t enumerate(const format &format=any) const
enumerate typified pins
Definition dx_stream.h:1031
struct dx::stream::desc::firmware firmware
struct dx::stream::desc::name_id vendor

Kernel code has no exceptions: a function returns dxd::os_result, try(status= ...) jumps to the function's catch: label on failure, dxd::log/warnlog/errorlog report. What the device holds on the stack below goes in conclude(), the destructor frees memory alone. The adapter's device interface (DX_PRODUCT_GUID) is what user mode's proxy device enumerates.

The user mode drivers

drv.h composes the devices from the framework's layers, each templated on the platform's preference store; a product's own base (its license, a doorman asking the daemon for a capture) comes first:

namespace myproduct{
namespace usb{ // the device from user mode: IOKit, WinUSB
template<typename preference_t= dx::preference> class device: public licensed, public dx::usb::stream::device<desc, preference_t>{
public:
using super::super;
};
namespace audio {template<typename preference_t= dx::preference> using pin= dx::stream::pin<device<preference_t>>;}
static const dx::proxy::driver<device<>>::match match{dx::guid{DX_STRINGIFY(DX_PRODUCT_GUID)}}; // the WinUSB inf's interface; IOKit: a matching dictionary
}
namespace proxy{ // the kernel driver through its control interface
template<typename preference_t= dx::preference> class device: public licensed, public dx::proxy::stream::device<desc, preference_t>{
typedef dx::proxy::stream::device<desc, preference_t> super;
public:
using super::super;
void launch() override {dx_pass(check(this->firmware.serial)? dx::ok: dx::not_permitted, "no license"); super::launch();}
};
static const dx::proxy::driver<device<>>::match match{dx::guid{DX_STRINGIFY(DX_PRODUCT_GUID)}};
}
}
one client's attachment to a stream: the pin desc it was made from, the channels it takes of that str...
Definition dx_stream_pin.h:49
the bus's device as a product composes it: the _device above with this bus's pipes and its own tickin...
Definition dx_usb_stream_device.h:294
#define dx_pass(test,...)
Definition dx_exception.h:55
#define DX_STRINGIFY(...)
Definition dx_macros.h:34
@ ok
Definition macOS/dx_platform.h:182
@ not_permitted
Definition macOS/dx_platform.h:200

The hosts wrap them:

The test app

dx::select takes one dx::test::driver per bus and parses the command line - --<bus> --help lists what a bus offers:

dx::aggregate{"CoreAudio", dx::aggregate{myproduct::coreaudio::match, DX_STRINGIFY(DX_PRODUCT_URID.CoreAudio), name}},
dx::aggregate{"proxy", dx::aggregate{myproduct::proxy::match, DX_STRINGIFY(DX_PRODUCT_URID), name}},
dx::aggregate{"USB", dx::aggregate{myproduct::usb::match, DX_STRINGIFY(DX_PRODUCT_URID.usb), name}},
}<< dx::parser::args(argv+ 1, argv+ argc);
std::deque< std::string > args
Definition dx_parser.h:60
select from aggregated drivers
Definition dx_parser.h:351
forwards a braced argument list into a type with no matching constructor - the conversion builds it f...
Definition dx_common.h:544

--<bus> --info lists the devices, --<bus> --0 --streaming-monitor [loopback|pattern-test|generator] <sec> runs a session on the first device, --<bus> --unit-test the driver and device life cycle, --log-level persists into the bus's preference store.


(c) copyright 2009 dynamic acoustics e.U. generated on

a closed source license may be obtained by requesting a written permission from dynamic acoustics e.U.
however - governmental use generally and military use especially is strictly prohibited though.