One of the most important (and thus difficult to debug) problem on the kernel programming is the race condition. On linux kernel, usually it's solved via spin-locks or semaphores. In general, if the race condition may happen in the interrupt handler, it's handled as atomic, and you have to use spinlock for protecting the critical session. If it never happens in the interrupt and it may take relatively long time, you should use semaphore.
As already seen, some pcm callbacks are atomic and some are
not. For example, hw_params callback is
non-atomic, while trigger callback is
atomic. This means, the latter is called already in a spinlock
held by the PCM middle layer. Please take this atomicity into
account when you use a spinlock or a semaphore in the callbacks.
In the atomic callbacks, you cannot use functions which may call
schedule or go to
sleep. The semaphore and mutex do sleep,
and hence they cannot be used inside the atomic callbacks
(e.g. trigger callback).
For taking a certain delay in such a callback, please use
udelay() or mdelay().
All three atomic callbacks (trigger, pointer, and ack) are called with local interrupts disabled.