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/powerpc/powermac/fcu.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 /* FCU registers
   55  * /u3@0,f8000000/i2c@f8001000/fan@15e
   56  */
   57 #define FCU_RPM_FAIL      0x0b      /* fans states in bits 0<1-6>7 */
   58 #define FCU_RPM_AVAILABLE 0x0c
   59 #define FCU_RPM_ACTIVE    0x0d
   60 #define FCU_RPM_READ(x)   0x11 + (x) * 2
   61 #define FCU_RPM_SET(x)    0x10 + (x) * 2
   62 
   63 #define FCU_PWM_FAIL      0x2b
   64 #define FCU_PWM_AVAILABLE 0x2c
   65 #define FCU_PWM_ACTIVE    0x2d
   66 #define FCU_PWM_RPM(x)    0x31 + (x) * 2 /* Get RPM. */
   67 #define FCU_PWM_SGET(x)   0x30 + (x) * 2 /* Set or get PWM. */
   68 
   69 struct fcu_fan {
   70         struct  pmac_fan fan;
   71         device_t dev;
   72 
   73         int     id;
   74         enum {
   75                 FCU_FAN_RPM,
   76                 FCU_FAN_PWM
   77         } type;
   78         int     setpoint;
   79         int     rpm;
   80 };
   81 
   82 struct fcu_softc {
   83         device_t                sc_dev;
   84         struct intr_config_hook enum_hook;
   85         uint32_t                sc_addr;
   86         struct fcu_fan          *sc_fans;
   87         int                     sc_nfans;
   88 };
   89 
   90 /* We can read the PWM and the RPM from a PWM controlled fan.
   91  * Offer both values via sysctl.
   92  */
   93 enum {
   94         FCU_PWM_SYSCTL_PWM   = 1 << 8,
   95         FCU_PWM_SYSCTL_RPM   = 2 << 8
   96 };
   97 
   98 static int fcu_rpm_shift;
   99 
  100 /* Regular bus attachment functions */
  101 static int  fcu_probe(device_t);
  102 static int  fcu_attach(device_t);
  103 
  104 /* Utility functions */
  105 static void fcu_attach_fans(device_t dev);
  106 static int  fcu_fill_fan_prop(device_t dev);
  107 static int  fcu_fan_set_rpm(struct fcu_fan *fan, int rpm);
  108 static int  fcu_fan_get_rpm(struct fcu_fan *fan);
  109 static int  fcu_fan_set_pwm(struct fcu_fan *fan, int pwm);
  110 static int  fcu_fan_get_pwm(device_t dev, struct fcu_fan *fan, int *pwm,
  111                             int *rpm);
  112 static int  fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS);
  113 static void fcu_start(void *xdev);
  114 static int  fcu_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buf,
  115                       int len);
  116 static int  fcu_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data);
  117 
  118 static device_method_t  fcu_methods[] = {
  119         /* Device interface */
  120         DEVMETHOD(device_probe,         fcu_probe),
  121         DEVMETHOD(device_attach,        fcu_attach),
  122         { 0, 0 },
  123 };
  124 
  125 static driver_t fcu_driver = {
  126         "fcu",
  127         fcu_methods,
  128         sizeof(struct fcu_softc)
  129 };
  130 
  131 static devclass_t fcu_devclass;
  132 
  133 DRIVER_MODULE(fcu, iicbus, fcu_driver, fcu_devclass, 0, 0);
  134 static MALLOC_DEFINE(M_FCU, "fcu", "FCU Sensor Information");
  135 
  136 static int
  137 fcu_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff,
  138           int len)
  139 {
  140         unsigned char buf[4];
  141         int try = 0;
  142 
  143         struct iic_msg msg[] = {
  144                 { addr, IIC_M_WR, 0, buf }
  145         };
  146 
  147         msg[0].len = len + 1;
  148         buf[0] = reg;
  149         memcpy(buf + 1, buff, len);
  150 
  151         for (;;)
  152         {
  153                 if (iicbus_transfer(dev, msg, 1) == 0)
  154                         return (0);
  155 
  156                 if (++try > 5) {
  157                         device_printf(dev, "iicbus write failed\n");
  158                         return (-1);
  159                 }
  160                 pause("fcu_write", hz);
  161         }
  162 }
  163 
  164 static int
  165 fcu_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data)
  166 {
  167         uint8_t buf[4];
  168         int err, try = 0;
  169 
  170         struct iic_msg msg[2] = {
  171             { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &reg },
  172             { addr, IIC_M_RD, 1, buf },
  173         };
  174 
  175         for (;;)
  176         {
  177                   err = iicbus_transfer(dev, msg, 2);
  178                   if (err != 0)
  179                           goto retry;
  180 
  181                   *data = *((uint8_t*)buf);
  182                   return (0);
  183         retry:
  184                   if (++try > 5) {
  185                           device_printf(dev, "iicbus read failed\n");
  186                           return (-1);
  187                   }
  188                   pause("fcu_read_1", hz);
  189         }
  190 }
  191 
  192 static int
  193 fcu_probe(device_t dev)
  194 {
  195         const char  *name, *compatible;
  196         struct fcu_softc *sc;
  197 
  198         name = ofw_bus_get_name(dev);
  199         compatible = ofw_bus_get_compat(dev);
  200 
  201         if (!name)
  202                 return (ENXIO);
  203 
  204         if (strcmp(name, "fan") != 0 || strcmp(compatible, "fcu") != 0)
  205                 return (ENXIO);
  206 
  207         sc = device_get_softc(dev);
  208         sc->sc_dev = dev;
  209         sc->sc_addr = iicbus_get_addr(dev);
  210 
  211         device_set_desc(dev, "Apple Fan Control Unit");
  212 
  213         return (0);
  214 }
  215 
  216 static int
  217 fcu_attach(device_t dev)
  218 {
  219         struct fcu_softc *sc;
  220 
  221         sc = device_get_softc(dev);
  222 
  223         sc->enum_hook.ich_func = fcu_start;
  224         sc->enum_hook.ich_arg = dev;
  225 
  226         /* We have to wait until interrupts are enabled. I2C read and write
  227          * only works if the interrupts are available.
  228          * The unin/i2c is controlled by the htpic on unin. But this is not
  229          * the master. The openpic on mac-io is controlling the htpic.
  230          * This one gets attached after the mac-io probing and then the
  231          * interrupts will be available.
  232          */
  233 
  234         if (config_intrhook_establish(&sc->enum_hook) != 0)
  235                 return (ENOMEM);
  236 
  237         return (0);
  238 }
  239 
  240 static void
  241 fcu_start(void *xdev)
  242 {
  243         unsigned char buf[1] = { 0xff };
  244         struct fcu_softc *sc;
  245 
  246         device_t dev = (device_t)xdev;
  247 
  248         sc = device_get_softc(dev);
  249 
  250         /* Start the fcu device. */
  251         fcu_write(sc->sc_dev, sc->sc_addr, 0xe, buf, 1);
  252         fcu_write(sc->sc_dev, sc->sc_addr, 0x2e, buf, 1);
  253         fcu_read_1(sc->sc_dev, sc->sc_addr, 0, buf);
  254         fcu_rpm_shift = (buf[0] == 1) ? 2 : 3;
  255 
  256         device_printf(dev, "FCU initialized, RPM shift: %d\n",
  257                       fcu_rpm_shift);
  258 
  259         /* Detect and attach child devices. */
  260 
  261         fcu_attach_fans(dev);
  262 
  263         config_intrhook_disestablish(&sc->enum_hook);
  264 
  265 }
  266 
  267 static int
  268 fcu_fan_set_rpm(struct fcu_fan *fan, int rpm)
  269 {
  270         uint8_t reg;
  271         struct fcu_softc *sc;
  272         unsigned char buf[2];
  273 
  274         sc = device_get_softc(fan->dev);
  275 
  276         /* Clamp to allowed range */
  277         rpm = max(fan->fan.min_rpm, rpm);
  278         rpm = min(fan->fan.max_rpm, rpm);
  279 
  280         if (fan->type == FCU_FAN_RPM) {
  281                 reg = FCU_RPM_SET(fan->id);
  282                 fan->setpoint = rpm;
  283         } else {
  284                 device_printf(fan->dev, "Unknown fan type: %d\n", fan->type);
  285                 return (ENXIO);
  286         }
  287 
  288         buf[0] = rpm >> (8 - fcu_rpm_shift);
  289         buf[1] = rpm << fcu_rpm_shift;
  290 
  291         if (fcu_write(sc->sc_dev, sc->sc_addr, reg, buf, 2) < 0)
  292                 return (EIO);
  293 
  294         return (0);
  295 }
  296 
  297 static int
  298 fcu_fan_get_rpm(struct fcu_fan *fan)
  299 {
  300         uint8_t reg;
  301         struct fcu_softc *sc;
  302         uint8_t buff[2] = { 0, 0 };
  303         uint8_t active = 0, avail = 0, fail = 0;
  304         int rpm;
  305 
  306         sc = device_get_softc(fan->dev);
  307 
  308         if (fan->type == FCU_FAN_RPM) {
  309                 /* Check if the fan is available. */
  310                 reg = FCU_RPM_AVAILABLE;
  311                 if (fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &avail) < 0)
  312                         return (-1);
  313                 if ((avail & (1 << fan->id)) == 0) {
  314                         device_printf(fan->dev,
  315                             "RPM Fan not available ID: %d\n", fan->id);
  316                         return (-1);
  317                 }
  318                 /* Check if we have a failed fan. */
  319                 reg = FCU_RPM_FAIL;
  320                 if (fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &fail) < 0)
  321                         return (-1);
  322                 if ((fail & (1 << fan->id)) != 0) {
  323                         device_printf(fan->dev,
  324                             "RPM Fan failed ID: %d\n", fan->id);
  325                         return (-1);
  326                 }
  327                 /* Check if fan is active. */
  328                 reg = FCU_RPM_ACTIVE;
  329                 if (fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &active) < 0)
  330                         return (-1);
  331                 if ((active & (1 << fan->id)) == 0) {
  332                         device_printf(fan->dev, "RPM Fan not active ID: %d\n",
  333                                       fan->id);
  334                         return (-1);
  335                 }
  336                 reg = FCU_RPM_READ(fan->id);
  337 
  338         } else {
  339                 device_printf(fan->dev, "Unknown fan type: %d\n", fan->type);
  340                 return (-1);
  341         }
  342 
  343         /* It seems that we can read the fans rpm. */
  344         if (fcu_read_1(sc->sc_dev, sc->sc_addr, reg, buff) < 0)
  345                 return (-1);
  346 
  347         rpm = (buff[0] << (8 - fcu_rpm_shift)) | buff[1] >> fcu_rpm_shift;
  348 
  349         return (rpm);
  350 }
  351 
  352 static int
  353 fcu_fan_set_pwm(struct fcu_fan *fan, int pwm)
  354 {
  355         uint8_t reg;
  356         struct fcu_softc *sc;
  357         uint8_t buf[2];
  358 
  359         sc = device_get_softc(fan->dev);
  360 
  361         /* Clamp to allowed range */
  362         pwm = max(fan->fan.min_rpm, pwm);
  363         pwm = min(fan->fan.max_rpm, pwm);
  364 
  365         if (fan->type == FCU_FAN_PWM) {
  366                 reg = FCU_PWM_SGET(fan->id);
  367                 if (pwm > 100)
  368                         pwm = 100;
  369                 if (pwm < 30)
  370                         pwm = 30;
  371                 fan->setpoint = pwm;
  372         } else {
  373                 device_printf(fan->dev, "Unknown fan type: %d\n", fan->type);
  374                 return (EIO);
  375         }
  376 
  377         buf[0] = (pwm * 2550) / 1000;
  378 
  379         if (fcu_write(sc->sc_dev, sc->sc_addr, reg, buf, 1) < 0)
  380                 return (EIO);
  381         return (0);
  382 }
  383 
  384 static int
  385 fcu_fan_get_pwm(device_t dev, struct fcu_fan *fan, int *pwm, int *rpm)
  386 {
  387         uint8_t reg;
  388         struct fcu_softc *sc;
  389         uint8_t buf[2];
  390         uint8_t active = 0, avail = 0, fail = 0;
  391 
  392         sc = device_get_softc(dev);
  393 
  394         if (fan->type == FCU_FAN_PWM) {
  395                 /* Check if the fan is available. */
  396                 reg = FCU_PWM_AVAILABLE;
  397                 if (fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &avail) < 0)
  398                         return (-1);
  399                 if ((avail & (1 << fan->id)) == 0) {
  400                         device_printf(dev, "PWM Fan not available ID: %d\n",
  401                                       fan->id);
  402                         return (-1);
  403                 }
  404                 /* Check if we have a failed fan. */
  405                 reg = FCU_PWM_FAIL;
  406                 if (fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &fail) < 0)
  407                         return (-1);
  408                 if ((fail & (1 << fan->id)) != 0) {
  409                         device_printf(dev, "PWM Fan failed ID: %d\n", fan->id);
  410                         return (-1);
  411                 }
  412                 /* Check if fan is active. */
  413                 reg = FCU_PWM_ACTIVE;
  414                 if (fcu_read_1(sc->sc_dev, sc->sc_addr, reg, &active) < 0)
  415                         return (-1);
  416                 if ((active & (1 << fan->id)) == 0) {
  417                         device_printf(dev, "PWM Fan not active ID: %d\n",
  418                                       fan->id);
  419                         return (-1);
  420                 }
  421                 reg = FCU_PWM_SGET(fan->id);
  422         } else {
  423                 device_printf(dev, "Unknown fan type: %d\n", fan->type);
  424                 return (EIO);
  425         }
  426 
  427         /* It seems that we can read the fans pwm. */
  428         if (fcu_read_1(sc->sc_dev, sc->sc_addr, reg, buf) < 0)
  429                 return (-1);
  430 
  431         *pwm = (buf[0] * 1000) / 2550;
  432 
  433         /* Now read the rpm. */
  434         reg = FCU_PWM_RPM(fan->id);
  435         if (fcu_read_1(sc->sc_dev, sc->sc_addr, reg, buf) < 0)
  436                 return (-1);
  437 
  438         *rpm = (buf[0] << (8 - fcu_rpm_shift)) | buf[1] >> fcu_rpm_shift;
  439 
  440         return (0);
  441 }
  442 
  443 /*
  444  * This function returns the number of fans. If we call it the second time
  445  * and we have allocated memory for sc->sc_fans, we fill in the properties.
  446  */
  447 static int
  448 fcu_fill_fan_prop(device_t dev)
  449 {
  450         phandle_t child;
  451         struct fcu_softc *sc;
  452         u_int id[8];
  453         char location[96];
  454         char type[64];
  455         int i = 0, j, len = 0, prop_len, prev_len = 0;
  456 
  457         sc = device_get_softc(dev);
  458 
  459         child = ofw_bus_get_node(dev);
  460 
  461         /* Fill the fan location property. */
  462         prop_len = OF_getprop(child, "hwctrl-location", location,
  463                               sizeof(location));
  464         while (len < prop_len) {
  465                 if (sc->sc_fans != NULL) {
  466                         strcpy(sc->sc_fans[i].fan.name, location + len);
  467                 }
  468                 prev_len = strlen(location + len) + 1;
  469                 len += prev_len;
  470                 i++;
  471         }
  472         if (sc->sc_fans == NULL)
  473                 return (i);
  474 
  475         /* Fill the fan type property. */
  476         len = 0;
  477         i = 0;
  478         prev_len = 0;
  479         prop_len = OF_getprop(child, "hwctrl-type", type, sizeof(type));
  480         while (len < prop_len) {
  481                 if (strcmp(type + len, "fan-rpm") == 0)
  482                         sc->sc_fans[i].type = FCU_FAN_RPM;
  483                 else
  484                         sc->sc_fans[i].type = FCU_FAN_PWM;
  485                 prev_len = strlen(type + len) + 1;
  486                 len += prev_len;
  487                 i++;
  488         }
  489 
  490         /* Fill the fan ID property. */
  491         prop_len = OF_getprop(child, "hwctrl-id", id, sizeof(id));
  492         for (j = 0; j < i; j++)
  493                 sc->sc_fans[j].id = ((id[j] >> 8) & 0x0f) % 8;
  494 
  495         /* Fill the fan zone property. */
  496         prop_len = OF_getprop(child, "hwctrl-zone", id, sizeof(id));
  497         for (j = 0; j < i; j++)
  498                 sc->sc_fans[j].fan.zone = id[j];
  499 
  500         /* Finish setting up fan properties */
  501         for (j = 0; j < i; j++) {
  502                 sc->sc_fans[j].dev = sc->sc_dev;
  503                 if (sc->sc_fans[j].type == FCU_FAN_RPM) {
  504                         sc->sc_fans[j].fan.min_rpm = 4800 >> fcu_rpm_shift;
  505                         sc->sc_fans[j].fan.max_rpm = 56000 >> fcu_rpm_shift;
  506                         sc->sc_fans[j].setpoint =
  507                             fcu_fan_get_rpm(&sc->sc_fans[j]);
  508                         sc->sc_fans[j].fan.read = 
  509                             (int (*)(struct pmac_fan *))(fcu_fan_get_rpm);
  510                         sc->sc_fans[j].fan.set =
  511                             (int (*)(struct pmac_fan *, int))(fcu_fan_set_rpm);
  512                 } else {
  513                         sc->sc_fans[j].fan.min_rpm = 30;        /* Percent */
  514                         sc->sc_fans[j].fan.max_rpm = 100;
  515                         sc->sc_fans[j].fan.read = NULL;
  516                         sc->sc_fans[j].fan.set =
  517                             (int (*)(struct pmac_fan *, int))(fcu_fan_set_pwm);
  518                 }
  519                 sc->sc_fans[j].fan.default_rpm = sc->sc_fans[j].fan.max_rpm;
  520         }
  521 
  522         return (i);
  523 }
  524 
  525 static int
  526 fcu_fanrpm_sysctl(SYSCTL_HANDLER_ARGS)
  527 {
  528         device_t fcu;
  529         struct fcu_softc *sc;
  530         struct fcu_fan *fan;
  531         int rpm = 0, pwm = 0, error = 0;
  532 
  533         fcu = arg1;
  534         sc = device_get_softc(fcu);
  535         fan = &sc->sc_fans[arg2 & 0x00ff];
  536         if (fan->type == FCU_FAN_RPM) {
  537                 rpm = fcu_fan_get_rpm(fan);
  538                 if (rpm < 0)
  539                         return (EIO);
  540                 error = sysctl_handle_int(oidp, &rpm, 0, req);
  541         } else {
  542                 error = fcu_fan_get_pwm(fcu, fan, &pwm, &rpm);
  543                 if (error < 0)
  544                         return (EIO);
  545 
  546                 switch (arg2 & 0xff00) {
  547                 case FCU_PWM_SYSCTL_PWM:
  548                         error = sysctl_handle_int(oidp, &pwm, 0, req);
  549                         break;
  550                 case FCU_PWM_SYSCTL_RPM:
  551                         error = sysctl_handle_int(oidp, &rpm, 0, req);
  552                         break;
  553                 default:
  554                         /* This should never happen */
  555                         return (EINVAL);
  556                 };
  557         }
  558 
  559         /* We can only read the RPM from a PWM controlled fan, so return. */
  560         if ((arg2 & 0xff00) == FCU_PWM_SYSCTL_RPM)
  561                 return (0);
  562 
  563         if (error || !req->newptr)
  564                 return (error);
  565 
  566         if (fan->type == FCU_FAN_RPM)
  567                 return (fcu_fan_set_rpm(fan, rpm));
  568         else
  569                 return (fcu_fan_set_pwm(fan, pwm));
  570 }
  571 
  572 static void
  573 fcu_attach_fans(device_t dev)
  574 {
  575         struct fcu_softc *sc;
  576         struct sysctl_oid *oid, *fanroot_oid;
  577         struct sysctl_ctx_list *ctx;
  578         char sysctl_name[32];
  579         int i, j;
  580 
  581         sc = device_get_softc(dev);
  582 
  583         sc->sc_nfans = 0;
  584 
  585         /* Count the actual number of fans. */
  586         sc->sc_nfans = fcu_fill_fan_prop(dev);
  587 
  588         device_printf(dev, "%d fans detected!\n", sc->sc_nfans);
  589 
  590         if (sc->sc_nfans == 0) {
  591                 device_printf(dev, "WARNING: No fans detected!\n");
  592                 return;
  593         }
  594 
  595         sc->sc_fans = malloc(sc->sc_nfans * sizeof(struct fcu_fan), M_FCU,
  596                              M_WAITOK | M_ZERO);
  597 
  598         ctx = device_get_sysctl_ctx(dev);
  599         fanroot_oid = SYSCTL_ADD_NODE(ctx,
  600             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "fans",
  601             CTLFLAG_RD, 0, "FCU Fan Information");
  602 
  603         /* Now we can fill the properties into the allocated struct. */
  604         sc->sc_nfans = fcu_fill_fan_prop(dev);
  605 
  606         /* Register fans with pmac_thermal */
  607         for (i = 0; i < sc->sc_nfans; i++)
  608                 pmac_thermal_fan_register(&sc->sc_fans[i].fan);
  609 
  610         /* Add sysctls for the fans. */
  611         for (i = 0; i < sc->sc_nfans; i++) {
  612                 for (j = 0; j < strlen(sc->sc_fans[i].fan.name); j++) {
  613                         sysctl_name[j] = tolower(sc->sc_fans[i].fan.name[j]);
  614                         if (isspace(sysctl_name[j]))
  615                                 sysctl_name[j] = '_';
  616                 }
  617                 sysctl_name[j] = 0;
  618 
  619                 if (sc->sc_fans[i].type == FCU_FAN_RPM) {
  620                         oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(fanroot_oid),
  621                                               OID_AUTO, sysctl_name,
  622                                               CTLFLAG_RD, 0, "Fan Information");
  623                         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  624                                        "minrpm", CTLFLAG_RD,
  625                                        &(sc->sc_fans[i].fan.min_rpm), 0,
  626                                        "Minimum allowed RPM");
  627                         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  628                                        "maxrpm", CTLFLAG_RD,
  629                                        &(sc->sc_fans[i].fan.max_rpm), 0,
  630                                        "Maximum allowed RPM");
  631                         /* I use i to pass the fan id. */
  632                         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  633                                         "rpm", CTLTYPE_INT | CTLFLAG_RW, dev, i,
  634                                         fcu_fanrpm_sysctl, "I", "Fan RPM");
  635                 } else {
  636                         fcu_fan_get_pwm(dev, &sc->sc_fans[i],
  637                                         &sc->sc_fans[i].setpoint,
  638                                         &sc->sc_fans[i].rpm);
  639 
  640                         oid = SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(fanroot_oid),
  641                                               OID_AUTO, sysctl_name,
  642                                               CTLFLAG_RD, 0, "Fan Information");
  643                         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  644                                        "minpwm", CTLFLAG_RD,
  645                                        &(sc->sc_fans[i].fan.min_rpm), 0,
  646                                        "Minimum allowed PWM in %");
  647                         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  648                                        "maxpwm", CTLFLAG_RD,
  649                                        &(sc->sc_fans[i].fan.max_rpm), 0,
  650                                        "Maximum allowed PWM in %");
  651                         /* I use i to pass the fan id or'ed with the type
  652                          * of info I want to display/modify.
  653                          */
  654                         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  655                                         "pwm", CTLTYPE_INT | CTLFLAG_RW, dev,
  656                                         FCU_PWM_SYSCTL_PWM | i,
  657                                         fcu_fanrpm_sysctl, "I", "Fan PWM in %");
  658                         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  659                                         "rpm", CTLTYPE_INT | CTLFLAG_RD, dev,
  660                                         FCU_PWM_SYSCTL_RPM | i,
  661                                         fcu_fanrpm_sysctl, "I", "Fan RPM");
  662                 }
  663         }
  664 
  665         /* Dump fan location, type & RPM. */
  666         if (bootverbose) {
  667                 device_printf(dev, "Fans\n");
  668                 for (i = 0; i < sc->sc_nfans; i++) {
  669                         device_printf(dev, "Location: %s type: %d ID: %d "
  670                                       "RPM: %d\n", sc->sc_fans[i].fan.name,
  671                                       sc->sc_fans[i].type, sc->sc_fans[i].id,
  672                                       (sc->sc_fans[i].type == FCU_FAN_RPM) ?
  673                                       sc->sc_fans[i].setpoint :
  674                                       sc->sc_fans[i].rpm );
  675             }
  676         }
  677 }

Cache object: 8c94acf95de12413c78486326a8b5247


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