| # do not edit this file, it will be overwritten on update |
| |
| SUBSYSTEM!="sound", GOTO="sound_end" |
| |
| ACTION=="add|change", KERNEL=="controlC*", ATTR{../uevent}="change" |
| ACTION!="change", GOTO="sound_end" |
| |
| # Ok, we probably need a little explanation here for what the two lines above |
| # are good for. |
| # |
| # The story goes like this: when ALSA registers a new sound card it emits a |
| # series of 'add' events to userspace, for the main card device and for all the |
| # child device nodes that belong to it. udev relays those to applications, |
| # however only maintains the order between father and child, but not between |
| # the siblings. The control device node creation can be used as synchronization |
| # point. All other devices that belong to a card are created in the kernel |
| # before it. However unfortunately due to the fact that siblings are forwarded |
| # out of order by udev this fact is lost to applications. |
| # |
| # OTOH before an application can open a device it needs to make sure that all |
| # its device nodes are completely created and set up. |
| # |
| # As a workaround for this issue we have added the udev rule above which will |
| # generate a 'change' event on the main card device from the 'add' event of the |
| # card's control device. Due to the ordering semantics of udev this event will |
| # only be relayed after all child devices have finished processing properly. |
| # When an application needs to listen for appearing devices it can hence look |
| # for 'change' events only, and ignore the actual 'add' events. |
| # |
| # When the application is initialized at the same time as a device is plugged |
| # in it may need to figure out if the 'change' event has already been triggered |
| # or not for a card. To find that out we store the flag environment variable |
| # SOUND_INITIALIZED on the device which simply tells us if the card 'change' |
| # event has already been processed. |
| |
| KERNEL!="card*", GOTO="sound_end" |
| |
| ENV{SOUND_INITIALIZED}="1" |
| |
| IMPORT{builtin}="hwdb" |
| SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id" |
| SUBSYSTEMS=="usb", GOTO="skip_pci" |
| |
| SUBSYSTEMS=="firewire", ATTRS{guid}=="?*", \ |
| ENV{ID_BUS}="firewire", ENV{ID_SERIAL}="$attr{guid}", ENV{ID_SERIAL_SHORT}="$attr{guid}", \ |
| ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{model}", \ |
| ENV{ID_VENDOR}="$attr{vendor_name}", ENV{ID_MODEL}="$attr{model_name}" |
| SUBSYSTEMS=="firewire", GOTO="skip_pci" |
| |
| SUBSYSTEMS=="pci", ENV{ID_BUS}="pci", ENV{ID_VENDOR_ID}="$attr{vendor}", ENV{ID_MODEL_ID}="$attr{device}" |
| LABEL="skip_pci" |
| |
| # Define ID_ID if ID_BUS and ID_SERIAL are set. This will work for both |
| # USB and firewire. |
| ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="?*", ENV{ID_ID}="$env{ID_BUS}-$env{ID_SERIAL}-$env{ID_USB_INTERFACE_NUM}" |
| ENV{ID_SERIAL}=="?*", ENV{ID_USB_INTERFACE_NUM}=="", ENV{ID_ID}="$env{ID_BUS}-$env{ID_SERIAL}" |
| |
| IMPORT{builtin}="path_id" |
| |
| # The values used here for $SOUND_FORM_FACTOR and $SOUND_CLASS should be kept |
| # in sync with those defined for PulseAudio's src/pulse/proplist.h |
| # PA_PROP_DEVICE_FORM_FACTOR, PA_PROP_DEVICE_CLASS properties. |
| |
| # If the first PCM device of this card has the pcm class 'modem', then the card is a modem |
| ATTR{pcmC%nD0p/pcm_class}=="modem", ENV{SOUND_CLASS}="modem", GOTO="sound_end" |
| |
| # Identify cards on the internal PCI bus as internal |
| SUBSYSTEMS=="pci", DEVPATH=="*/0000:00:??.?/sound/*", ENV{SOUND_FORM_FACTOR}="internal", GOTO="sound_end" |
| |
| # Devices that also support Image/Video interfaces are most likely webcams |
| SUBSYSTEMS=="usb", ENV{ID_USB_INTERFACES}=="*:0e????:*", ENV{SOUND_FORM_FACTOR}="webcam", GOTO="sound_end" |
| |
| # Matching on the model strings is a bit ugly, I admit |
| ENV{ID_MODEL}=="*[Ss]peaker*", ENV{SOUND_FORM_FACTOR}="speaker", GOTO="sound_end" |
| ENV{ID_MODEL_FROM_DATABASE}=="*[Ss]peaker*", ENV{SOUND_FORM_FACTOR}="speaker", GOTO="sound_end" |
| |
| ENV{ID_MODEL}=="*[Hh]eadphone*", ENV{SOUND_FORM_FACTOR}="headphone", GOTO="sound_end" |
| ENV{ID_MODEL_FROM_DATABASE}=="*[Hh]eadphone*", ENV{SOUND_FORM_FACTOR}="headphone", GOTO="sound_end" |
| |
| ENV{ID_MODEL}=="*[Hh]eadset*", ENV{SOUND_FORM_FACTOR}="headset", GOTO="sound_end" |
| ENV{ID_MODEL_FROM_DATABASE}=="*[Hh]eadset*", ENV{SOUND_FORM_FACTOR}="headset", GOTO="sound_end" |
| |
| ENV{ID_MODEL}=="*[Hh]andset*", ENV{SOUND_FORM_FACTOR}="handset", GOTO="sound_end" |
| ENV{ID_MODEL_FROM_DATABASE}=="*[Hh]andset*", ENV{SOUND_FORM_FACTOR}="handset", GOTO="sound_end" |
| |
| ENV{ID_MODEL}=="*[Mm]icrophone*", ENV{SOUND_FORM_FACTOR}="microphone", GOTO="sound_end" |
| ENV{ID_MODEL_FROM_DATABASE}=="*[Mm]icrophone*", ENV{SOUND_FORM_FACTOR}="microphone", GOTO="sound_end" |
| |
| LABEL="sound_end" |