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

Cache object: cf18e2d95e3655ed93c167e8c449d15c


[ 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.