Subject: Re: cn_tab and consdev redirection from serial terminal to Graphics Card (69030)
To: None <tech-kern@netbsd.org>
From: Toru Nishimura <locore32@gaea.ocn.ne.jp>
List: tech-kern
Date: 11/14/2003 18:16:33
Ok, here is the HOWTO (which is the haunted 5 capitalized letters
most people in this forum want to avoid, I guess) of wscons driver.

In essence there are only entry points visible from outside.

CFATTACH_DECL(foofb, sizeof(struct foofb_softc),
    foofbmatch, foofbattach, NULL, NULL);

and,

    foofbcnattach(babababa)

The former is a structure used to be written in;

const struct cfattach foofb_ca = {
        sizeof(struct foofb_softc), foofbmatch, foofbattach,
};

The structure encapsulates this whole driver in a single entity and
is used for configure() device enumeration as well as other device
drivers.  foofbmatch() is called to determine the hardware circuit.
If the hardware is detected, then foofbattach() is called to run whole
device driver initialization.  It's the plain simple NetBSD way.

Now let's say this is the display driver which is capable of showing
booting message on screen.   The issue is, the display initialization
must be done =before= configure() gets started.   foofbcnattach()
is responsible for this.  foofbcnattach() does hardware initialization and
WSCONS binding.  This job is somehow parallel to what foofbattach()
does but differs in substantial aspect; no malloc available for foofbcnattach().

There would be a conventional function to make hardware initialization,
say, foo_hw_init().   This knows the register layout of the target graphics
hardware and does appropriate things enough to show characters on screen.
Then foo_hw_init() is called in two ways;

foofbcnattach(...)
{
    foo_hw_init(...);
    ... (explained later) ...
    wsdisplay_cnattach(babababa, ...);
    wskbd_cnattach(blahblablah ,...);
    foo_is_console = 1;
}

foofbattach(...)
{
    if (foo_is_console) {
        ...
    }
    else {
        foo_hw_init(...);
        MALLOC(rasops_info);
        ... (explained later) ...
    }
    printf(": ...\n");
    ...
}
        
Now what is rasops_info?  WSCONS defines one important
structure.  It plays the central role to encapsulate all the information
to make raster operations for screen.  It contains screen geometry
and a handful number of pointers to character drawing functions.

foofbcnattach() is responsible to fulfill the rasops_info structure.
Note that because malloc is not available for it, the rasops_info
must be static data;

static struct rasops_info foofb_console_ri;

Now, let's we invent foo_common_init() to fulfill the "ri" structure.
Then, the previous two functions would be like;

foofbcnattach()
{
    foo_hw_init(...);
    foo_common_init(&foofb_console_ri);
    (*ri->ri_ops.alloc_attr)(&ri, 0, 0, 0, &defattr);
    wsdisplay_cnattach(&sfb_stdscreen, ri, 0, 0, defattr);
    wskbd_cnattach(blahblahblah, ...);
    foo_is_console = 1;
}

foofbattach(...)
{
    if (foo_is_console) {
        ... bind &foofb_console_ri to "foofb_softc" local storage ...
    }
    else {
        ri = MALLOC(rasops_info);
        foo_common_init(ri);
        ... bind the ri to foofb_softc ...
    }
    ...
    waa.console = foo_is_console;
    waa.scrdata = &foofb_screenlist;
    waa.accessops = &foofb_accessops;
    waa.accesscookie = sc;
    config_found(self, &waa, wsemuldisplaydevprint);
}

I think the whole story is pretty clean and simple.  (Indeed, console
determining logic should be more complicated for completeness, but
it's out of cope in this story)

Toru Nishimura/ALKYL Technology