diff options
Diffstat (limited to 'sys/dev/ppbus/ppbconf.c')
-rw-r--r-- | sys/dev/ppbus/ppbconf.c | 429 |
1 files changed, 245 insertions, 184 deletions
diff --git a/sys/dev/ppbus/ppbconf.c b/sys/dev/ppbus/ppbconf.c index f98fcf2..2d7aa1a 100644 --- a/sys/dev/ppbus/ppbconf.c +++ b/sys/dev/ppbus/ppbconf.c @@ -26,61 +26,154 @@ * $FreeBSD$ * */ +#include "opt_ppb_1284.h" + #include <sys/param.h> #include <sys/systm.h> -#include <sys/linker_set.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> #include <sys/malloc.h> -#include <vm/vm.h> -#include <vm/pmap.h> - #include <dev/ppbus/ppbconf.h> #include <dev/ppbus/ppb_1284.h> -#include "opt_ppb_1284.h" +#include "ppbus_if.h" + +#define DEVTOSOFTC(dev) ((struct ppb_data *)device_get_softc(dev)) + +MALLOC_DEFINE(M_PPBUSDEV, "ppbusdev", "Parallel Port bus device"); -static LIST_HEAD(, ppb_data) ppbdata; /* list of existing ppbus */ +static devclass_t ppbus_devclass; /* - * Add a null driver so that the linker set always exists. + * Device methods */ - -static struct ppb_driver nulldriver = { - NULL, NULL, "null" +static int ppbus_probe(device_t); +static int ppbus_attach(device_t); +static void ppbus_print_child(device_t bus, device_t dev); +static int ppbus_read_ivar(device_t, device_t, int, uintptr_t *); +static int ppbus_write_ivar(device_t, device_t, int, u_long); +static int ppbus_setup_intr(device_t, device_t, struct resource *, int, + void (*)(void *), void *, void **); +static int ppbus_teardown_intr(device_t, device_t, struct resource *, void *); + +static device_method_t ppbus_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, ppbus_probe), + DEVMETHOD(device_attach, ppbus_attach), + + /* bus interface */ + DEVMETHOD(bus_print_child, ppbus_print_child), + DEVMETHOD(bus_read_ivar, ppbus_read_ivar), + DEVMETHOD(bus_write_ivar, ppbus_write_ivar), + DEVMETHOD(bus_setup_intr, ppbus_setup_intr), + DEVMETHOD(bus_teardown_intr, ppbus_teardown_intr), + DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), + + { 0, 0 } }; -DATA_SET(ppbdriver_set, nulldriver); +static driver_t ppbus_driver = { + "ppbus", + ppbus_methods, + sizeof(struct ppb_data), + }; + +static void +ppbus_print_child(device_t bus, device_t dev) +{ + struct ppb_device *ppbdev; + + bus_print_child_header(bus, dev); + + ppbdev = (struct ppb_device *)device_get_ivars(dev); + + if (ppbdev->flags != 0) + printf(" flags 0x%x", ppbdev->flags); + + printf(" on %s%d\n", device_get_name(bus), device_get_unit(bus)); + + return; +} + +static int +ppbus_probe(device_t dev) +{ + device_set_desc(dev, "Parallel port bus"); + + return (0); +} /* - * ppb_alloc_bus() + * ppb_add_device() * - * Allocate area to store the ppbus description. + * Add a ppbus device, allocate/initialize the ivars */ -struct ppb_data * -ppb_alloc_bus(void) +static void +ppbus_add_device(device_t dev, const char *name, int unit) { - struct ppb_data *ppb; - static int ppbdata_initted = 0; /* done-init flag */ - - ppb = (struct ppb_data *) malloc(sizeof(struct ppb_data), - M_TEMP, M_NOWAIT); + struct ppb_device *ppbdev; + device_t child; + + /* allocate ivars for the new ppbus child */ + ppbdev = malloc(sizeof(struct ppb_device), M_PPBUSDEV, M_NOWAIT); + if (!ppbdev) + return; + bzero(ppbdev, sizeof *ppbdev); + + /* initialize the ivars */ + ppbdev->name = name; + + /* add the device as a child to the ppbus bus with the allocated + * ivars */ + child = device_add_child(dev, name, unit); + device_set_ivars(child, ppbdev); - /* - * Add the new parallel port bus to the list of existing ppbus. - */ - if (ppb) { - bzero(ppb, sizeof(struct ppb_data)); + return; +} - if (!ppbdata_initted) { /* list not initialised */ - LIST_INIT(&ppbdata); - ppbdata_initted = 1; - } - LIST_INSERT_HEAD(&ppbdata, ppb, ppb_chain); - } else { - printf("ppb_alloc_bus: cannot malloc!\n"); +static int +ppbus_read_ivar(device_t bus, device_t dev, int index, uintptr_t* val) + { + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); + + switch (index) { + case PPBUS_IVAR_MODE: + /* XXX yet device mode = ppbus mode = chipset mode */ + *val = (u_long)ppb_get_mode(bus); + ppbdev->mode = (u_short)*val; + break; + case PPBUS_IVAR_AVM: + *val = (u_long)ppbdev->avm; + break; + case PPBUS_IVAR_IRQ: + BUS_READ_IVAR(device_get_parent(bus), bus, PPC_IVAR_IRQ, val); + break; + default: + return (ENOENT); } - return(ppb); + + return (0); } + +static int +ppbus_write_ivar(device_t bus, device_t dev, int index, u_long val) +{ + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); + + switch (index) { + case PPBUS_IVAR_MODE: + /* XXX yet device mode = ppbus mode = chipset mode */ + ppb_set_mode(bus,val); + ppbdev->mode = ppb_get_mode(bus); + break; + default: + return (ENOENT); + } + + return (0); + } #define PPB_PNP_PRINTER 0 #define PPB_PNP_MODEM 1 @@ -151,17 +244,17 @@ search_token(char *str, int slen, char *token) * Returns the class id. of the peripherial, -1 otherwise */ static int -ppb_pnp_detect(struct ppb_data *ppb, struct ppb_device *pnpdev) +ppb_pnp_detect(device_t bus) { char *token, *class = 0; int i, len, error; int class_id = -1; char str[PPB_PnP_STRING_SIZE+1]; + int unit = device_get_unit(bus); - printf("Probing for PnP devices on ppbus%d:\n", - ppb->ppb_link->adapter_unit); + printf("Probing for PnP devices on ppbus%d:\n", unit); - if ((error = ppb_1284_read_id(pnpdev, PPB_NIBBLE, str, + if ((error = ppb_1284_read_id(bus, PPB_NIBBLE, str, PPB_PnP_STRING_SIZE, &len))) goto end_detect; @@ -178,10 +271,10 @@ ppb_pnp_detect(struct ppb_data *ppb, struct ppb_device *pnpdev) if ((token = search_token(str, len, "MFG")) != NULL || (token = search_token(str, len, "MANUFACTURER")) != NULL) - printf("ppbus%d: <%s", ppb->ppb_link->adapter_unit, + printf("ppbus%d: <%s", unit, search_token(token, UNKNOWN_LENGTH, ":") + 1); else - printf("ppbus%d: <unknown", ppb->ppb_link->adapter_unit); + printf("ppbus%d: <unknown", unit); if ((token = search_token(str, len, "MDL")) != NULL || (token = search_token(str, len, "MODEL")) != NULL) @@ -233,21 +326,11 @@ end_detect: * Scan the ppbus for IEEE1284 compliant devices */ static int -ppb_scan_bus(struct ppb_data *ppb) +ppb_scan_bus(device_t bus) { - struct ppb_device pnpdev; /* temporary device to perform I/O */ + struct ppb_data * ppb = (struct ppb_data *)device_get_softc(bus); int error = 0; - - /* initialize the pnpdev structure for future use */ - bzero(&pnpdev, sizeof(pnpdev)); - pnpdev.ppb = ppb; - - if ((error = ppb_request_bus(&pnpdev, PPB_DONTWAIT))) { - if (bootverbose) - printf("ppb: cannot allocate ppbus!\n"); - - return (error); - } + int unit = device_get_unit(bus); /* try all IEEE1284 modes, for one device only * @@ -255,207 +338,175 @@ ppb_scan_bus(struct ppb_data *ppb) * daisy chained devices */ - error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, PPB_REQUEST_ID); + error = ppb_1284_negociate(bus, PPB_NIBBLE, PPB_REQUEST_ID); if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284)) goto end_scan; - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); - printf("ppb%d: IEEE1284 device found ", ppb->ppb_link->adapter_unit); + printf("ppbus%d: IEEE1284 device found ", unit); - if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, 0))) { + if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE, 0))) { printf("/NIBBLE"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2, 0))) { + if (!(error = ppb_1284_negociate(bus, PPB_PS2, 0))) { printf("/PS2"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, 0))) { + if (!(error = ppb_1284_negociate(bus, PPB_ECP, 0))) { printf("/ECP"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, PPB_USE_RLE))) { + if (!(error = ppb_1284_negociate(bus, PPB_ECP, PPB_USE_RLE))) { printf("/ECP_RLE"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_EPP, 0))) { + if (!(error = ppb_1284_negociate(bus, PPB_EPP, 0))) { printf("/EPP"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } /* try more IEEE1284 modes */ if (bootverbose) { - if (!(error = ppb_1284_negociate(&pnpdev, PPB_NIBBLE, + if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE, PPB_REQUEST_ID))) { printf("/NIBBLE_ID"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_PS2, + if (!(error = ppb_1284_negociate(bus, PPB_PS2, PPB_REQUEST_ID))) { printf("/PS2_ID"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, + if (!(error = ppb_1284_negociate(bus, PPB_ECP, PPB_REQUEST_ID))) { printf("/ECP_ID"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_ECP, + if (!(error = ppb_1284_negociate(bus, PPB_ECP, PPB_REQUEST_ID | PPB_USE_RLE))) { printf("/ECP_RLE_ID"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } - if (!(error = ppb_1284_negociate(&pnpdev, PPB_COMPATIBLE, + if (!(error = ppb_1284_negociate(bus, PPB_COMPATIBLE, PPB_EXTENSIBILITY_LINK))) { printf("/Extensibility Link"); - ppb_1284_terminate(&pnpdev); + ppb_1284_terminate(bus); } } printf("\n"); /* detect PnP devices */ - ppb->class_id = ppb_pnp_detect(ppb, &pnpdev); - - ppb_release_bus(&pnpdev); + ppb->class_id = ppb_pnp_detect(bus); return (0); end_scan: - ppb_release_bus(&pnpdev); return (error); } #endif /* !DONTPROBE_1284 */ -/* - * ppb_attachdevs() - * - * Called by ppcattach(), this function probes the ppbus and - * attaches found devices. - */ -int -ppb_attachdevs(struct ppb_data *ppb) +static int +ppbus_attach(device_t dev) { - struct ppb_device *dev; - struct ppb_driver **p_drvpp, *p_drvp; + int i; + int unit, disabled; + char *name; - LIST_INIT(&ppb->ppb_devs); /* initialise device/driver list */ - p_drvpp = (struct ppb_driver **)ppbdriver_set.ls_items; - -#ifndef DONTPROBE_1284 - /* detect IEEE1284 compliant devices */ - ppb_scan_bus(ppb); -#endif /* !DONTPROBE_1284 */ - /* - * Blindly try all probes here. Later we should look at - * the parallel-port PnP standard, and intelligently seek - * drivers based on configuration first. + * Add all devices configured to be attached to ppbus0. */ - while ((p_drvp = *p_drvpp++) != NULL) { - if (p_drvp->probe && (dev = (p_drvp->probe(ppb))) != NULL) { - /* - * Add the device to the list of probed devices. - */ - LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); - - /* Call the device's attach routine */ - (void)p_drvp->attach(dev); - } + for (i = resource_query_string(-1, "at", "ppbus0"); + i != -1; + i = resource_query_string(i, "at", "ppbus0")) { + unit = resource_query_unit(i); + name = resource_query_name(i); + if (resource_int_value(name, unit, "disabled", &disabled) == 0) { + if (disabled) + continue; + } + ppbus_add_device(dev, name, unit); } - return (0); -} - -/* - * ppb_next_bus() - * - * Return the next bus in ppbus queue - */ -struct ppb_data * -ppb_next_bus(struct ppb_data *ppb) -{ - if (ppb == NULL) - return (ppbdata.lh_first); - - return (ppb->ppb_chain.le_next); -} + /* + * and ppbus? + */ + for (i = resource_query_string(-1, "at", "ppbus"); + i != -1; + i = resource_query_string(i, "at", "ppbus")) { + unit = resource_query_unit(i); + name = resource_query_name(i); + if (resource_int_value(name, unit, "disabled", &disabled) == 0) { + if (disabled) + continue; + } + ppbus_add_device(dev, name, unit); + } -/* - * ppb_lookup_bus() - * - * Get ppb_data structure pointer according to the base address of the ppbus - */ -struct ppb_data * -ppb_lookup_bus(int base_port) -{ - struct ppb_data *ppb; +#ifndef DONTPROBE_1284 + /* detect IEEE1284 compliant devices */ + ppb_scan_bus(dev); +#endif /* !DONTPROBE_1284 */ - for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next) - if (ppb->ppb_link->base == base_port) - break; + /* launch attachement of the added children */ + bus_generic_attach(dev); - return (ppb); + return 0; } -/* - * ppb_lookup_link() - * - * Get ppb_data structure pointer according to the unit value - * of the corresponding link structure - */ -struct ppb_data * -ppb_lookup_link(int unit) +static int +ppbus_setup_intr(device_t bus, device_t child, struct resource *r, int flags, + void (*ihand)(void *), void *arg, void **cookiep) { - struct ppb_data *ppb; + int error; + struct ppb_data *ppb = DEVTOSOFTC(bus); + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child); - for (ppb = ppbdata.lh_first; ppb; ppb = ppb->ppb_chain.le_next) - if (ppb->ppb_link->adapter_unit == unit) - break; + /* a device driver must own the bus to register an interrupt */ + if (ppb->ppb_owner != child) + return (EINVAL); - return (ppb); -} - -/* - * ppb_attach_device() - * - * Called by loadable kernel modules to add a device - */ -int -ppb_attach_device(struct ppb_device *dev) -{ - struct ppb_data *ppb = dev->ppb; + if ((error = BUS_SETUP_INTR(device_get_parent(bus), child, r, flags, + ihand, arg, cookiep))) + return (error); - /* add the device to the list of probed devices */ - LIST_INSERT_HEAD(&ppb->ppb_devs, dev, chain); + /* store the resource and the cookie for eventually forcing + * handler unregistration + */ + ppbdev->intr_cookie = *cookiep; + ppbdev->intr_resource = r; return (0); } -/* - * ppb_remove_device() - * - * Called by loadable kernel modules to remove a device - */ -void -ppb_remove_device(struct ppb_device *dev) +static int +ppbus_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih) { + struct ppb_data *ppb = DEVTOSOFTC(bus); + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child); + + /* a device driver must own the bus to unregister an interrupt */ + if ((ppb->ppb_owner != child) || (ppbdev->intr_cookie != ih) || + (ppbdev->intr_resource != r)) + return (EINVAL); - /* remove the device from the list of probed devices */ - LIST_REMOVE(dev, chain); + ppbdev->intr_cookie = 0; + ppbdev->intr_resource = 0; - return; + /* pass unregistration to the upper layer */ + return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, ih)); } /* @@ -466,10 +517,11 @@ ppb_remove_device(struct ppb_device *dev) * how : PPB_WAIT or PPB_DONTWAIT */ int -ppb_request_bus(struct ppb_device *dev, int how) +ppb_request_bus(device_t bus, device_t dev, int how) { int s, error = 0; - struct ppb_data *ppb = dev->ppb; + struct ppb_data *ppb = DEVTOSOFTC(bus); + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); while (!error) { s = splhigh(); @@ -499,8 +551,8 @@ ppb_request_bus(struct ppb_device *dev, int how) * drivers that do not set there operating mode * during attachement */ - if (dev->ctx.valid) - ppb_set_mode(dev, dev->ctx.mode); + if (ppbdev->ctx.valid) + ppb_set_mode(bus, ppbdev->ctx.mode); splx(s); return (0); @@ -516,10 +568,17 @@ ppb_request_bus(struct ppb_device *dev, int how) * Release the device allocated with ppb_request_dev() */ int -ppb_release_bus(struct ppb_device *dev) +ppb_release_bus(device_t bus, device_t dev) { - int s; - struct ppb_data *ppb = dev->ppb; + int s, error; + struct ppb_data *ppb = DEVTOSOFTC(bus); + struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev); + + if (ppbdev->intr_resource != 0) + /* force interrupt handler unregistration when the ppbus is released */ + if ((error = BUS_TEARDOWN_INTR(bus, dev, ppbdev->intr_resource, + ppbdev->intr_cookie))) + return (error); s = splhigh(); if (ppb->ppb_owner != dev) { @@ -531,13 +590,15 @@ ppb_release_bus(struct ppb_device *dev) splx(s); /* save the context of the device */ - dev->ctx.mode = ppb_get_mode(dev); + ppbdev->ctx.mode = ppb_get_mode(bus); /* ok, now the context of the device is valid */ - dev->ctx.valid = 1; + ppbdev->ctx.valid = 1; /* wakeup waiting processes */ wakeup(ppb); return (0); } + +DRIVER_MODULE(ppbus, ppc, ppbus_driver, ppbus_devclass, 0, 0); |