Resources and ACPI

Craig Boston craig at tobuj.gank.org
Wed Apr 11 15:37:08 UTC 2007


Ok, well just for the record it's been a while since I've worked with
busdma so my knowledge is more of a high level overview.  Hopefully if
I get anything wrong someone will step in and correct me. :)

On Thu, Apr 12, 2007 at 12:37:07AM +1000, Alan Garfield wrote:
> I've got a very machine specific device (eg. it's built into the PRS
> controller on the motherboard) so I don't think I have to worry about
> machine independence.

Machine independence is just a side benefit of using busdma, really it's
the standard "FreeBSD driver API" way of doing things.

> At the moment I've got the io ports and irq's being hardcoded into the
> driver, which seems icky to me. The acpi bus when the device is attached
> outputs all the appropriate resources so _something_ knows what they
> are. All I want is a way to access them and to know what they are.

The question is, do you really need to know what they are?  The way it's
supposed to work is you do something like this.

int rid;

rid = i;
/* Allocate the i-th IO port resource */
sc->io[i] = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
/* Get a tag for use with bus_space */
sc->iot[i] = rman_get_bustag(sc->io[i]);
/* Get a handle describing the resource */
sc->ioh[i] = rman_get_bushandle(sc->io[i]);

bus_alloc_resource_any tells the OS to use the "default" resource
allocation, which for a device that's enumerated through ACPI will be
the values that you're seeing through acpi.  The rman_get_* functions
retrieve the tag and handle associated with the resource for use with
the bus_space_* functions.  AFAIK these are valid until you call
bus_release_resource on sc->io[i], at which point they should be
discarded.

Then to read or write to registers within your IO range, you would do
something like this:

bus_space_write_1(sc->iot[0], sc->ioh[0], offset, value);
/* Write a single byte to (your first IO port) + offset */
value = bus_space_read_2(sc->iot[1], sc->ioh[1], offset);
/* Read a word from (your second IO port) + offset */

When you use bus_space_*, you don't need to know the exact starting
address of your ports like you would with outb().  You only need to know
the offset within the range that your device uses, the API automatically
takes care of the rest.

Many drivers wrap bus_space_read_* and write_* in a set of macros that
automatically fill in the tag and handler, for convenience.

If you really want to know the address, for example to print out for
debugging messages:

start = rman_get_start(sc->io[i]);
size = rman_get_size(sc->io[i]);

The "io 0x??? - 0x??? irq X" messages that are printed when the device
attaches are normally handled by your parent bus, so you normally don't
even need to worry about what the actual port base is.

For an IRQ you typically call bus_setup_intr() with your resource
pointer and handler function.  If you need to know the IRQ number for
some reason, rman_get_start() should work on that as well.

There are lots of examples of using the busdma API in the kernel tree
(virtually every driver).

Hope this helps,
Craig


More information about the freebsd-hackers mailing list