examples of work for newconfig Project

Last updateed: $Date: 1999/08/11 14:57:29 $
Here are examples of what we need.

Modefications of PCI drivers

In newconfig version of FreeBSD, we need rewrite probe routine and attach routine of PCI drivers, which arguments must be match what newconfig requires. Here, I explain how to rewrite with the case of example rewriting of sys/pci/cy_pci.c .

example of rewriting

explanation


Include sys/device.h which is needed in newconfig mode.
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#ifdef NEW_CONFIG
+#include <sys/device.h>
+#endif
 #include <vm/vm.h>
 #include <vm/pmap.h>

The probe function and the attach function should be renamed. We rewrite foo_probe to foo_pci_match , and foo_attach to foo_pci_attach . However, in case of a driver which is only for PCI specific device and which has no share code with another bus based driver such as ISA, we can omit a bus specific part of name such as _pci because there are no ambiguities.
+#ifndef NEW_CONFIG
 static char *cy_probe		__P((pcici_t, pcidi_t));
 static void cy_attach		__P((pcici_t, int));
+#else
+static int cy_pci_match __P((struct device *, struct cfdata *, void *));
+static void cy_pci_attach __P((struct device *, struct device *, void *));
+#endif

An object of struct cfattach should be defined. It works almost like struct pci_device, but former struct is common to any bus type. cy_pci_softc will be described later.
+#ifdef NEW_CONFIG
+struct cy_pci_softc {
+	struct  device cy_pci_dev;
+};
+
+struct cfattach cy_pci_ca = {
+	sizeof(struct cy_pci_softc), 1, NULL, cy_pci_match, cy_pci_attach,
+};
+#else
A definition of struct pci_device and a macro DATA_SET which store the definition to the system are removed by #ifdef because it is no more required. cy_pci part of a name of the object of struct cfattach should be a "frontend name" which is specified in "files" file for config.new to read in. "frontend name" will be described later. In addition to it, names of softc structure, match function and attach function might be composed from frontend name to keep up a custom.
Arguments of the probe (match) function should be changed. In newconfig, all match functions and attach functions have same argument types even if it is for different bus. Bus dependent data is passed via void *aux , and it casts to bus dependent structrue (in case of PCI, it is struct pci_attach_args ).
-static char *
-cy_probe(config_id, device_id)
-	pcici_t config_id;
-	pcidi_t device_id;
+static int
+cy_match (struct device *parent, struct cfdata *match, void *aux)
 {
+	struct pci_attach_args *pa = aux;
+	pcici_t config_id = pa->pa_tag;
+	pcidi_t device_id = pa->pa_type;

As same as before, a return value of probe (match) function should be rewritten. If one supports a device specified by void *aux then 1 is returned; otherwise 0 is returned
-		return ("Cyclades Cyclom-Y Serial Adapter");
-	return NULL;
+		return (1);
+	return (0);

Arguments of the attach function should be changed. As same as the match function, bug dependent data is passed via void *aux , and it casts to bus dependent structrue (in case of PCI, it is struct pci_attach_args ).
static void
-cy_attach(config_id, unit)
-	pcici_t config_id;
-	int unit;
+cy_attach (struct device *parent, struct device *self, void *aux)
 {
+	struct pci_attach_args *pa = aux;
+	pcici_t config_id = pa->pa_tag;
+	int unit = self->dv_unit;

In newconfig, desplaying of the device information should be performed in the attach function.
+	printf (": Cyclades Cyclom-Y Serial Adapter\n")
 	ioport = (u_int32_t) pci_conf_read(config_id, CY_PCI_BASE_ADDR1) & ~0x3;

Modefications of ISA drivers

Here, I explain how to rewrite with the case of example rewriting of sys/i386/isa/psm.c .

example of rewriting

explanation


As same as PCI example, sys/device.h is should be included.
 #include <sys/select.h>
 #include <sys/uio.h>
+#ifdef NEW_CONFIG
+#include <sys/device.h>
+#endif

A object of struct cfattach should be defined. It is also like the PCI example, but slightly differs. To keep minimum change from old ISA code, we provide two configuration ways. One is a "newconfig" mode. In "newconfig" mode, match function and attach function are defined as same as PCI device case. Onother is a "ISA compatible" mode. In "ISA compatible" mode, old probe function and attach function are just used without any change. In case of change of psm.c , we use "ISA compatible" mode.
+#ifdef NEW_CONFIG
+struct psm_softc_new {
+	struct  device psm_dev;
+};
+
+struct cfattach psm_ca = {
+	sizeof(struct psm_softc_new), 0, &psmdriver, isa_dev_match, NULL,
+};
+#endif
In "ISA compatible" mode, a pointer to struct isa_driver is assigned to ca_aux member of struct cfattach . 0 is also assigned to ca_level member of it. isa_dev_match , which is common match function to all "ISA compatible" mode, is assigned to match function member. NULL is assigned to attach function member because it is not used.

newconfig mode

ISA compatible mode is makeshift; all ISA driver is expected to rewrite in newconfig mode. Here, I explain how to rewrite from "ISA compatible mode" to "newconfig mode" with the case of sys/i386/isa/psm.c .

Note that along with this rewriting, softc structure also needed to rewrite to use the one reserved by newconfig. So, most of the parts that access softc structure need rewriting. These rewriting are ommited here. Please see "softc structure" section for details.

example of rewriting

explanation

Include ioconf.h which is needed in newconfig mode.
+#ifdef NEW_CONFIG
+#include "ioconf.h"
+#endif /* NEW_CONFIG */

Following the instruction in "softc structure" section, rewrite definition of softc structure and add struct device member in the begining of definition. In ISA comapatible mode psm.c , pointers of softc structures are prepared statically as an array of length NPSM , which is not suitable for newconfig mode. Please see "softc structure" section for details.
 
 /* driver control block */
-static struct psm_softc {    /* Driver status information */
+struct psm_softc {    /* Driver status information */
+#ifdef NEW_CONFIG
+    struct device psm_dev;	/* device generic information */
+#endif
	:
-} *psm_softc[NPSM];
+};
+#ifndef NEW_CONFIG
+static struct psm_softc *psm_softc[NPSM];
+#endif

Delete psmprobe() and psmattach() which are not needed in newconfig mode.
 /* function prototypes */
+#ifndef NEW_CONFIG
 static int psmprobe __P((struct isa_device *));
 static int psmattach __P((struct isa_device *));
+#endif

Delete isa_driver which is not needed in newconfig mode.
 
+#ifndef NEW_CONFIG
 /* device driver declarateion */
 struct isa_driver psmdriver = { psmprobe, psmattach, "psm", FALSE };
+#endif

Delete softc structure for "ISA compatible mode" which is not needed in newconfig mode. Rewrite objects of cfattach structure as following:
	cf_level	 In ISA compatible mode 0, in newconfig mode 1
	ca_aux		 In newconfig mode NULL
	ca_match	 Match function in newconfig mode
	ca_attach	 Attach function in newconfig mode
	ca_detach	 Normally NULL
	ca_activate	 Normally NULL
 #ifdef NEW_CONFIG
-struct psm_softc_new {
-	struct  device psm_dev;
-};
+static int psm_match	__P((struct device *, struct cfdata *, void *));
+static void psm_attach	__P((struct device *, struct device *, void *));
+static int psm_init	__P((struct psm_softc *, int, int));
 
 struct cfattach psm_ca = {
-	sizeof(struct psm_softc_new), 0, &psmdriver, isa_dev_match, NULL, NULL,
+	sizeof(struct psm_softc), 1, NULL, psm_match, psm_attach, NULL,NULL,
 };
 #endif

endprobe() is a macro for psm_init() (previous psmprobe() ). Here is the rewriting accompanying with rewriting from psmprobe() to psm_init().
 
 /* psm driver entry points */
 
+#ifdef NEW_CONFIG
+
+#define endprobe(v)	{   if (bootverbose) 				\
+				--verbose;   				\
+                            kbdc_set_device_mask(sc->kbdc, mask);	\
+			    kbdc_lock(sc->kbdc, FALSE);			\
+			    return (v);	     				\
+			}
+#else
+
 #define endprobe(v)	{   if (bootverbose) 				\
 				--verbose;   				\
                             kbdc_set_device_mask(sc->kbdc, mask);	\
@@ -728,17 +761,28 @@
  	                    free(sc, M_DEVBUF);                         \
 			    return (v);	     				\
 			}
