The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ppbus/ppbconf.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 1997, 1998, 1999 Nicolas Souchu
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  *
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/7.3/sys/dev/ppbus/ppbconf.c 175370 2008-01-15 22:28:15Z jhb $");
   31 #include "opt_ppb_1284.h"
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/kernel.h>
   36 #include <sys/module.h>
   37 #include <sys/bus.h>
   38 #include <sys/malloc.h>
   39 #include <sys/rman.h>
   40 
   41 #include <machine/resource.h>
   42 
   43 #include <dev/ppbus/ppbconf.h>
   44 #include <dev/ppbus/ppb_1284.h>
   45 
   46 #include "ppbus_if.h"
   47   
   48 #define DEVTOSOFTC(dev) ((struct ppb_data *)device_get_softc(dev))
   49   
   50 static MALLOC_DEFINE(M_PPBUSDEV, "ppbusdev", "Parallel Port bus device");
   51 
   52 
   53 /*
   54  * Device methods
   55  */
   56 
   57 static void
   58 ppbus_print_child(device_t bus, device_t dev)
   59 {
   60         struct ppb_device *ppbdev;
   61 
   62         bus_print_child_header(bus, dev);
   63 
   64         ppbdev = (struct ppb_device *)device_get_ivars(dev);
   65 
   66         if (ppbdev->flags != 0)
   67                 printf(" flags 0x%x", ppbdev->flags);
   68 
   69         printf(" on %s%d\n", device_get_name(bus), device_get_unit(bus));
   70 
   71         return;
   72 }
   73 
   74 static int
   75 ppbus_probe(device_t dev)
   76 {
   77         device_set_desc(dev, "Parallel port bus");
   78 
   79         return (0);
   80 }
   81 
   82 /*
   83  * ppbus_add_child()
   84  *
   85  * Add a ppbus device, allocate/initialize the ivars
   86  */
   87 static device_t
   88 ppbus_add_child(device_t dev, int order, const char *name, int unit)
   89 {
   90         struct ppb_device *ppbdev;
   91         device_t child;
   92         
   93         /* allocate ivars for the new ppbus child */
   94         ppbdev = malloc(sizeof(struct ppb_device), M_PPBUSDEV,
   95                 M_NOWAIT | M_ZERO);
   96         if (!ppbdev)
   97                 return NULL;
   98 
   99         /* initialize the ivars */
  100         ppbdev->name = name;
  101 
  102         /* add the device as a child to the ppbus bus with the allocated
  103          * ivars */
  104         child = device_add_child_ordered(dev, order, name, unit);
  105         device_set_ivars(child, ppbdev);
  106 
  107         return child;
  108 }
  109 
  110 static int
  111 ppbus_read_ivar(device_t bus, device_t dev, int index, uintptr_t* val)
  112 {
  113         struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
  114   
  115         switch (index) {
  116         case PPBUS_IVAR_MODE:
  117                 /* XXX yet device mode = ppbus mode = chipset mode */
  118                 *val = (u_long)ppb_get_mode(bus);
  119                 ppbdev->mode = (u_short)*val;
  120                 break;
  121         case PPBUS_IVAR_AVM:
  122                 *val = (u_long)ppbdev->avm;
  123                 break;
  124         case PPBUS_IVAR_IRQ:
  125                 BUS_READ_IVAR(device_get_parent(bus), bus, PPC_IVAR_IRQ, val);
  126                 break;
  127         default:
  128                 return (ENOENT);
  129         }
  130   
  131         return (0);
  132 }
  133   
  134 static int
  135 ppbus_write_ivar(device_t bus, device_t dev, int index, u_long val)
  136 {
  137         struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
  138 
  139         switch (index) {
  140         case PPBUS_IVAR_MODE:
  141                 /* XXX yet device mode = ppbus mode = chipset mode */
  142                 ppb_set_mode(bus,val);
  143                 ppbdev->mode = ppb_get_mode(bus);
  144                 break;
  145         default:
  146                 return (ENOENT);
  147         }
  148 
  149         return (0);
  150   }
  151 
  152 #define PPB_PNP_PRINTER         0
  153 #define PPB_PNP_MODEM           1
  154 #define PPB_PNP_NET             2
  155 #define PPB_PNP_HDC             3
  156 #define PPB_PNP_PCMCIA          4
  157 #define PPB_PNP_MEDIA           5
  158 #define PPB_PNP_FDC             6
  159 #define PPB_PNP_PORTS           7
  160 #define PPB_PNP_SCANNER         8
  161 #define PPB_PNP_DIGICAM         9
  162 
  163 #ifndef DONTPROBE_1284
  164 
  165 static char *pnp_tokens[] = {
  166         "PRINTER", "MODEM", "NET", "HDC", "PCMCIA", "MEDIA",
  167         "FDC", "PORTS", "SCANNER", "DIGICAM", "", NULL };
  168 
  169 #if 0
  170 static char *pnp_classes[] = {
  171         "printer", "modem", "network device",
  172         "hard disk", "PCMCIA", "multimedia device",
  173         "floppy disk", "ports", "scanner",
  174         "digital camera", "unknown device", NULL };
  175 #endif
  176 
  177 /*
  178  * search_token()
  179  *
  180  * Search the first occurence of a token within a string
  181  */
  182 static char *
  183 search_token(char *str, int slen, char *token)
  184 {
  185         int tlen, i;
  186 
  187 #define UNKNOWN_LENGTH  -1
  188 
  189         if (slen == UNKNOWN_LENGTH)
  190                 /* get string's length */
  191                 slen = strlen(str);
  192 
  193         /* get token's length */
  194         tlen = strlen(token);
  195         if (tlen == 0)
  196                 return (str);
  197 
  198         for (i = 0; i <= slen-tlen; i++) {
  199                 if (strncmp(str + i, token, tlen) == 0)
  200                         return (&str[i]);
  201         }
  202 
  203         return (NULL);
  204 }
  205 
  206 /*
  207  * ppb_pnp_detect()
  208  *
  209  * Returns the class id. of the peripherial, -1 otherwise
  210  */
  211 static int
  212 ppb_pnp_detect(device_t bus)
  213 {
  214         char *token, *class = 0;
  215         int i, len, error;
  216         int class_id = -1;
  217         char str[PPB_PnP_STRING_SIZE+1];
  218         int unit = device_get_unit(bus);
  219 
  220         printf("Probing for PnP devices on ppbus%d:\n", unit);
  221         
  222         if ((error = ppb_1284_read_id(bus, PPB_NIBBLE, str,
  223                                         PPB_PnP_STRING_SIZE, &len)))
  224                 goto end_detect;
  225 
  226 #ifdef DEBUG_1284
  227         printf("ppb: <PnP> %d characters: ", len);
  228         for (i = 0; i < len; i++)
  229                 printf("%c(0x%x) ", str[i], str[i]);
  230         printf("\n");
  231 #endif
  232 
  233         /* replace ';' characters by '\0' */
  234         for (i = 0; i < len; i++)
  235                 str[i] = (str[i] == ';') ? '\0' : str[i];
  236 
  237         if ((token = search_token(str, len, "MFG")) != NULL ||
  238                 (token = search_token(str, len, "MANUFACTURER")) != NULL)
  239                 printf("ppbus%d: <%s", unit,
  240                         search_token(token, UNKNOWN_LENGTH, ":") + 1);
  241         else
  242                 printf("ppbus%d: <unknown", unit);
  243 
  244         if ((token = search_token(str, len, "MDL")) != NULL ||
  245                 (token = search_token(str, len, "MODEL")) != NULL)
  246                 printf(" %s",
  247                         search_token(token, UNKNOWN_LENGTH, ":") + 1);
  248         else
  249                 printf(" unknown");
  250 
  251         if ((token = search_token(str, len, "VER")) != NULL)
  252                 printf("/%s",
  253                         search_token(token, UNKNOWN_LENGTH, ":") + 1);
  254 
  255         if ((token = search_token(str, len, "REV")) != NULL)
  256                 printf(".%s",
  257                         search_token(token, UNKNOWN_LENGTH, ":") + 1);
  258 
  259         printf(">");
  260 
  261         if ((token = search_token(str, len, "CLS")) != NULL) {
  262                 class = search_token(token, UNKNOWN_LENGTH, ":") + 1;
  263                 printf(" %s", class);
  264         }
  265 
  266         if ((token = search_token(str, len, "CMD")) != NULL ||
  267                 (token = search_token(str, len, "COMMAND")) != NULL)
  268                 printf(" %s",
  269                         search_token(token, UNKNOWN_LENGTH, ":") + 1);
  270 
  271         printf("\n");
  272 
  273         if (class)
  274                 /* identify class ident */
  275                 for (i = 0; pnp_tokens[i] != NULL; i++) {
  276                         if (search_token(class, len, pnp_tokens[i]) != NULL) {
  277                                 class_id = i;
  278                                 goto end_detect;
  279                         }
  280                 }
  281 
  282         class_id = PPB_PnP_UNKNOWN;
  283 
  284 end_detect:
  285         return (class_id);
  286 }
  287 
  288 /*
  289  * ppb_scan_bus()
  290  *
  291  * Scan the ppbus for IEEE1284 compliant devices
  292  */
  293 static int
  294 ppb_scan_bus(device_t bus)
  295 {
  296         struct ppb_data * ppb = (struct ppb_data *)device_get_softc(bus);
  297         int error = 0;
  298         int unit = device_get_unit(bus);
  299 
  300         /* try all IEEE1284 modes, for one device only
  301          * 
  302          * XXX We should implement the IEEE1284.3 standard to detect
  303          * daisy chained devices
  304          */
  305 
  306         error = ppb_1284_negociate(bus, PPB_NIBBLE, PPB_REQUEST_ID);
  307 
  308         if ((ppb->state == PPB_ERROR) && (ppb->error == PPB_NOT_IEEE1284))
  309                 goto end_scan;
  310 
  311         ppb_1284_terminate(bus);
  312 
  313         printf("ppbus%d: IEEE1284 device found ", unit);
  314 
  315         if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE, 0))) {
  316                 printf("/NIBBLE");
  317                 ppb_1284_terminate(bus);
  318         }
  319 
  320         if (!(error = ppb_1284_negociate(bus, PPB_PS2, 0))) {
  321                 printf("/PS2");
  322                 ppb_1284_terminate(bus);
  323         }
  324 
  325         if (!(error = ppb_1284_negociate(bus, PPB_ECP, 0))) {
  326                 printf("/ECP");
  327                 ppb_1284_terminate(bus);
  328         }
  329 
  330         if (!(error = ppb_1284_negociate(bus, PPB_ECP, PPB_USE_RLE))) {
  331                 printf("/ECP_RLE");
  332                 ppb_1284_terminate(bus);
  333         }
  334 
  335         if (!(error = ppb_1284_negociate(bus, PPB_EPP, 0))) {
  336                 printf("/EPP");
  337                 ppb_1284_terminate(bus);
  338         }
  339 
  340         /* try more IEEE1284 modes */
  341         if (bootverbose) {
  342                 if (!(error = ppb_1284_negociate(bus, PPB_NIBBLE,
  343                                 PPB_REQUEST_ID))) {
  344                         printf("/NIBBLE_ID");
  345                         ppb_1284_terminate(bus);
  346                 }
  347 
  348                 if (!(error = ppb_1284_negociate(bus, PPB_PS2,
  349                                 PPB_REQUEST_ID))) {
  350                         printf("/PS2_ID");
  351                         ppb_1284_terminate(bus);
  352                 }
  353 
  354                 if (!(error = ppb_1284_negociate(bus, PPB_ECP,
  355                                 PPB_REQUEST_ID))) {
  356                         printf("/ECP_ID");
  357                         ppb_1284_terminate(bus);
  358                 }
  359 
  360                 if (!(error = ppb_1284_negociate(bus, PPB_ECP,
  361                                 PPB_REQUEST_ID | PPB_USE_RLE))) {
  362                         printf("/ECP_RLE_ID");
  363                         ppb_1284_terminate(bus);
  364                 }
  365 
  366                 if (!(error = ppb_1284_negociate(bus, PPB_COMPATIBLE,
  367                                 PPB_EXTENSIBILITY_LINK))) {
  368                         printf("/Extensibility Link");
  369                         ppb_1284_terminate(bus);
  370                 }
  371         }
  372 
  373         printf("\n");
  374 
  375         /* detect PnP devices */
  376         ppb->class_id = ppb_pnp_detect(bus);
  377 
  378         return (0);
  379 
  380 end_scan:
  381         return (error);
  382 }
  383 
  384 #endif /* !DONTPROBE_1284 */
  385 
  386 static void
  387 ppbus_dummy_intr(void *arg)
  388 {
  389 }
  390 
  391 static int
  392 ppbus_attach(device_t dev)
  393 {
  394         struct ppb_data *ppb = (struct ppb_data *)device_get_softc(dev);
  395         uintptr_t irq;
  396         int error, rid;
  397 
  398         /* Attach a dummy interrupt handler to suck up any stray interrupts. */
  399         BUS_READ_IVAR(device_get_parent(dev), dev, PPC_IVAR_IRQ, &irq);
  400 
  401         if (irq > 0) {
  402                 rid = 0;
  403                 ppb->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, irq,
  404                     irq, 1, RF_SHAREABLE);
  405                 if (ppb->irq_res != NULL) {
  406                         error = bus_setup_intr(dev, ppb->irq_res,
  407                             INTR_TYPE_TTY | INTR_MPSAFE, NULL, ppbus_dummy_intr,
  408                             ppb, &ppb->intr_cookie);
  409                         if (error) {
  410                                 device_printf(dev,
  411                                     "failed to setup interrupt handler\n");
  412                                 bus_release_resource(dev, SYS_RES_IRQ, 0,
  413                                     ppb->irq_res);
  414                                 return (error);
  415                         }
  416                 }
  417         }
  418 
  419         /* Locate our children */
  420         bus_generic_probe(dev);
  421 
  422 #ifndef DONTPROBE_1284
  423         /* detect IEEE1284 compliant devices */
  424         ppb_scan_bus(dev);
  425 #endif /* !DONTPROBE_1284 */
  426 
  427         /* launch attachement of the added children */
  428         bus_generic_attach(dev);
  429 
  430         return 0;
  431 }
  432 
  433 static int
  434 ppbus_detach(device_t dev)
  435 {
  436         struct ppb_data *ppb = (struct ppb_data *)device_get_softc(dev);
  437         device_t *children;
  438         int nchildren, i;
  439 
  440         /* detach & delete all children */
  441         if (!device_get_children(dev, &children, &nchildren)) {
  442                 for (i = 0; i < nchildren; i++)
  443                         if (children[i])
  444                                 device_delete_child(dev, children[i]);
  445                 free(children, M_TEMP);
  446         }
  447 
  448         if (ppb->irq_res != NULL) {
  449                 bus_teardown_intr(dev, ppb->irq_res, ppb->intr_cookie);
  450                 bus_release_resource(dev, SYS_RES_IRQ, 0, ppb->irq_res);
  451         }
  452         return (0);
  453 }
  454 
  455 static int
  456 ppbus_setup_intr(device_t bus, device_t child, struct resource *r, int flags,
  457     driver_filter_t *filt, void (*ihand)(void *), void *arg, void **cookiep)
  458 {
  459         int error;
  460         struct ppb_data *ppb = DEVTOSOFTC(bus);
  461         struct ppb_device *ppbdev = device_get_ivars(child);
  462 
  463         /* a device driver must own the bus to register an interrupt */
  464         if (ppb->ppb_owner != child)
  465                 return (EINVAL);
  466 
  467         if ((error = BUS_SETUP_INTR(device_get_parent(bus), child, r, flags,
  468                                         filt, ihand, arg, cookiep)))
  469                 return (error);
  470 
  471         /* store the resource and the cookie for eventually forcing
  472          * handler unregistration
  473          */
  474         ppbdev->intr_cookie = *cookiep;
  475         ppbdev->intr_resource = r;
  476 
  477         return (0);
  478 }
  479 
  480 static int
  481 ppbus_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih)
  482 {
  483         struct ppb_data *ppb = DEVTOSOFTC(bus);
  484         struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child);
  485         
  486         /* a device driver must own the bus to unregister an interrupt */
  487         if ((ppb->ppb_owner != child) || (ppbdev->intr_cookie != ih) ||
  488                         (ppbdev->intr_resource != r))
  489                 return (EINVAL);
  490 
  491         ppbdev->intr_cookie = 0;
  492         ppbdev->intr_resource = 0;
  493 
  494         /* pass unregistration to the upper layer */
  495         return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, ih));
  496 }
  497 
  498 /*
  499  * ppb_request_bus()
  500  *
  501  * Allocate the device to perform transfers.
  502  *
  503  * how  : PPB_WAIT or PPB_DONTWAIT
  504  */
  505 int
  506 ppb_request_bus(device_t bus, device_t dev, int how)
  507 {
  508         int s, error = 0;
  509         struct ppb_data *ppb = DEVTOSOFTC(bus);
  510         struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
  511 
  512         while (!error) {
  513                 s = splhigh();  
  514                 if (ppb->ppb_owner) {
  515                         splx(s);
  516 
  517                         switch (how) {
  518                         case (PPB_WAIT | PPB_INTR):
  519                                 error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0);
  520                                 break;
  521 
  522                         case (PPB_WAIT | PPB_NOINTR):
  523                                 error = tsleep(ppb, PPBPRI, "ppbreq", 0);
  524                                 break;
  525 
  526                         default:
  527                                 return (EWOULDBLOCK);
  528                                 break;
  529                         }
  530 
  531                 } else {
  532                         ppb->ppb_owner = dev;
  533 
  534                         /* restore the context of the device
  535                          * The first time, ctx.valid is certainly false
  536                          * then do not change anything. This is usefull for
  537                          * drivers that do not set there operating mode 
  538                          * during attachement
  539                          */
  540                         if (ppbdev->ctx.valid)
  541                                 ppb_set_mode(bus, ppbdev->ctx.mode);
  542 
  543                         splx(s);
  544                         return (0);
  545                 }
  546         }
  547 
  548         return (error);
  549 }
  550 
  551 /*
  552  * ppb_release_bus()
  553  *
  554  * Release the device allocated with ppb_request_bus()
  555  */
  556 int
  557 ppb_release_bus(device_t bus, device_t dev)
  558 {
  559         int s, error;
  560         struct ppb_data *ppb = DEVTOSOFTC(bus);
  561         struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
  562 
  563         if (ppbdev->intr_resource != 0)
  564                 /* force interrupt handler unregistration when the ppbus is released */
  565                 if ((error = BUS_TEARDOWN_INTR(bus, dev, ppbdev->intr_resource,
  566                                                ppbdev->intr_cookie)))
  567                         return (error);
  568 
  569         s = splhigh();
  570         if (ppb->ppb_owner != dev) {
  571                 splx(s);
  572                 return (EACCES);
  573         }
  574 
  575         ppb->ppb_owner = 0;
  576         splx(s);
  577 
  578         /* save the context of the device */
  579         ppbdev->ctx.mode = ppb_get_mode(bus);
  580 
  581         /* ok, now the context of the device is valid */
  582         ppbdev->ctx.valid = 1;
  583 
  584         /* wakeup waiting processes */
  585         wakeup(ppb);
  586 
  587         return (0);
  588 }
  589 
  590 static devclass_t ppbus_devclass;
  591 
  592 static device_method_t ppbus_methods[] = {
  593         /* device interface */
  594         DEVMETHOD(device_probe,         ppbus_probe),
  595         DEVMETHOD(device_attach,        ppbus_attach),
  596         DEVMETHOD(device_detach,        ppbus_detach),
  597   
  598         /* bus interface */
  599         DEVMETHOD(bus_add_child,        ppbus_add_child),
  600         DEVMETHOD(bus_print_child,      ppbus_print_child),
  601         DEVMETHOD(bus_read_ivar,        ppbus_read_ivar),
  602         DEVMETHOD(bus_write_ivar,       ppbus_write_ivar),
  603         DEVMETHOD(bus_setup_intr,       ppbus_setup_intr),
  604         DEVMETHOD(bus_teardown_intr,    ppbus_teardown_intr),
  605         DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
  606 
  607         { 0, 0 }
  608 };
  609 
  610 static driver_t ppbus_driver = {
  611         "ppbus",
  612         ppbus_methods,
  613         sizeof(struct ppb_data),
  614 };
  615 DRIVER_MODULE(ppbus, ppc, ppbus_driver, ppbus_devclass, 0, 0);

Cache object: 8b553ac9754dbd1287ca8015ba540698


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.