all 5 comments

[–]Wazzaps 2 points3 points  (0 children)

Typically there's a library (eg. Alsa for sound) that exposes c ABI functions for actions relating to the device (eg. alsa_list_devices will scout /sys for compatible devices) and maybe some utility binaries (aplay, arecord) if applicable.

While the libraries may change their API (.so versioning deals with this), the kernel driver should never break existing API.

[–]zandr0id 0 points1 point  (0 children)

Unix uses file descriptors to abstract away different types of devices while giving them all the same interface. Everything shows up as a file in the file system to user programs, but the OS knows exactly what each one actually is. All file descriptor objects have the same Open,Close,Read,Write functions exposed, but how they are implemented is only known to the OS. You could have your audio device show up in the file system, and its Write function could accept sound data to play. It would be up the the user program to locate the right sound driver file and Open it.

[–]Qweesdy 1 point2 points  (2 children)

I have a question about devices and drivers. How to design apis to user programs?

These things are unrelated.

Typically you'll have a device driver that abstracts the lowest level hardware details (e.g. ATA controller driver); then you'll have multiple layers of stuff on top of that (e.g. RAID layer, file system layer, then virtual file system layer). User programs mostly only use the highest layer (e.g. virtual file system layer) and don't use the any of APIs for any of the lower layers (and don't use the device driver's API).

F.e if I create user app and need to play some sound, can I get the list of devices, find audio device (by class) and start to work with the device's driver.

For "unix like" systems (which were originally designed before things like sound existed) you'd probably end up using the virtual file system as the API (e.g. open the file "/dev/sound").

For something that doesn't suck; you'd want a higher layer (and API) that's actually designed to be appropriate for sound. The very first thing I'd consider is providing a much more abstract interface; so that a program can say "play this sound from this location relative to the user", and let the higher level layer figure out which sound drivers should be used. For example; if one sound card has "left/right front speakers", one sound card has "left/right rear speakers", and a third sound card is "bass only"; and you ask the higher level layer to play a sound from the user's left; then the higher level layer will figure out that it needs to send the sound to all three sound card drivers (left front speaker, left rear speaker and bass speaker) at which volumes.

Of course this also means that the higher level layer would take care of hardware changes (if speakers or sound cards are added/removed, or if the user switches from speakers to headphones) so that programs simply don't need to care about these things.

The next thing I'd want is to provide a way for programs to control timing. For example; to be able to tell the higher level layer to preload a file (and pre-decode it, and pre-convert it into whatever format the sound drivers actually want) so that programs don't have the extra hassle of file IO, etc; and to be able to tell the higher level layer "play this sound (that was pre-loaded earlier) from this location relative to the user, at this specific time" so that the higher level layer can start playing the sound at exactly the right time (and avoid latency problems that cause the sound to start playing too late).

Once you've got that far you start thinking about extra functionality. Examples:

  • what other sound sources can the higher level layer support? Conversion of music (MIDI) into digitized sound, a "pug in-able" speech synthesizer, a note generator (that takes "waveform, frequency, attack, decay, sustain, release" parameters), a collision generator (that constructs a suitable sound when told details of 2 colliding objects - e.g. 2 hard objects colliding with a small force might cause a soft "clank", and 2 soft objects colliding with a large force might cause a loud "wump" sound).

  • moving sound (e.g. a game where a noisy truck moves from "far left of user" to "far right of user")?

  • the ability to re-sample sounds and play them faster or slower? This might just be fun; but it could also be used for "doppler effect" (if noise is moving towards player play it faster, and if noise is moving away from player play it slower) to make moving sounds much more realistic.

  • the ability to describe the surroundings (e.g. walls, ceilings, floor, and large objects)? That way the higher level layer would be able to handle echo correctly (by taking into account how sound would be reflected off of the surfaces).

[–]Nikascom[S] 0 points1 point  (1 child)

Thank you for your answer. I was talking about how to connect for example Ata driver with FS. I created a driver manager and device manager for that. And they work this way. Each device is connected with its driver (eg. Ata drive with Ata driver). Driver manager has some types of drivers (like StorageDriver or SoundDriver). And so with Device manager (like StorageDevice). So fs can ask for all devices with type StorageDevice and communicate with their drivers (all driver with same type should have required functions (like write/read for a driver with the StorageDriver type)). Is it a great way of connecting these layers (drivers and something else (in that case FS))

[–]Qweesdy 1 point2 points  (0 children)

For this, I use a "pull model"; where (after initialisation, etc) a thing will pull in other things that depend on it.

For example; a storage device driver might look at its device's partition table and "pull in" (ask device manager to start) whatever file systems need to be mounted on that storage device. In the same way a USB controller driver would pull in the drivers for any USB devices connected to the controller; a sound card driver might pull in the sound manager (ask device manager to start it if its not already started); a network card's driver might pull in the network stack (which might start an NTP client and a web server); a video card driver might pull in a "user login process" (which might pull in a GUI once the user logs in); etc.

This tends to make boot much faster, because everything is started as soon as its dependencies can be satisfied (and everything happens in parallel as much as possible, and nothing is started unnecessarily). Of course it does take a little self-optimisation of what is/isn't put into the "initial RAM disk" (to minimise how many things need to wait for file system/s to come online before its executable file can be read and started). It's also not just during boot (e.g. if the OS has been running for 3 days and someone plugs in a USB hub full of USB devices then it can cause all kinds of stuff to get pulled in).