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/iicbus/ad7417.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) 2010 Andreas Tobler
    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 ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   19  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   20  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
   21  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   22  * 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 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/bus.h>
   32 #include <sys/systm.h>
   33 #include <sys/module.h>
   34 #include <sys/callout.h>
   35 #include <sys/conf.h>
   36 #include <sys/cpu.h>
   37 #include <sys/ctype.h>
   38 #include <sys/kernel.h>
   39 #include <sys/reboot.h>
   40 #include <sys/rman.h>
   41 #include <sys/sysctl.h>
   42 #include <sys/limits.h>
   43 
   44 #include <machine/bus.h>
   45 #include <machine/md_var.h>
   46 
   47 #include <dev/iicbus/iicbus.h>
   48 #include <dev/iicbus/iiconf.h>
   49 
   50 #include <dev/ofw/openfirm.h>
   51 #include <dev/ofw/ofw_bus.h>
   52 #include <powerpc/powermac/powermac_thermal.h>
   53 
   54 /* CPU A/B sensors, temp and adc: AD7417. */
   55 
   56 #define AD7417_TEMP         0x00
   57 #define AD7417_CONFIG       0x01
   58 #define AD7417_ADC          0x04
   59 #define AD7417_CONFIG2      0x05
   60 #define AD7417_CONFMASK     0xe0
   61 
   62 uint8_t adc741x_config;
   63 
   64 struct ad7417_sensor {
   65         struct  pmac_therm therm;
   66         device_t dev;
   67         int     id;
   68         enum {
   69                 ADC7417_TEMP_SENSOR,
   70                 ADC7417_ADC_SENSOR
   71         } type;
   72 };
   73 
   74 struct write_data {
   75         uint8_t reg;
   76         uint8_t val;
   77 };
   78 
   79 struct read_data {
   80         uint8_t reg;
   81         uint16_t val;
   82 };
   83 
   84 /* Regular bus attachment functions */
   85 static int ad7417_probe(device_t);
   86 static int ad7417_attach(device_t);
   87 
   88 /* Utility functions */
   89 static int ad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS);
   90 static int ad7417_write(device_t dev, uint32_t addr, uint8_t reg,
   91                         uint8_t *buf, int len);
   92 static int ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg,
   93                          uint8_t *data);
   94 static int ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg,
   95                          uint16_t *data);
   96 static int ad7417_write_read(device_t dev, uint32_t addr,
   97                              struct write_data out, struct read_data *in);
   98 static int ad7417_diode_read(struct ad7417_sensor *sens);
   99 static int ad7417_adc_read(struct ad7417_sensor *sens);
  100 static int ad7417_sensor_read(struct ad7417_sensor *sens);
  101 
  102 struct ad7417_softc {
  103         device_t                sc_dev;
  104         uint32_t                sc_addr;
  105         struct ad7417_sensor    *sc_sensors;
  106         int                     sc_nsensors;
  107 };
  108 static device_method_t  ad7417_methods[] = {
  109         /* Device interface */
  110         DEVMETHOD(device_probe,         ad7417_probe),
  111         DEVMETHOD(device_attach,        ad7417_attach),
  112         { 0, 0 },
  113 };
  114 
  115 static driver_t ad7417_driver = {
  116         "ad7417",
  117         ad7417_methods,
  118         sizeof(struct ad7417_softc)
  119 };
  120 
  121 static devclass_t ad7417_devclass;
  122 
  123 DRIVER_MODULE(ad7417, iicbus, ad7417_driver, ad7417_devclass, 0, 0);
  124 static MALLOC_DEFINE(M_AD7417, "ad7417", "Supply-Monitor AD7417");
  125 
  126 
  127 static int
  128 ad7417_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff, int len)
  129 {
  130         unsigned char buf[4];
  131         int try = 0;
  132 
  133         struct iic_msg msg[] = {
  134                 { addr, IIC_M_WR, 0, buf }
  135         };
  136 
  137         msg[0].len = len + 1;
  138         buf[0] = reg;
  139         memcpy(buf + 1, buff, len);
  140 
  141         for (;;)
  142         {
  143                 if (iicbus_transfer(dev, msg, 1) == 0)
  144                         return (0);
  145 
  146                 if (++try > 5) {
  147                         device_printf(dev, "iicbus write failed\n");
  148                         return (-1);
  149                 }
  150                 pause("ad7417_write", hz);
  151         }
  152 }
  153 
  154 static int
  155 ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data)
  156 {
  157         uint8_t buf[4];
  158         int err, try = 0;
  159 
  160         struct iic_msg msg[2] = {
  161             { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg },
  162             { addr, IIC_M_RD, 1, buf },
  163         };
  164 
  165         for (;;)
  166         {
  167                 err = iicbus_transfer(dev, msg, 2);
  168                 if (err != 0)
  169                         goto retry;
  170 
  171                 *data = *((uint8_t*)buf);
  172                 return (0);
  173         retry:
  174                 if (++try > 5) {
  175                         device_printf(dev, "iicbus read failed\n");
  176                         return (-1);
  177                 }
  178                 pause("ad7417_read_1", hz);
  179         }
  180 }
  181 
  182 static int
  183 ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data)
  184 {
  185         uint8_t buf[4];
  186         int err, try = 0;
  187 
  188         struct iic_msg msg[2] = {
  189             { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg },
  190             { addr, IIC_M_RD, 2, buf },
  191         };
  192 
  193         for (;;)
  194         {
  195                 err = iicbus_transfer(dev, msg, 2);
  196                 if (err != 0)
  197                         goto retry;
  198 
  199                 *data = *((uint16_t*)buf);
  200                 return (0);
  201         retry:
  202                 if (++try > 5) {
  203                         device_printf(dev, "iicbus read failed\n");
  204                         return (-1);
  205                 }
  206                 pause("ad7417_read_2", hz);
  207         }
  208 }
  209 
  210 static int
  211 ad7417_write_read(device_t dev, uint32_t addr, struct write_data out,
  212                   struct read_data *in)
  213 {
  214         uint8_t buf[4];
  215         int err, try = 0;
  216 
  217         /* Do a combined write/read. */
  218         struct iic_msg msg[3] = {
  219             { addr, IIC_M_WR, 2, buf },
  220             { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &in->reg },
  221             { addr, IIC_M_RD, 2, buf },
  222         };
  223 
  224         /* Prepare the write msg. */
  225         buf[0] = out.reg;
  226         buf[1] = out.val & 0xff;
  227 
  228         for (;;)
  229         {
  230                 err = iicbus_transfer(dev, msg, 3);
  231                 if (err != 0)
  232                         goto retry;
  233 
  234                 in->val = *((uint16_t*)buf);
  235                 return (0);
  236         retry:
  237                 if (++try > 5) {
  238                         device_printf(dev, "iicbus write/read failed\n");
  239                         return (-1);
  240                 }
  241                 pause("ad7417_write_read", hz);
  242         }
  243 }
  244 
  245 static int
  246 ad7417_init_adc(device_t dev, uint32_t addr)
  247 {
  248         uint8_t buf;
  249         int err;
  250 
  251         adc741x_config = 0;
  252         /* Clear Config2 */
  253         buf = 0;
  254 
  255         err = ad7417_write(dev, addr, AD7417_CONFIG2, &buf, 1);
  256 
  257          /* Read & cache Config1 */
  258         buf = 0;
  259         err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1);
  260         err = ad7417_read_1(dev, addr, AD7417_CONFIG, &buf);
  261         adc741x_config = (uint8_t)buf;
  262 
  263         /* Disable shutdown mode */
  264         adc741x_config &= 0xfe;
  265         buf = adc741x_config;
  266         err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1);
  267         if (err < 0)
  268                 return (-1);
  269 
  270         return (0);
  271 
  272 }
  273 static int
  274 ad7417_probe(device_t dev)
  275 {
  276         const char  *name, *compatible;
  277         struct ad7417_softc *sc;
  278 
  279         name = ofw_bus_get_name(dev);
  280         compatible = ofw_bus_get_compat(dev);
  281 
  282         if (!name)
  283                 return (ENXIO);
  284 
  285         if (strcmp(name, "supply-monitor") != 0 ||
  286             strcmp(compatible, "ad7417") != 0)
  287                 return (ENXIO);
  288 
  289         sc = device_get_softc(dev);
  290         sc->sc_dev = dev;
  291         sc->sc_addr = iicbus_get_addr(dev);
  292 
  293         device_set_desc(dev, "Supply-Monitor AD7417");
  294 
  295         return (0);
  296 }
  297 
  298 /*
  299  * This function returns the number of sensors. If we call it the second time
  300  * and we have allocated memory for sc->sc_sensors, we fill in the properties.
  301  */
  302 static int
  303 ad7417_fill_sensor_prop(device_t dev)
  304 {
  305         phandle_t child;
  306         struct ad7417_softc *sc;
  307         u_int id[10];
  308         char location[96];
  309         char type[32];
  310         int i = 0, j, len = 0, prop_len, prev_len = 0;
  311 
  312         sc = device_get_softc(dev);
  313 
  314         child = ofw_bus_get_node(dev);
  315 
  316         /* Fill the sensor location property. */
  317         prop_len = OF_getprop(child, "hwsensor-location", location,
  318                               sizeof(location));
  319         while (len < prop_len) {
  320                 if (sc->sc_sensors != NULL)
  321                         strcpy(sc->sc_sensors[i].therm.name, location + len);
  322                 prev_len = strlen(location + len) + 1;
  323                 len += prev_len;
  324                 i++;
  325         }
  326         if (sc->sc_sensors == NULL)
  327                 return (i);
  328 
  329         /* Fill the sensor type property. */
  330         len = 0;
  331         i = 0;
  332         prev_len = 0;
  333         prop_len = OF_getprop(child, "hwsensor-type", type, sizeof(type));
  334         while (len < prop_len) {
  335                 if (strcmp(type + len, "temperature") == 0)
  336                         sc->sc_sensors[i].type = ADC7417_TEMP_SENSOR;
  337                 else
  338                         sc->sc_sensors[i].type = ADC7417_ADC_SENSOR;
  339                 prev_len = strlen(type + len) + 1;
  340                 len += prev_len;
  341                 i++;
  342         }
  343 
  344         /* Fill the sensor id property. Taken from OF. */
  345         prop_len = OF_getprop(child, "hwsensor-id", id, sizeof(id));
  346         for (j = 0; j < i; j++)
  347                 sc->sc_sensors[j].id = id[j];
  348 
  349         /* Fill the sensor zone property. Taken from OF. */
  350         prop_len = OF_getprop(child, "hwsensor-zone", id, sizeof(id));
  351         for (j = 0; j < i; j++)
  352                 sc->sc_sensors[j].therm.zone = id[j];
  353 
  354         /* Finish setting up sensor properties */
  355         for (j = 0; j < i; j++) {
  356                 sc->sc_sensors[j].dev = dev;
  357         
  358                 /* HACK: Apple wired a random diode to the ADC line */
  359                 if (strstr(sc->sc_sensors[j].therm.name, "DIODE TEMP")
  360                     != NULL) {
  361                         sc->sc_sensors[j].type = ADC7417_TEMP_SENSOR;
  362                         sc->sc_sensors[j].therm.read =
  363                             (int (*)(struct pmac_therm *))(ad7417_diode_read);
  364                 } else {
  365                         sc->sc_sensors[j].therm.read =
  366                             (int (*)(struct pmac_therm *))(ad7417_sensor_read);
  367                 }
  368                         
  369                 if (sc->sc_sensors[j].type != ADC7417_TEMP_SENSOR)
  370                         continue;
  371 
  372                 /* Make up some ranges */
  373                 sc->sc_sensors[j].therm.target_temp = 500 + ZERO_C_TO_K;
  374                 sc->sc_sensors[j].therm.max_temp = 900 + ZERO_C_TO_K;
  375                 
  376                 pmac_thermal_sensor_register(&sc->sc_sensors[j].therm);
  377         }
  378 
  379         return (i);
  380 }
  381 
  382 static int
  383 ad7417_attach(device_t dev)
  384 {
  385         struct ad7417_softc *sc;
  386         struct sysctl_oid *oid, *sensroot_oid;
  387         struct sysctl_ctx_list *ctx;
  388         char sysctl_name[32];
  389         int i, j;
  390         const char *unit;
  391         const char *desc;
  392 
  393         sc = device_get_softc(dev);
  394 
  395         sc->sc_nsensors = 0;
  396 
  397         /* Count the actual number of sensors. */
  398         sc->sc_nsensors = ad7417_fill_sensor_prop(dev);
  399 
  400         device_printf(dev, "%d sensors detected.\n", sc->sc_nsensors);
  401 
  402         if (sc->sc_nsensors == 0)
  403                 device_printf(dev, "WARNING: No AD7417 sensors detected!\n");
  404 
  405         sc->sc_sensors = malloc (sc->sc_nsensors * sizeof(struct ad7417_sensor),
  406                                  M_AD7417, M_WAITOK | M_ZERO);
  407 
  408         ctx = device_get_sysctl_ctx(dev);
  409         sensroot_oid = SYSCTL_ADD_NODE(ctx,
  410             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "sensor",
  411             CTLFLAG_RD, 0, "AD7417 Sensor Information");
  412 
  413         /* Now we can fill the properties into the allocated struct. */
  414         sc->sc_nsensors = ad7417_fill_sensor_prop(dev);
  415 
  416         /* Add sysctls for the sensors. */
  417         for (i = 0; i < sc->sc_nsensors; i++) {
  418                 for (j = 0; j < strlen(sc->sc_sensors[i].therm.name); j++) {
  419                         sysctl_name[j] =
  420                             tolower(sc->sc_sensors[i].therm.name[j]);
  421                         if (isspace(sysctl_name[j]))
  422                                 sysctl_name[j] = '_';
  423                 }
  424                 sysctl_name[j] = 0;
  425 
  426                 oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(sensroot_oid),
  427                                       OID_AUTO,
  428                                       sysctl_name, CTLFLAG_RD, 0,
  429                                       "Sensor Information");
  430 
  431                 if (sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR) {
  432                         unit = "temp";
  433                         desc = "Sensor temp in C";
  434                 } else {
  435                         unit = "volt";
  436                         desc = "Sensor Volt in V";
  437                 }
  438                 /* I use i to pass the sensor id. */
  439                 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  440                                 unit, CTLTYPE_INT | CTLFLAG_RD, dev,
  441                                 i, ad7417_sensor_sysctl,
  442                                 sc->sc_sensors[i].type == ADC7417_TEMP_SENSOR ?
  443                                 "IK" : "I", desc);
  444         }
  445         /* Dump sensor location, ID & type. */
  446         if (bootverbose) {
  447                 device_printf(dev, "Sensors\n");
  448                 for (i = 0; i < sc->sc_nsensors; i++) {
  449                         device_printf(dev, "Location: %s ID: %d type: %d\n",
  450                                       sc->sc_sensors[i].therm.name,
  451                                       sc->sc_sensors[i].id,
  452                                       sc->sc_sensors[i].type);
  453                 }
  454         }
  455 
  456         return (0);
  457 }
  458 
  459 static int
  460 ad7417_get_temp(device_t dev, uint32_t addr, int *temp)
  461 {
  462         uint16_t buf[2];
  463         uint16_t read;
  464         int err;
  465 
  466         err = ad7417_read_2(dev, addr, AD7417_TEMP, buf);
  467 
  468         if (err < 0)
  469                 return (-1);
  470 
  471         read = *((int16_t*)buf);
  472 
  473         /* The ADC is 10 bit, the resolution is 0.25 C.
  474            The temperature is in tenth kelvin.
  475         */
  476         *temp = (((int16_t)(read & 0xffc0)) >> 6) * 25 / 10;
  477         return (0);
  478 }
  479 
  480 static int
  481 ad7417_get_adc(device_t dev, uint32_t addr, unsigned int *value,
  482                uint8_t chan)
  483 {
  484         uint8_t tmp;
  485         int err;
  486         struct write_data config;
  487         struct read_data data;
  488 
  489         tmp = chan << 5;
  490         config.reg = AD7417_CONFIG;
  491         data.reg = AD7417_ADC;
  492         data.val = 0;
  493 
  494         err = ad7417_read_1(dev, addr, AD7417_CONFIG, &config.val);
  495 
  496         config.val = (config.val & ~AD7417_CONFMASK) | (tmp & AD7417_CONFMASK);
  497 
  498         err = ad7417_write_read(dev, addr, config, &data);
  499         if (err < 0)
  500                 return (-1);
  501 
  502         *value = ((uint32_t)data.val) >> 6;
  503 
  504         return (0);
  505 }
  506 
  507 static int
  508 ad7417_diode_read(struct ad7417_sensor *sens)
  509 {
  510         static int eeprom_read = 0;
  511         static cell_t eeprom[2][40];
  512         phandle_t eeprom_node;
  513         int rawval, diode_slope, diode_offset;
  514         int temp;
  515 
  516         if (!eeprom_read) {
  517                 eeprom_node = OF_finddevice("/u3/i2c/cpuid@a0");
  518                 OF_getprop(eeprom_node, "cpuid", eeprom[0], sizeof(eeprom[0]));
  519                 eeprom_node = OF_finddevice("/u3/i2c/cpuid@a2");
  520                 OF_getprop(eeprom_node, "cpuid", eeprom[1], sizeof(eeprom[1]));
  521                 eeprom_read = 1;
  522         }
  523 
  524         rawval = ad7417_adc_read(sens);
  525         if (rawval < 0)
  526                 return (-1);
  527 
  528         if (strstr(sens->therm.name, "CPU B") != NULL) {
  529                 diode_slope = eeprom[1][0x11] >> 16;
  530                 diode_offset = (int16_t)(eeprom[1][0x11] & 0xffff) << 12;
  531         } else {
  532                 diode_slope = eeprom[0][0x11] >> 16;
  533                 diode_offset = (int16_t)(eeprom[0][0x11] & 0xffff) << 12;
  534         }
  535 
  536         temp = (rawval*diode_slope + diode_offset) >> 2;
  537         temp = (10*(temp >> 16)) + ((10*(temp & 0xffff)) >> 16);
  538         
  539         return (temp + ZERO_C_TO_K);
  540 }
  541 
  542 static int
  543 ad7417_adc_read(struct ad7417_sensor *sens)
  544 {
  545         struct ad7417_softc *sc;
  546         uint8_t chan;
  547         int temp;
  548 
  549         sc = device_get_softc(sens->dev);
  550 
  551         switch (sens->id) {
  552         case 11:
  553         case 16:
  554                 chan = 1;
  555                 break;
  556         case 12:
  557         case 17:
  558                 chan = 2;
  559                 break;
  560         case 13:
  561         case 18:
  562                 chan = 3;
  563                 break;
  564         case 14:
  565         case 19:
  566                 chan = 4;
  567                 break;
  568         default:
  569                 chan = 1;
  570         }
  571 
  572         if (ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan) < 0)
  573                 return (-1);
  574 
  575         return (temp);
  576 }
  577 
  578 
  579 static int
  580 ad7417_sensor_read(struct ad7417_sensor *sens)
  581 {
  582         struct ad7417_softc *sc;
  583         int temp;
  584 
  585         sc = device_get_softc(sens->dev);
  586 
  587         /* Init the ADC. */
  588         if (ad7417_init_adc(sc->sc_dev, sc->sc_addr) < 0)
  589                 return (-1);
  590 
  591         if (sens->type == ADC7417_TEMP_SENSOR) {
  592                 if (ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp) < 0)
  593                         return (-1);
  594                 temp += ZERO_C_TO_K;
  595         } else {
  596                 temp = ad7417_adc_read(sens);
  597         }
  598         return (temp);
  599 }
  600 
  601 static int
  602 ad7417_sensor_sysctl(SYSCTL_HANDLER_ARGS)
  603 {
  604         device_t dev;
  605         struct ad7417_softc *sc;
  606         struct ad7417_sensor *sens;
  607         int value = 0;
  608         int error;
  609 
  610         dev = arg1;
  611         sc = device_get_softc(dev);
  612         sens = &sc->sc_sensors[arg2];
  613 
  614         value = sens->therm.read(&sens->therm);
  615         if (value < 0)
  616                 return (ENXIO);
  617 
  618         error = sysctl_handle_int(oidp, &value, 0, req);
  619 
  620         return (error);
  621 }

Cache object: 1a03c77de51250c73a8b3d69ec8bda90


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