This is commonly asked by new and experienced driver writers alike:  "which locking primitive should I use in my driver?"  Well, if the answer were simple, I think the question would not come up as much as it does ;).  I can certainly give parts of the answer, but I can't give the answer that the question deserves.  Rather, you should go read the great document on Locking, Deadlocks, and Synchronization on WHDC.

I can give a small piece of generic advice though.  Unlike user mode where the performance and process scope of the lock are the main guidelines for which lock you use, in kernel mode you must also take into account the IRQL which is going to need the synchronization.  For instance, if you need to synchronize against code running at DISPATCH_LEVEL (a timer, a DPC, a completion routine, etc.) then a lock which synchronizes only at PASSIVE_LEVEL is of no use to you and you need to use a KSPIN_LOCK or other DISPATCH_LEVEL level locks.