3. But what about fixed resources that the module uses like a fixed external interrupt pin like INT0 or INT1 how do I ensure that no one else uses that resource.
4. Then comes interrupts again this would have its own interrupt handler where should the interrupt related code go?
You can only go so far to utilize or protect resources that are fundamentally un-sharable.
the most practical way forward is to just not worry about it because the complexity and compromises of making something portable outweigh the benefit you gets
Yeah. That. You really don't want to implement a timer hw allocation mechanism that loops through all the timers available on the chip looking for one that isn't assigned to some other function yet, and figuring out how to use that timer with your "modular code" (keeping in mind that a given chip usually contains several different types of timers.
The interrupts are actually a pretty good mechanism for defending resources. Put your ISRs (usually with fixed names) in your C code, and if anyone else uses the same ISR, you'll get error messages at link time.
I'd have ps2k.c, ps2k-private.h, ps2k-api.h, psk2-config.h - stuff that you expect to be easily changeable (pin numbers) goes in the last one, and the others shouldn't have to change.
"Not going overboard on portability" isn't the same as ignoring portability entirely, of course. It'd be better to base your code on a timer callback service rather than a hardware timer, and better to use an interrupt mechanism that allows other pins in the same port to still get interrupts that are directed to other code (on an AVR, there are some pins that generate individually vectored interrupts, and some that only generate interrupts has part of a "pin change" interrupt shared with all the other bits on that port. It would be reasonable to at least consider both.)
People have mentioned testability. Testing all cases of a generalized library is "hard." 2nd best is to DOCUMENT those cases you've tested and found working, those you've tested and found NOT working, and those you haven't tested but expect to fall in one side or the other.
Spend a lot of time thinking about the API to the higher-level code. Chances are that being able to move the ps/2 keyboard to use a different type of interrupts may be less important (portability-wise) than being able to replace the ps/2 keyboard with a USB keyboard, so ... do you really want to use key codes that are specific to PS/2, or do you want something more generic (any codes permitted) or more specific (unified codes for the common keys)?
5. Then comes other peripherals like timers, uart, if this module needs to use those resources where would those be defined and how would those be used?
A library should touch as few "other peripherals" as possible. There's not excuse for a PS/2 keyboard library to do anything with a UART.
You CAN use "abstracted" features controlled by the config file. Fiddling with UART registers would be awful, but using "debug_print(xxx)" is fine...