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/usb/serial/ubser.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) 2004 Bernd Walter <ticso@FreeBSD.org>
    3  *
    4  * $URL: https://devel.bwct.de/svn/projects/ubser/ubser.c $
    5  * $Date: 2004-02-29 01:53:10 +0100 (Sun, 29 Feb 2004) $
    6  * $Author: ticso $
    7  * $Rev: 1127 $
    8  */
    9 
   10 /*-
   11  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-2-Clause-NetBSD
   12  *
   13  * Copyright (c) 2001-2002, Shunsuke Akiyama <akiyama@jp.FreeBSD.org>.
   14  * All rights reserved.
   15  *
   16  * Redistribution and use in source and binary forms, with or without
   17  * modification, are permitted provided that the following conditions
   18  * are met:
   19  * 1. Redistributions of source code must retain the above copyright
   20  *    notice, this list of conditions and the following disclaimer.
   21  * 2. Redistributions in binary form must reproduce the above copyright
   22  *    notice, this list of conditions and the following disclaimer in the
   23  *    documentation and/or other materials provided with the distribution.
   24  *
   25  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   35  * SUCH DAMAGE.
   36  */
   37 
   38 /*-
   39  * Copyright (c) 2000 The NetBSD Foundation, Inc.
   40  * All rights reserved.
   41  *
   42  * This code is derived from software contributed to The NetBSD Foundation
   43  * by Lennart Augustsson (lennart@augustsson.net).
   44  *
   45  * Redistribution and use in source and binary forms, with or without
   46  * modification, are permitted provided that the following conditions
   47  * are met:
   48  * 1. Redistributions of source code must retain the above copyright
   49  *    notice, this list of conditions and the following disclaimer.
   50  * 2. Redistributions in binary form must reproduce the above copyright
   51  *    notice, this list of conditions and the following disclaimer in the
   52  *    documentation and/or other materials provided with the distribution.
   53  *
   54  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   55  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   56  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   57  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   58  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   59  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   60  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   61  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   62  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   63  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   64  * POSSIBILITY OF SUCH DAMAGE.
   65  */
   66 
   67 #include <sys/cdefs.h>
   68 __FBSDID("$FreeBSD$");
   69 
   70 /*
   71  * BWCT serial adapter driver
   72  */
   73 
   74 #include <sys/stdint.h>
   75 #include <sys/stddef.h>
   76 #include <sys/param.h>
   77 #include <sys/queue.h>
   78 #include <sys/types.h>
   79 #include <sys/systm.h>
   80 #include <sys/kernel.h>
   81 #include <sys/bus.h>
   82 #include <sys/module.h>
   83 #include <sys/lock.h>
   84 #include <sys/mutex.h>
   85 #include <sys/condvar.h>
   86 #include <sys/sysctl.h>
   87 #include <sys/sx.h>
   88 #include <sys/unistd.h>
   89 #include <sys/callout.h>
   90 #include <sys/malloc.h>
   91 #include <sys/priv.h>
   92 
   93 #include <dev/usb/usb.h>
   94 #include <dev/usb/usbdi.h>
   95 #include <dev/usb/usbdi_util.h>
   96 #include "usbdevs.h"
   97 
   98 #define USB_DEBUG_VAR ubser_debug
   99 #include <dev/usb/usb_debug.h>
  100 #include <dev/usb/usb_process.h>
  101 
  102 #include <dev/usb/serial/usb_serial.h>
  103 
  104 #define UBSER_UNIT_MAX  32
  105 
  106 /* Vendor Interface Requests */
  107 #define VENDOR_GET_NUMSER               0x01
  108 #define VENDOR_SET_BREAK                0x02
  109 #define VENDOR_CLEAR_BREAK              0x03
  110 
  111 #ifdef USB_DEBUG
  112 static int ubser_debug = 0;
  113 
  114 static SYSCTL_NODE(_hw_usb, OID_AUTO, ubser, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
  115     "USB ubser");
  116 SYSCTL_INT(_hw_usb_ubser, OID_AUTO, debug, CTLFLAG_RWTUN,
  117     &ubser_debug, 0, "ubser debug level");
  118 #endif
  119 
  120 enum {
  121         UBSER_BULK_DT_WR,
  122         UBSER_BULK_DT_RD,
  123         UBSER_N_TRANSFER,
  124 };
  125 
  126 struct ubser_softc {
  127         struct ucom_super_softc sc_super_ucom;
  128         struct ucom_softc sc_ucom[UBSER_UNIT_MAX];
  129 
  130         struct usb_xfer *sc_xfer[UBSER_N_TRANSFER];
  131         struct usb_device *sc_udev;
  132         struct mtx sc_mtx;
  133 
  134         uint16_t sc_tx_size;
  135 
  136         uint8_t sc_numser;
  137         uint8_t sc_iface_no;
  138         uint8_t sc_iface_index;
  139         uint8_t sc_curr_tx_unit;
  140 };
  141 
  142 /* prototypes */
  143 
  144 static device_probe_t ubser_probe;
  145 static device_attach_t ubser_attach;
  146 static device_detach_t ubser_detach;
  147 static void ubser_free_softc(struct ubser_softc *);
  148 
  149 static usb_callback_t ubser_write_callback;
  150 static usb_callback_t ubser_read_callback;
  151 
  152 static void     ubser_free(struct ucom_softc *);
  153 static int      ubser_pre_param(struct ucom_softc *, struct termios *);
  154 static void     ubser_cfg_set_break(struct ucom_softc *, uint8_t);
  155 static void     ubser_cfg_get_status(struct ucom_softc *, uint8_t *,
  156                     uint8_t *);
  157 static void     ubser_start_read(struct ucom_softc *);
  158 static void     ubser_stop_read(struct ucom_softc *);
  159 static void     ubser_start_write(struct ucom_softc *);
  160 static void     ubser_stop_write(struct ucom_softc *);
  161 static void     ubser_poll(struct ucom_softc *ucom);
  162 
  163 static const struct usb_config ubser_config[UBSER_N_TRANSFER] = {
  164         [UBSER_BULK_DT_WR] = {
  165                 .type = UE_BULK,
  166                 .endpoint = UE_ADDR_ANY,
  167                 .direction = UE_DIR_OUT,
  168                 .bufsize = 0,   /* use wMaxPacketSize */
  169                 .flags = {.pipe_bof = 1,.force_short_xfer = 1,},
  170                 .callback = &ubser_write_callback,
  171         },
  172 
  173         [UBSER_BULK_DT_RD] = {
  174                 .type = UE_BULK,
  175                 .endpoint = UE_ADDR_ANY,
  176                 .direction = UE_DIR_IN,
  177                 .bufsize = 0,   /* use wMaxPacketSize */
  178                 .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
  179                 .callback = &ubser_read_callback,
  180         },
  181 };
  182 
  183 static const struct ucom_callback ubser_callback = {
  184         .ucom_cfg_set_break = &ubser_cfg_set_break,
  185         .ucom_cfg_get_status = &ubser_cfg_get_status,
  186         .ucom_pre_param = &ubser_pre_param,
  187         .ucom_start_read = &ubser_start_read,
  188         .ucom_stop_read = &ubser_stop_read,
  189         .ucom_start_write = &ubser_start_write,
  190         .ucom_stop_write = &ubser_stop_write,
  191         .ucom_poll = &ubser_poll,
  192         .ucom_free = &ubser_free,
  193 };
  194 
  195 static device_method_t ubser_methods[] = {
  196         DEVMETHOD(device_probe, ubser_probe),
  197         DEVMETHOD(device_attach, ubser_attach),
  198         DEVMETHOD(device_detach, ubser_detach),
  199         DEVMETHOD_END
  200 };
  201 
  202 static driver_t ubser_driver = {
  203         .name = "ubser",
  204         .methods = ubser_methods,
  205         .size = sizeof(struct ubser_softc),
  206 };
  207 
  208 DRIVER_MODULE(ubser, uhub, ubser_driver, NULL, NULL);
  209 MODULE_DEPEND(ubser, ucom, 1, 1, 1);
  210 MODULE_DEPEND(ubser, usb, 1, 1, 1);
  211 MODULE_VERSION(ubser, 1);
  212 
  213 static int
  214 ubser_probe(device_t dev)
  215 {
  216         struct usb_attach_arg *uaa = device_get_ivars(dev);
  217 
  218         if (uaa->usb_mode != USB_MODE_HOST) {
  219                 return (ENXIO);
  220         }
  221         /* check if this is a BWCT vendor specific ubser interface */
  222         if ((strcmp(usb_get_manufacturer(uaa->device), "BWCT") == 0) &&
  223             (uaa->info.bInterfaceClass == 0xff) &&
  224             (uaa->info.bInterfaceSubClass == 0x00))
  225                 return (0);
  226 
  227         return (ENXIO);
  228 }
  229 
  230 static int
  231 ubser_attach(device_t dev)
  232 {
  233         struct usb_attach_arg *uaa = device_get_ivars(dev);
  234         struct ubser_softc *sc = device_get_softc(dev);
  235         struct usb_device_request req;
  236         uint8_t n;
  237         int error;
  238 
  239         device_set_usb_desc(dev);
  240         mtx_init(&sc->sc_mtx, "ubser", NULL, MTX_DEF);
  241         ucom_ref(&sc->sc_super_ucom);
  242 
  243         sc->sc_iface_no = uaa->info.bIfaceNum;
  244         sc->sc_iface_index = uaa->info.bIfaceIndex;
  245         sc->sc_udev = uaa->device;
  246 
  247         /* get number of serials */
  248         req.bmRequestType = UT_READ_VENDOR_INTERFACE;
  249         req.bRequest = VENDOR_GET_NUMSER;
  250         USETW(req.wValue, 0);
  251         req.wIndex[0] = sc->sc_iface_no;
  252         req.wIndex[1] = 0;
  253         USETW(req.wLength, 1);
  254         error = usbd_do_request_flags(uaa->device, NULL,
  255             &req, &sc->sc_numser,
  256             0, NULL, USB_DEFAULT_TIMEOUT);
  257 
  258         if (error || (sc->sc_numser == 0)) {
  259                 device_printf(dev, "failed to get number "
  260                     "of serial ports: %s\n",
  261                     usbd_errstr(error));
  262                 goto detach;
  263         }
  264         if (sc->sc_numser > UBSER_UNIT_MAX)
  265                 sc->sc_numser = UBSER_UNIT_MAX;
  266 
  267         device_printf(dev, "found %i serials\n", sc->sc_numser);
  268 
  269         error = usbd_transfer_setup(uaa->device, &sc->sc_iface_index,
  270             sc->sc_xfer, ubser_config, UBSER_N_TRANSFER, sc, &sc->sc_mtx);
  271         if (error) {
  272                 goto detach;
  273         }
  274         sc->sc_tx_size = usbd_xfer_max_len(sc->sc_xfer[UBSER_BULK_DT_WR]);
  275 
  276         if (sc->sc_tx_size == 0) {
  277                 DPRINTFN(0, "invalid tx_size\n");
  278                 goto detach;
  279         }
  280         /* initialize port numbers */
  281 
  282         for (n = 0; n < sc->sc_numser; n++) {
  283                 sc->sc_ucom[n].sc_portno = n;
  284         }
  285 
  286         error = ucom_attach(&sc->sc_super_ucom, sc->sc_ucom,
  287             sc->sc_numser, sc, &ubser_callback, &sc->sc_mtx);
  288         if (error) {
  289                 goto detach;
  290         }
  291         ucom_set_pnpinfo_usb(&sc->sc_super_ucom, dev);
  292 
  293         mtx_lock(&sc->sc_mtx);
  294         usbd_xfer_set_stall(sc->sc_xfer[UBSER_BULK_DT_WR]);
  295         usbd_xfer_set_stall(sc->sc_xfer[UBSER_BULK_DT_RD]);
  296         usbd_transfer_start(sc->sc_xfer[UBSER_BULK_DT_RD]);
  297         mtx_unlock(&sc->sc_mtx);
  298 
  299         return (0);                     /* success */
  300 
  301 detach:
  302         ubser_detach(dev);
  303         return (ENXIO);                 /* failure */
  304 }
  305 
  306 static int
  307 ubser_detach(device_t dev)
  308 {
  309         struct ubser_softc *sc = device_get_softc(dev);
  310 
  311         DPRINTF("\n");
  312 
  313         ucom_detach(&sc->sc_super_ucom, sc->sc_ucom);
  314         usbd_transfer_unsetup(sc->sc_xfer, UBSER_N_TRANSFER);
  315 
  316         device_claim_softc(dev);
  317 
  318         ubser_free_softc(sc);
  319 
  320         return (0);
  321 }
  322 
  323 UCOM_UNLOAD_DRAIN(ubser);
  324 
  325 static void
  326 ubser_free_softc(struct ubser_softc *sc)
  327 {
  328         if (ucom_unref(&sc->sc_super_ucom)) {
  329                 mtx_destroy(&sc->sc_mtx);
  330                 device_free_softc(sc);
  331         }
  332 }
  333 
  334 static void
  335 ubser_free(struct ucom_softc *ucom)
  336 {
  337         ubser_free_softc(ucom->sc_parent);
  338 }
  339 
  340 static int
  341 ubser_pre_param(struct ucom_softc *ucom, struct termios *t)
  342 {
  343         DPRINTF("\n");
  344 
  345         /*
  346          * The firmware on our devices can only do 8n1@9600bps
  347          * without handshake.
  348          * We refuse to accept other configurations.
  349          */
  350 
  351         /* ensure 9600bps */
  352         switch (t->c_ospeed) {
  353         case 9600:
  354                 break;
  355         default:
  356                 return (EINVAL);
  357         }
  358 
  359         /* 2 stop bits not possible */
  360         if (t->c_cflag & CSTOPB)
  361                 return (EINVAL);
  362 
  363         /* XXX parity handling not possible with current firmware */
  364         if (t->c_cflag & PARENB)
  365                 return (EINVAL);
  366 
  367         /* we can only do 8 data bits */
  368         switch (t->c_cflag & CSIZE) {
  369         case CS8:
  370                 break;
  371         default:
  372                 return (EINVAL);
  373         }
  374 
  375         /* we can't do any kind of hardware handshaking */
  376         if ((t->c_cflag &
  377             (CRTS_IFLOW | CDTR_IFLOW | CDSR_OFLOW | CCAR_OFLOW)) != 0)
  378                 return (EINVAL);
  379 
  380         /*
  381          * XXX xon/xoff not supported by the firmware!
  382          * This is handled within FreeBSD only and may overflow buffers
  383          * because of delayed reaction due to device buffering.
  384          */
  385 
  386         return (0);
  387 }
  388 
  389 static __inline void
  390 ubser_inc_tx_unit(struct ubser_softc *sc)
  391 {
  392         sc->sc_curr_tx_unit++;
  393         if (sc->sc_curr_tx_unit >= sc->sc_numser) {
  394                 sc->sc_curr_tx_unit = 0;
  395         }
  396 }
  397 
  398 static void
  399 ubser_write_callback(struct usb_xfer *xfer, usb_error_t error)
  400 {
  401         struct ubser_softc *sc = usbd_xfer_softc(xfer);
  402         struct usb_page_cache *pc;
  403         uint8_t buf[1];
  404         uint8_t first_unit = sc->sc_curr_tx_unit;
  405         uint32_t actlen;
  406 
  407         switch (USB_GET_STATE(xfer)) {
  408         case USB_ST_SETUP:
  409         case USB_ST_TRANSFERRED:
  410 tr_setup:
  411                 pc = usbd_xfer_get_frame(xfer, 0);
  412                 do {
  413                         if (ucom_get_data(sc->sc_ucom + sc->sc_curr_tx_unit,
  414                             pc, 1, sc->sc_tx_size - 1,
  415                             &actlen)) {
  416                                 buf[0] = sc->sc_curr_tx_unit;
  417 
  418                                 usbd_copy_in(pc, 0, buf, 1);
  419 
  420                                 usbd_xfer_set_frame_len(xfer, 0, actlen + 1);
  421                                 usbd_transfer_submit(xfer);
  422 
  423                                 ubser_inc_tx_unit(sc);  /* round robin */
  424 
  425                                 break;
  426                         }
  427                         ubser_inc_tx_unit(sc);
  428 
  429                 } while (sc->sc_curr_tx_unit != first_unit);
  430 
  431                 return;
  432 
  433         default:                        /* Error */
  434                 if (error != USB_ERR_CANCELLED) {
  435                         /* try to clear stall first */
  436                         usbd_xfer_set_stall(xfer);
  437                         goto tr_setup;
  438                 }
  439                 return;
  440         }
  441 }
  442 
  443 static void
  444 ubser_read_callback(struct usb_xfer *xfer, usb_error_t error)
  445 {
  446         struct ubser_softc *sc = usbd_xfer_softc(xfer);
  447         struct usb_page_cache *pc;
  448         uint8_t buf[1];
  449         int actlen;
  450 
  451         usbd_xfer_status(xfer, &actlen, NULL, NULL, NULL);
  452 
  453         switch (USB_GET_STATE(xfer)) {
  454         case USB_ST_TRANSFERRED:
  455                 if (actlen < 1) {
  456                         DPRINTF("invalid actlen=0!\n");
  457                         goto tr_setup;
  458                 }
  459                 pc = usbd_xfer_get_frame(xfer, 0);
  460                 usbd_copy_out(pc, 0, buf, 1);
  461 
  462                 if (buf[0] >= sc->sc_numser) {
  463                         DPRINTF("invalid serial number!\n");
  464                         goto tr_setup;
  465                 }
  466                 ucom_put_data(sc->sc_ucom + buf[0], pc, 1, actlen - 1);
  467 
  468         case USB_ST_SETUP:
  469 tr_setup:
  470                 usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
  471                 usbd_transfer_submit(xfer);
  472                 return;
  473 
  474         default:                        /* Error */
  475                 if (error != USB_ERR_CANCELLED) {
  476                         /* try to clear stall first */
  477                         usbd_xfer_set_stall(xfer);
  478                         goto tr_setup;
  479                 }
  480                 return;
  481         }
  482 }
  483 
  484 static void
  485 ubser_cfg_set_break(struct ucom_softc *ucom, uint8_t onoff)
  486 {
  487         struct ubser_softc *sc = ucom->sc_parent;
  488         uint8_t x = ucom->sc_portno;
  489         struct usb_device_request req;
  490         usb_error_t err;
  491 
  492         if (onoff) {
  493                 req.bmRequestType = UT_READ_VENDOR_INTERFACE;
  494                 req.bRequest = VENDOR_SET_BREAK;
  495                 req.wValue[0] = x;
  496                 req.wValue[1] = 0;
  497                 req.wIndex[0] = sc->sc_iface_no;
  498                 req.wIndex[1] = 0;
  499                 USETW(req.wLength, 0);
  500 
  501                 err = ucom_cfg_do_request(sc->sc_udev, ucom, 
  502                     &req, NULL, 0, 1000);
  503                 if (err) {
  504                         DPRINTFN(0, "send break failed, error=%s\n",
  505                             usbd_errstr(err));
  506                 }
  507         }
  508 }
  509 
  510 static void
  511 ubser_cfg_get_status(struct ucom_softc *ucom, uint8_t *lsr, uint8_t *msr)
  512 {
  513         /* fake status bits */
  514         *lsr = 0;
  515         *msr = SER_DCD;
  516 }
  517 
  518 static void
  519 ubser_start_read(struct ucom_softc *ucom)
  520 {
  521         struct ubser_softc *sc = ucom->sc_parent;
  522 
  523         usbd_transfer_start(sc->sc_xfer[UBSER_BULK_DT_RD]);
  524 }
  525 
  526 static void
  527 ubser_stop_read(struct ucom_softc *ucom)
  528 {
  529         struct ubser_softc *sc = ucom->sc_parent;
  530 
  531         usbd_transfer_stop(sc->sc_xfer[UBSER_BULK_DT_RD]);
  532 }
  533 
  534 static void
  535 ubser_start_write(struct ucom_softc *ucom)
  536 {
  537         struct ubser_softc *sc = ucom->sc_parent;
  538 
  539         usbd_transfer_start(sc->sc_xfer[UBSER_BULK_DT_WR]);
  540 }
  541 
  542 static void
  543 ubser_stop_write(struct ucom_softc *ucom)
  544 {
  545         struct ubser_softc *sc = ucom->sc_parent;
  546 
  547         usbd_transfer_stop(sc->sc_xfer[UBSER_BULK_DT_WR]);
  548 }
  549 
  550 static void
  551 ubser_poll(struct ucom_softc *ucom)
  552 {
  553         struct ubser_softc *sc = ucom->sc_parent;
  554         usbd_transfer_poll(sc->sc_xfer, UBSER_N_TRANSFER);
  555 }

Cache object: 879c913217b35a51891a8d85969de072


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