I am writing a driver for a piece of hardware that can be communicated
with only through SMBus. My SMBus controller is already supported by
FreeBSD and I can do some testing from userland via ioctls of /dev/smb#.

I would like to learn how to do properly the following things in
kernel-land:

1. declare that my module/driver uses smbus, and make smbus and a driver
for my particular smb controller be loaded when my module is loaded
2. discover smbus of interest and slave address of interest provided
that I know how my hardware responds to particular commands
3. register/allocate smbus of interest and/or slave address of interest
("smbus resource") to my driver
3a. make sure that smbus will no go away (get unloaded) while my
module/driver is loaded and active
3b. make sure that there will be no issues with concurrent access of
"my" smbus, that is, that no activity on /dev/smb# or other activity on
"my" smbus interferes my driver's smbus usage
3c. likewise to the above, make sure that nothing tries to "own" "my"
slave address

I see that in Linux they have some framework for using smbus and its
resources from kernel-land:
http://www.charmed.com/txt/writing-clients.txt

I could not find anything similar in FreeBSD. I see that we use smbus in
kernel-land only in two places: device smb and bktr driver. Both seem to
be rather special, if I interpret things correctly. device smb seems to
be a glue between smbus and user-land, so it does not claim any specific
resources and translates commands from userland in one-shot fashion,
without any long term resource acquirement. bktr driver seems to be both
smb controller and smb client at once. So, probably, it is not worried
too much about concurrency and resource ownership issues.

This is what I have written so far for smbus/HW detection:
sc->smbus_dev = NULL;
smbus_class = devclass_find("smbus");
if (smbus_class == NULL)
        goto end;

for (i = 0; i < 128; i++) {
        int j, err;
        uint8_t val;

        smbus_dev = devclass_get_device(smbus_class, i);
        if (smbus_dev == NULL) /* past last unit ??? */
                break;
                
        for (j = 0; j < sizeof(identity)/sizeof(identity[0]); j++) {
                if ((err = smbus_readb(smbus_dev, SLAVE_ADDR,
                        identity[j].reg, &val)) != 0)
                        break;
                if (val != identity[j].val)
                        break;
        }

        if (j == sizeof(identity)/sizeof(identity[0])) {
                /* all checks passed */
                sc->smbus_dev = smbus_dev;
                break;
        }
}

Basically, outer loop tries to loop over all smbus devices/units I could
imagine (0-127), inner loop checks identity registers/commands against
expected values. Currently I check only one slave address, but I plan to
add an intermediate loop that will loop over all possible 127 slave
addresses.


-- 
Andriy Gapon
_______________________________________________
freebsd-hackers@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to