+#endif

Rewrite psmprobe() and psmattach() make psm_match() and psm_attach(). Note, previous psmprobe() not only probe the device, but also initializes the device and softc structure, which psmattach() depends on. This not suitable for newconfig style as in the section "precautions". So rewite psmprobe() as initializing function psm_init(). Then call psm_init() from psm_match() and psm_attach() to initialize the device and the softc structure.

The softc structure is allocated by newconfig, so delete and rewrite lines for malloc(). Accompanying with the deletion of static array of softc structure, delete lines that check of validation with NPSM constant.

 
+#ifdef NEW_CONFIG
+static int
+psm_init(struct psm_softc *sc, int iobase, int flags)
+#else
 static int
 psmprobe(struct isa_device *dvp)
+#endif
 {
+#ifdef NEW_CONFIG
+    int unit = sc->psm_dev.dv_unit;		/* XXX */
+#else
     int unit = dvp->id_unit;
     struct psm_softc *sc;
+#endif
     int stat[3];
     int command_byte;
     int mask;
     int i;
 
+#ifndef NEW_CONFIG
     /* validate unit number */
     if (unit >= NPSM)
         return (0);
@@ -749,13 +793,20 @@
     if (sc == NULL)
         return (0);
     bzero(sc, sizeof *sc);
+#endif
 
 #if 0
     kbdc_debug(TRUE);
 #endif
+#ifdef NEW_CONFIG
+    sc->addr = iobase;
+    sc->kbdc = kbdc_open(sc->addr);
+    sc->config = flags & PSM_CONFIG_FLAGS;
+#else
     sc->addr = dvp->id_iobase;
     sc->kbdc = kbdc_open(sc->addr);
     sc->config = dvp->id_flags & PSM_CONFIG_FLAGS;
+#endif
     sc->flags = 0;
     if (bootverbose)
         ++verbose;
@@ -764,7 +815,9 @@
         printf("psm%d: unable to lock the controller.\n", unit);
         if (bootverbose)
             --verbose;
+#ifndef NEW_CONFIG
         free(sc, M_DEVBUF);
+#endif
 	return (0);
     }
 
