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/5.3/sys/dev/ppbus/ppbconf.c 119418 2003-08-24 17:55:58Z obrien $");
   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_setup_intr(device_t bus, device_t child, struct resource *r, int flags,
  403                         void (*ihand)(void *), void *arg, void **cookiep)
  404 {
  405         int error;
  406         struct ppb_data *ppb = DEVTOSOFTC(bus);
  407         struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child);
  408 
  409         /* a device driver must own the bus to register an interrupt */
  410         if (ppb->ppb_owner != child)
  411                 return (EINVAL);
  412 
  413         if ((error = BUS_SETUP_INTR(device_get_parent(bus), child, r, flags,
  414                                         ihand, arg, cookiep)))
  415                 return (error);
  416 
  417         /* store the resource and the cookie for eventually forcing
  418          * handler unregistration
  419          */
  420         ppbdev->intr_cookie = *cookiep;
  421         ppbdev->intr_resource = r;
  422 
  423         return (0);
  424 }
  425 
  426 static int
  427 ppbus_teardown_intr(device_t bus, device_t child, struct resource *r, void *ih)
  428 {
  429         struct ppb_data *ppb = DEVTOSOFTC(bus);
  430         struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(child);
  431         
  432         /* a device driver must own the bus to unregister an interrupt */
  433         if ((ppb->ppb_owner != child) || (ppbdev->intr_cookie != ih) ||
  434                         (ppbdev->intr_resource != r))
  435                 return (EINVAL);
  436 
  437         ppbdev->intr_cookie = 0;
  438         ppbdev->intr_resource = 0;
  439 
  440         /* pass unregistration to the upper layer */
  441         return (BUS_TEARDOWN_INTR(device_get_parent(bus), child, r, ih));
  442 }
  443 
  444 /*
  445  * ppb_request_bus()
  446  *
  447  * Allocate the device to perform transfers.
  448  *
  449  * how  : PPB_WAIT or PPB_DONTWAIT
  450  */
  451 int
  452 ppb_request_bus(device_t bus, device_t dev, int how)
  453 {
  454         int s, error = 0;
  455         struct ppb_data *ppb = DEVTOSOFTC(bus);
  456         struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
  457 
  458         while (!error) {
  459                 s = splhigh();  
  460                 if (ppb->ppb_owner) {
  461                         splx(s);
  462 
  463                         switch (how) {
  464                         case (PPB_WAIT | PPB_INTR):
  465                                 error = tsleep(ppb, PPBPRI|PCATCH, "ppbreq", 0);
  466                                 break;
  467 
  468                         case (PPB_WAIT | PPB_NOINTR):
  469                                 error = tsleep(ppb, PPBPRI, "ppbreq", 0);
  470                                 break;
  471 
  472                         default:
  473                                 return (EWOULDBLOCK);
  474                                 break;
  475                         }
  476 
  477                 } else {
  478                         ppb->ppb_owner = dev;
  479 
  480                         /* restore the context of the device
  481                          * The first time, ctx.valid is certainly false
  482                          * then do not change anything. This is usefull for
  483                          * drivers that do not set there operating mode 
  484                          * during attachement
  485                          */
  486                         if (ppbdev->ctx.valid)
  487                                 ppb_set_mode(bus, ppbdev->ctx.mode);
  488 
  489                         splx(s);
  490                         return (0);
  491                 }
  492         }
  493 
  494         return (error);
  495 }
  496 
  497 /*
  498  * ppb_release_bus()
  499  *
  500  * Release the device allocated with ppb_request_bus()
  501  */
  502 int
  503 ppb_release_bus(device_t bus, device_t dev)
  504 {
  505         int s, error;
  506         struct ppb_data *ppb = DEVTOSOFTC(bus);
  507         struct ppb_device *ppbdev = (struct ppb_device *)device_get_ivars(dev);
  508 
  509         if (ppbdev->intr_resource != 0)
  510                 /* force interrupt handler unregistration when the ppbus is released */
  511                 if ((error = BUS_TEARDOWN_INTR(bus, dev, ppbdev->intr_resource,
  512                                                ppbdev->intr_cookie)))
  513                         return (error);
  514 
  515         s = splhigh();
  516         if (ppb->ppb_owner != dev) {
  517                 splx(s);
  518                 return (EACCES);
  519         }
  520 
  521         ppb->ppb_owner = 0;
  522         splx(s);
  523 
  524         /* save the context of the device */
  525         ppbdev->ctx.mode = ppb_get_mode(bus);
  526 
  527         /* ok, now the context of the device is valid */
  528         ppbdev->ctx.valid = 1;
  529 
  530         /* wakeup waiting processes */
  531         wakeup(ppb);
  532 
  533         return (0);
  534 }
  535 
  536 static devclass_t ppbus_devclass;
  537 
  538 static device_method_t ppbus_methods[] = {
  539         /* device interface */
  540         DEVMETHOD(device_probe,         ppbus_probe),
  541         DEVMETHOD(device_attach,        ppbus_attach),
  542   
  543         /* bus interface */
  544         DEVMETHOD(bus_add_child,        ppbus_add_child),
  545         DEVMETHOD(bus_print_child,      ppbus_print_child),
  546         DEVMETHOD(bus_read_ivar,        ppbus_read_ivar),
  547         DEVMETHOD(bus_write_ivar,       ppbus_write_ivar),
  548         DEVMETHOD(bus_setup_intr,       ppbus_setup_intr),
  549         DEVMETHOD(bus_teardown_intr,    ppbus_teardown_intr),
  550         DEVMETHOD(bus_alloc_resource,   bus_generic_alloc_resource),
  551 
  552         { 0, 0 }
  553 };
  554 
  555 static driver_t ppbus_driver = {
  556         "ppbus",
  557         ppbus_methods,
  558         sizeof(struct ppb_data),
  559 };
  560 DRIVER_MODULE(ppbus, ppc, ppbus_driver, ppbus_devclass, 0, 0);

Cache object: 06f030959378b9fbfb746a2b56b9c41e


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