Mike, you beat me to the punch. The code looks good, but....
It can accommodate only constants as the pin argument.
If you are to use a constant, then the all-macro technique as demonstrated by abcminiuser (Dean Camers) on
www.avrfreaks will work with no penalty of added code at all. It simply uses interlocking macros to translate a symbolic name (e.g. 4) to the correct port and pin designation.
The harder one is to be able to have the pin selected at run-time. For this a lookup table is necessary instead of a bunch of defines. BUT, the general technique of combining pin and port into an integer will work, and knowing that port, ddr, and pin are usually in the same physical relationship in RAM (except PORTF) will also work.
I have nearly completed the coding for PutPin(unsigned char PinNum, unsigned char code).
I have the access to the port functions completed, and I just need to assemble it into a couple of functions.
I think it might be useful to have 2 PutPin-type functions. One which takes a constant pin arg, and is quite fast (around 3 asm statements to set the port, and more to do the logic for the code) and the one that takes a variable pin arg which takes about 37 asm statements to set the port.
One might be called PutPin() and the other PutPin_Const(). In C++ I guess it might be possible to have overloaded functions if the compiler can discriminate the variable value from a constant value. Not that we are using C++.....