@@ -978,20 +1031,56 @@
     }
 
     /* done */
+#ifdef NEW_CONFIG
+    kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
+    kbdc_lock(sc->kbdc, FALSE);
+    return (1);
+#else
     psm_softc[unit] = sc;
     kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS);
     kbdc_lock(sc->kbdc, FALSE);
     return (IO_PSMSIZE);
+#endif
+}

Write psm_match() function that calls psm_init().

The softc structure is not transfered to match function, which leads to the match function cannot access softc structure. That needs some work arounds.

sc_sensitive field in isa_softc structure of the parent controls the order of ISA probe. For the sensitive hardware devices,

    if (!isa_sc->sc_sensitive)
	return (0);
Otherwise,
    if (isa_sc->sc_sensitive)
	return (0);
+#ifdef NEW_CONFIG
+static int
+psm_match(struct device *parent, struct cfdata *cf, void *aux)
+{
+    struct psm_softc dummy;
+    struct isa_softc *isa_sc = (struct isa_softc *)parent;
+    struct isa_attach_args *ia = (struct isa_attach_args *)aux;
+    int v;
+
+    if (isa_sc->sc_sensitive)
+	return (0);		/* psm is not sensitive device */
+    bzero(&dummy, sizeof dummy);
+    ia->ia_compat.id_alive = IO_PSMSIZE;
+
+    v = psm_init(&dummy, ia->ia_iobase, ia->ia_flags);
+    return (v);
 }


Rewrite psmattach() as psm_attach().

In newconfig mode, the intterupt is registrated in attach() function. The registration is done calling isa_register_intr() function. isa_register_intr() is written in sys/i386/isa/isa.c .

Arguments of isa_register_intr() are as follows:

	int	irq;
		Interrupt number (Note: this is not bit vector).

	int	*mp;
		Pointer to interupt mask. Following the imask {tty,
		bio, net, cam} of the device line in old config file, 
		write one of pointers:

			tty_imask
			bio_imask
			net_imask
			cam_imask

		If there is no imask in the device line write NULL.

	u_int	flags;
		If there is `FAST' interrupt flag, write RI_FAST.
		This corresponds to the id_ri_flags field of old
		struct isa_device, which is mostly used RS-232C
		drivers(ex. sio). Otherwise, write `0'.

	inthand2_t	handler;
		Pointer to the interrupt handler function (psm_intr()).

	void*	arg;
		Argument that intterrupt handler is called. Write the
		pointer to the softc structure.
+static void
+psm_attach(struct device *parent, struct device *self, void *aux)
+#else
 static int
 psmattach(struct isa_device *dvp)
+#endif
 {
+#ifdef NEW_CONFIG
+    struct psm_softc *sc = (struct psm_softc *)self;
+    struct isa_attach_args *ia = (struct isa_attach_args *)aux;
+
+    psm_init(sc, ia->ia_iobase, ia->ia_flags);
+    isa_register_intr(ia->ia_irq, &tty_imask, 0, psm_intr, (void *)sc); 
+#else
     int unit = dvp->id_unit;
     struct psm_softc *sc = psm_softc[unit];
 
     if (sc == NULL)    /* shouldn't happen */
 	return (0);
+#endif
 
     /* Setup initial state */
     sc->state = PSM_VALID;
@@ -1007,7 +1096,7 @@
 #endif /* DEVFS */
 
 #ifdef NEW_CONFIG
-	printf(": ");
+    printf(": ");
 #endif /* NEW_CONFIG */
 
 #ifdef PSM_HOOKAPM
@@ -1053,7 +1142,9 @@
     if (bootverbose)
         --verbose;
 
+#ifndef NEW_CONFIG
     return (1);
+#endif /* NEW_CONFIG */
 }

Rewrite psmintr() to psm_intr(). In newconfig mode, softc structure is the argument of psm_intr() not the unit number.
+#ifdef NEW_CONFIG
+void
+psm_intr(void *arg)
+#else /* NEW_CONFIG */
 void
 psmintr(int unit)
+#endif /* NEW_CONFIG */
 {
     /*
      * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN)
@@ -1714,7 +1826,11 @@
 	MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN,
         MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN
     };
+#ifdef NEW_CONFIG
+    struct psm_softc *sc = (struct psm_softc *)arg;
+#else /* NEW_CONFIG */
     register struct psm_softc *sc = psm_softc[unit];
+#endif /* NEW_CONFIG */
     mousestatus_t ms;
     int x, y, z;
     int c;

Modification of "files" file

When new driver added, file names of the driver of source codes should be added to "files" file. Currently, there are two "files" file. One is a /sys/conf/files.newconf and another is a /sys/i386/conf/files.i386.newconf . The former is for a machine independent driver, and the later is for a machine dependent driver. Device drivers which souce code locates under /sys/i386 might be registered later, and others might be registerd former.

How to register source codes of the device driver is related to following syntax. (I will skip detail explanations. Please refer to a paper of Mr. Chiris Torek)

softc structure

Generally speaking, a device driver needs internal work variables for each driver units. These variables are gathered up to a structure, and are initialized when the device driver is attached. The structure is called "softc structure".

In old FreeBSD config scheme, the device driver is responsible for initialization and allocation of a softc structure. In newconfig scheme, these are performed by the configuration framework rather than the device deriver. In order to let the framework know a size of a softc structure to be allocated, the size should be described in cfattach structure.

In newconfig scheme, head part of a softc structure is used by the framework internally. Because of this, head part of any device driver should be a element of device structure. Of cause, the size of the softc structure to let the framework know is equal or larger than the size of the softc structure itself.

Newconfig is designed as the framework allocates a softc structure. Because each driver allocates a softc structure in the traditional FreeBSD framework, we may use old softc structure in first step of the porting, after it is changed to use a softc structure which is allocated by the framework. In this case, there should be device structure at least for the newconfig framework.

We can access to a softc structure allocated by newconfig by following way:

precautions

In newconfig framework, you should be care about following points:

Generally speaking, an attach function is not always called just after a match function is called. In a bus code, after every soft of match function are called, the best attach function is called depending on the return value of all match functions. So you should avoid side effect operation in a match function. An attach function should not depend on a status caused by a match function. If you need a kind of initialization of a device, you should also initialize in an attach function.

In a device which is a controller of another bus, an attach function should call a initialization code of the bus. Newconfig framework defines how to call a initialization code of the bus, so you need to change an attach function. It includes SCSI bus, IDE bus(wdc), parallel port bus(nlpt) and so. In device drivers of these bus controller devices, you need to modify a code which initialize bus. Until the bus controller code is implemented, we can not use a driver under the bus.


For questions of this page, please mail to
newconfig@jp.FreeBSD.org
.