Annotation of sys/scsi/safte.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: safte.c,v 1.37 2007/06/24 05:34:35 dlg Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: #include "bio.h"
! 20:
! 21: #include <sys/param.h>
! 22: #include <sys/systm.h>
! 23: #include <sys/device.h>
! 24: #include <sys/scsiio.h>
! 25: #include <sys/malloc.h>
! 26: #include <sys/proc.h>
! 27: #include <sys/rwlock.h>
! 28: #include <sys/queue.h>
! 29: #include <sys/sensors.h>
! 30:
! 31: #if NBIO > 0
! 32: #include <dev/biovar.h>
! 33: #endif
! 34:
! 35: #include <scsi/scsi_all.h>
! 36: #include <scsi/scsiconf.h>
! 37:
! 38: #include <scsi/safte.h>
! 39:
! 40: #ifdef SAFTE_DEBUG
! 41: #define DPRINTF(x) do { if (safte_debug) printf x ; } while (0)
! 42: int safte_debug = 1;
! 43: #else
! 44: #define DPRINTF(x) /* x */
! 45: #endif
! 46:
! 47:
! 48: int safte_match(struct device *, void *, void *);
! 49: void safte_attach(struct device *, struct device *, void *);
! 50: int safte_detach(struct device *, int);
! 51:
! 52: struct safte_sensor {
! 53: struct ksensor se_sensor;
! 54: enum {
! 55: SAFTE_T_FAN,
! 56: SAFTE_T_PWRSUP,
! 57: SAFTE_T_DOORLOCK,
! 58: SAFTE_T_ALARM,
! 59: SAFTE_T_TEMP
! 60: } se_type;
! 61: u_int8_t *se_field;
! 62: };
! 63:
! 64: struct safte_softc {
! 65: struct device sc_dev;
! 66: struct scsi_link *sc_link;
! 67: struct rwlock sc_lock;
! 68:
! 69: u_int sc_encbuflen;
! 70: u_char *sc_encbuf;
! 71:
! 72: int sc_nsensors;
! 73: struct safte_sensor *sc_sensors;
! 74: struct ksensordev sc_sensordev;
! 75: struct sensor_task *sc_sensortask;
! 76:
! 77: int sc_celsius;
! 78: int sc_ntemps;
! 79: struct safte_sensor *sc_temps;
! 80: u_int16_t *sc_temperrs;
! 81:
! 82: #if NBIO > 0
! 83: int sc_nslots;
! 84: u_int8_t *sc_slots;
! 85: #endif
! 86: };
! 87:
! 88: struct cfattach safte_ca = {
! 89: sizeof(struct safte_softc), safte_match, safte_attach, safte_detach
! 90: };
! 91:
! 92: struct cfdriver safte_cd = {
! 93: NULL, "safte", DV_DULL
! 94: };
! 95:
! 96: #define DEVNAME(s) ((s)->sc_dev.dv_xname)
! 97:
! 98: int safte_read_config(struct safte_softc *);
! 99: void safte_read_encstat(void *);
! 100:
! 101: #if NBIO > 0
! 102: int safte_ioctl(struct device *, u_long, caddr_t);
! 103: int safte_bio_blink(struct safte_softc *, struct bioc_blink *);
! 104: #endif
! 105:
! 106: int64_t safte_temp2uK(u_int8_t, int);
! 107:
! 108: int
! 109: safte_match(struct device *parent, void *match, void *aux)
! 110: {
! 111: struct scsi_attach_args *sa = aux;
! 112: struct scsi_inquiry_data *inq = sa->sa_inqbuf;
! 113: struct scsi_inquiry_data inqbuf;
! 114: struct scsi_inquiry cmd;
! 115: struct safte_inq *si = (struct safte_inq *)&inqbuf.extra;
! 116: int length, flags;
! 117:
! 118: if (inq == NULL)
! 119: return (0);
! 120:
! 121: /* match on dell enclosures */
! 122: if ((inq->device & SID_TYPE) == T_PROCESSOR &&
! 123: SCSISPC(inq->version) == 3)
! 124: return (2);
! 125:
! 126: if ((inq->device & SID_TYPE) != T_PROCESSOR ||
! 127: SCSISPC(inq->version) != 2 ||
! 128: (inq->response_format & SID_ANSII) != 2)
! 129: return (0);
! 130:
! 131: length = inq->additional_length + SAFTE_EXTRA_OFFSET;
! 132: if (length < SAFTE_INQ_LEN)
! 133: return (0);
! 134: if (length > sizeof(inqbuf))
! 135: length = sizeof(inqbuf);
! 136:
! 137: memset(&cmd, 0, sizeof(cmd));
! 138: cmd.opcode = INQUIRY;
! 139: _lto2b(length, cmd.length);
! 140:
! 141: memset(&inqbuf, 0, sizeof(inqbuf));
! 142: memset(&inqbuf.extra, ' ', sizeof(inqbuf.extra));
! 143:
! 144: flags = SCSI_DATA_IN;
! 145: if (cold)
! 146: flags |= SCSI_AUTOCONF;
! 147:
! 148: if (scsi_scsi_cmd(sa->sa_sc_link, (struct scsi_generic *)&cmd,
! 149: sizeof(cmd), (u_char *)&inqbuf, length, 2, 10000, NULL,
! 150: flags) != 0)
! 151: return (0);
! 152:
! 153: if (memcmp(si->ident, SAFTE_IDENT, sizeof(si->ident)) == 0)
! 154: return (2);
! 155:
! 156: return (0);
! 157: }
! 158:
! 159: void
! 160: safte_attach(struct device *parent, struct device *self, void *aux)
! 161: {
! 162: struct safte_softc *sc = (struct safte_softc *)self;
! 163: struct scsi_attach_args *sa = aux;
! 164: int i = 0;
! 165:
! 166: sc->sc_link = sa->sa_sc_link;
! 167: sa->sa_sc_link->device_softc = sc;
! 168: rw_init(&sc->sc_lock, DEVNAME(sc));
! 169:
! 170: printf("\n");
! 171:
! 172: sc->sc_encbuf = NULL;
! 173: sc->sc_nsensors = 0;
! 174: #if NBIO > 0
! 175: sc->sc_nslots = 0;
! 176: #endif
! 177:
! 178: if (safte_read_config(sc) != 0) {
! 179: printf("%s: unable to read enclosure configuration\n",
! 180: DEVNAME(sc));
! 181: return;
! 182: }
! 183:
! 184: if (sc->sc_nsensors > 0) {
! 185: sc->sc_sensortask = sensor_task_register(sc,
! 186: safte_read_encstat, 10);
! 187: if (sc->sc_sensortask == NULL) {
! 188: printf("%s: unable to register update task\n",
! 189: DEVNAME(sc));
! 190: sc->sc_nsensors = sc->sc_ntemps = 0;
! 191: free(sc->sc_sensors, M_DEVBUF);
! 192: } else {
! 193: for (i = 0; i < sc->sc_nsensors; i++)
! 194: sensor_attach(&sc->sc_sensordev,
! 195: &sc->sc_sensors[i].se_sensor);
! 196: sensordev_install(&sc->sc_sensordev);
! 197: }
! 198: }
! 199:
! 200: #if NBIO > 0
! 201: if (sc->sc_nslots > 0 &&
! 202: bio_register(self, safte_ioctl) != 0) {
! 203: printf("%s: unable to register ioctl with bio\n", DEVNAME(sc));
! 204: sc->sc_nslots = 0;
! 205: } else
! 206: i++;
! 207: #endif
! 208:
! 209: if (i) /* if we're doing something, then preinit encbuf and sensors */
! 210: safte_read_encstat(sc);
! 211: else {
! 212: free(sc->sc_encbuf, M_DEVBUF);
! 213: sc->sc_encbuf = NULL;
! 214: }
! 215: }
! 216:
! 217: int
! 218: safte_detach(struct device *self, int flags)
! 219: {
! 220: struct safte_softc *sc = (struct safte_softc *)self;
! 221: int i;
! 222:
! 223: rw_enter_write(&sc->sc_lock);
! 224:
! 225: #if NBIO > 0
! 226: if (sc->sc_nslots > 0)
! 227: bio_unregister(self);
! 228: #endif
! 229:
! 230: if (sc->sc_nsensors > 0) {
! 231: sensordev_deinstall(&sc->sc_sensordev);
! 232: sensor_task_unregister(sc->sc_sensortask);
! 233:
! 234: for (i = 0; i < sc->sc_nsensors; i++)
! 235: sensor_detach(&sc->sc_sensordev,
! 236: &sc->sc_sensors[i].se_sensor);
! 237: free(sc->sc_sensors, M_DEVBUF);
! 238: }
! 239:
! 240: if (sc->sc_encbuf != NULL)
! 241: free(sc->sc_encbuf, M_DEVBUF);
! 242:
! 243: rw_exit_write(&sc->sc_lock);
! 244:
! 245: return (0);
! 246: }
! 247:
! 248: int
! 249: safte_read_config(struct safte_softc *sc)
! 250: {
! 251: struct safte_readbuf_cmd cmd;
! 252: struct safte_config config;
! 253: struct safte_sensor *s;
! 254: int flags, i, j;
! 255:
! 256: memset(&cmd, 0, sizeof(cmd));
! 257: cmd.opcode = READ_BUFFER;
! 258: cmd.flags |= SAFTE_RD_MODE;
! 259: cmd.bufferid = SAFTE_RD_CONFIG;
! 260: cmd.length = htobe16(sizeof(config));
! 261: flags = SCSI_DATA_IN;
! 262: #ifndef SCSIDEBUG
! 263: flags |= SCSI_SILENT;
! 264: #endif
! 265:
! 266: if (cold)
! 267: flags |= SCSI_AUTOCONF;
! 268:
! 269: if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
! 270: sizeof(cmd), (u_char *)&config, sizeof(config), 2, 30000, NULL,
! 271: flags) != 0)
! 272: return (1);
! 273:
! 274: DPRINTF(("%s: nfans: %d npwrsup: %d nslots: %d doorlock: %d ntemps: %d"
! 275: " alarm: %d celsius: %d ntherm: %d\n", DEVNAME(sc), config.nfans,
! 276: config.npwrsup, config.nslots, config.doorlock, config.ntemps,
! 277: config.alarm, SAFTE_CFG_CELSIUS(config.therm),
! 278: SAFTE_CFG_NTHERM(config.therm)));
! 279:
! 280: sc->sc_encbuflen = config.nfans * sizeof(u_int8_t) + /* fan status */
! 281: config.npwrsup * sizeof(u_int8_t) + /* power supply status */
! 282: config.nslots * sizeof(u_int8_t) + /* device scsi id (lun) */
! 283: sizeof(u_int8_t) + /* door lock status */
! 284: sizeof(u_int8_t) + /* speaker status */
! 285: config.ntemps * sizeof(u_int8_t) + /* temp sensors */
! 286: sizeof(u_int16_t); /* temp out of range sensors */
! 287:
! 288: sc->sc_encbuf = malloc(sc->sc_encbuflen, M_DEVBUF, M_NOWAIT);
! 289: if (sc->sc_encbuf == NULL)
! 290: return (1);
! 291:
! 292: sc->sc_nsensors = config.nfans + config.npwrsup + config.ntemps +
! 293: (config.doorlock ? 1 : 0) + (config.alarm ? 1 : 0);
! 294:
! 295: sc->sc_sensors = malloc(sc->sc_nsensors * sizeof(struct safte_sensor),
! 296: M_DEVBUF, M_NOWAIT);
! 297: if (sc->sc_sensors == NULL) {
! 298: free(sc->sc_encbuf, M_DEVBUF);
! 299: sc->sc_encbuf = NULL;
! 300: sc->sc_nsensors = 0;
! 301: return (1);
! 302: }
! 303:
! 304: strlcpy(sc->sc_sensordev.xname, DEVNAME(sc),
! 305: sizeof(sc->sc_sensordev.xname));
! 306:
! 307: memset(sc->sc_sensors, 0,
! 308: sc->sc_nsensors * sizeof(struct safte_sensor));
! 309: s = sc->sc_sensors;
! 310:
! 311: for (i = 0; i < config.nfans; i++) {
! 312: s->se_type = SAFTE_T_FAN;
! 313: s->se_field = (u_int8_t *)(sc->sc_encbuf + i);
! 314: s->se_sensor.type = SENSOR_INDICATOR;
! 315: snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
! 316: "Fan%d", i);
! 317:
! 318: s++;
! 319: }
! 320: j = config.nfans;
! 321:
! 322: for (i = 0; i < config.npwrsup; i++) {
! 323: s->se_type = SAFTE_T_PWRSUP;
! 324: s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
! 325: s->se_sensor.type = SENSOR_INDICATOR;
! 326: snprintf(s->se_sensor.desc, sizeof(s->se_sensor.desc),
! 327: "PSU%d", i);
! 328:
! 329: s++;
! 330: }
! 331: j += config.npwrsup;
! 332:
! 333: #if NBIO > 0
! 334: sc->sc_nslots = config.nslots;
! 335: sc->sc_slots = (u_int8_t *)(sc->sc_encbuf + j);
! 336: #endif
! 337: j += config.nslots;
! 338:
! 339: if (config.doorlock) {
! 340: s->se_type = SAFTE_T_DOORLOCK;
! 341: s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
! 342: s->se_sensor.type = SENSOR_INDICATOR;
! 343: strlcpy(s->se_sensor.desc, "doorlock",
! 344: sizeof(s->se_sensor.desc));
! 345:
! 346: s++;
! 347: }
! 348: j++;
! 349:
! 350: if (config.alarm) {
! 351: s->se_type = SAFTE_T_ALARM;
! 352: s->se_field = (u_int8_t *)(sc->sc_encbuf + j);
! 353: s->se_sensor.type = SENSOR_INDICATOR;
! 354: strlcpy(s->se_sensor.desc, "alarm", sizeof(s->se_sensor.desc));
! 355:
! 356: s++;
! 357: }
! 358: j++;
! 359:
! 360: /*
! 361: * stash the temp info so we can get out of range status. limit the
! 362: * number so the out of temp checks cant go into memory it doesnt own
! 363: */
! 364: sc->sc_ntemps = (config.ntemps > 15) ? 15 : config.ntemps;
! 365: sc->sc_temps = s;
! 366: sc->sc_celsius = SAFTE_CFG_CELSIUS(config.therm);
! 367: for (i = 0; i < config.ntemps; i++) {
! 368: s->se_type = SAFTE_T_TEMP;
! 369: s->se_field = (u_int8_t *)(sc->sc_encbuf + j + i);
! 370: s->se_sensor.type = SENSOR_TEMP;
! 371:
! 372: s++;
! 373: }
! 374: j += config.ntemps;
! 375:
! 376: sc->sc_temperrs = (u_int16_t *)(sc->sc_encbuf + j);
! 377:
! 378: return (0);
! 379: }
! 380:
! 381: void
! 382: safte_read_encstat(void *arg)
! 383: {
! 384: struct safte_softc *sc = (struct safte_softc *)arg;
! 385: struct safte_readbuf_cmd cmd;
! 386: int flags, i;
! 387: struct safte_sensor *s;
! 388: u_int16_t oot;
! 389:
! 390: rw_enter_write(&sc->sc_lock);
! 391:
! 392: memset(&cmd, 0, sizeof(cmd));
! 393: cmd.opcode = READ_BUFFER;
! 394: cmd.flags |= SAFTE_RD_MODE;
! 395: cmd.bufferid = SAFTE_RD_ENCSTAT;
! 396: cmd.length = htobe16(sc->sc_encbuflen);
! 397: flags = SCSI_DATA_IN;
! 398: #ifndef SCSIDEBUG
! 399: flags |= SCSI_SILENT;
! 400: #endif
! 401:
! 402: if (cold)
! 403: flags |= SCSI_AUTOCONF;
! 404:
! 405: if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
! 406: sizeof(cmd), sc->sc_encbuf, sc->sc_encbuflen, 2, 30000, NULL,
! 407: flags) != 0) {
! 408: rw_exit_write(&sc->sc_lock);
! 409: return;
! 410: }
! 411:
! 412: for (i = 0; i < sc->sc_nsensors; i++) {
! 413: s = &sc->sc_sensors[i];
! 414: s->se_sensor.flags &= ~SENSOR_FUNKNOWN;
! 415:
! 416: DPRINTF(("%s: %d type: %d field: 0x%02x\n", DEVNAME(sc), i,
! 417: s->se_type, *s->se_field));
! 418:
! 419: switch (s->se_type) {
! 420: case SAFTE_T_FAN:
! 421: switch (*s->se_field) {
! 422: case SAFTE_FAN_OP:
! 423: s->se_sensor.value = 1;
! 424: s->se_sensor.status = SENSOR_S_OK;
! 425: break;
! 426: case SAFTE_FAN_MF:
! 427: s->se_sensor.value = 0;
! 428: s->se_sensor.status = SENSOR_S_CRIT;
! 429: break;
! 430: case SAFTE_FAN_NOTINST:
! 431: case SAFTE_FAN_UNKNOWN:
! 432: default:
! 433: s->se_sensor.value = 0;
! 434: s->se_sensor.status = SENSOR_S_UNKNOWN;
! 435: s->se_sensor.flags |= SENSOR_FUNKNOWN;
! 436: break;
! 437: }
! 438: break;
! 439:
! 440: case SAFTE_T_PWRSUP:
! 441: switch (*s->se_field) {
! 442: case SAFTE_PWR_OP_ON:
! 443: s->se_sensor.value = 1;
! 444: s->se_sensor.status = SENSOR_S_OK;
! 445: break;
! 446: case SAFTE_PWR_OP_OFF:
! 447: s->se_sensor.value = 0;
! 448: s->se_sensor.status = SENSOR_S_OK;
! 449: break;
! 450: case SAFTE_PWR_MF_ON:
! 451: s->se_sensor.value = 1;
! 452: s->se_sensor.status = SENSOR_S_CRIT;
! 453: break;
! 454: case SAFTE_PWR_MF_OFF:
! 455: s->se_sensor.value = 0;
! 456: s->se_sensor.status = SENSOR_S_CRIT;
! 457: break;
! 458: case SAFTE_PWR_NOTINST:
! 459: case SAFTE_PWR_PRESENT:
! 460: case SAFTE_PWR_UNKNOWN:
! 461: s->se_sensor.value = 0;
! 462: s->se_sensor.status = SENSOR_S_UNKNOWN;
! 463: s->se_sensor.flags |= SENSOR_FUNKNOWN;
! 464: break;
! 465: }
! 466: break;
! 467:
! 468: case SAFTE_T_DOORLOCK:
! 469: switch (*s->se_field) {
! 470: case SAFTE_DOOR_LOCKED:
! 471: s->se_sensor.value = 1;
! 472: s->se_sensor.status = SENSOR_S_OK;
! 473: break;
! 474: case SAFTE_DOOR_UNLOCKED:
! 475: s->se_sensor.value = 0;
! 476: s->se_sensor.status = SENSOR_S_CRIT;
! 477: break;
! 478: case SAFTE_DOOR_UNKNOWN:
! 479: s->se_sensor.value = 0;
! 480: s->se_sensor.status = SENSOR_S_CRIT;
! 481: s->se_sensor.flags |= SENSOR_FUNKNOWN;
! 482: break;
! 483: }
! 484: break;
! 485:
! 486: case SAFTE_T_ALARM:
! 487: switch (*s->se_field) {
! 488: case SAFTE_SPKR_OFF:
! 489: s->se_sensor.value = 0;
! 490: s->se_sensor.status = SENSOR_S_OK;
! 491: break;
! 492: case SAFTE_SPKR_ON:
! 493: s->se_sensor.value = 1;
! 494: s->se_sensor.status = SENSOR_S_CRIT;
! 495: break;
! 496: }
! 497: break;
! 498:
! 499: case SAFTE_T_TEMP:
! 500: s->se_sensor.value = safte_temp2uK(*s->se_field,
! 501: sc->sc_celsius);
! 502: break;
! 503: }
! 504: }
! 505:
! 506: oot = betoh16(*sc->sc_temperrs);
! 507: for (i = 0; i < sc->sc_ntemps; i++)
! 508: sc->sc_temps[i].se_sensor.status =
! 509: (oot & (1 << i)) ? SENSOR_S_CRIT : SENSOR_S_OK;
! 510:
! 511: rw_exit_write(&sc->sc_lock);
! 512: }
! 513:
! 514: #if NBIO > 0
! 515: int
! 516: safte_ioctl(struct device *dev, u_long cmd, caddr_t addr)
! 517: {
! 518: struct safte_softc *sc = (struct safte_softc *)dev;
! 519: int error = 0;
! 520:
! 521: switch (cmd) {
! 522: case BIOCBLINK:
! 523: error = safte_bio_blink(sc, (struct bioc_blink *)addr);
! 524: break;
! 525:
! 526: default:
! 527: error = EINVAL;
! 528: break;
! 529: }
! 530:
! 531: return (error);
! 532: }
! 533:
! 534: int
! 535: safte_bio_blink(struct safte_softc *sc, struct bioc_blink *blink)
! 536: {
! 537: struct safte_writebuf_cmd cmd;
! 538: struct safte_slotop *op;
! 539: int slot;
! 540: int flags;
! 541: int wantblink;
! 542:
! 543: switch (blink->bb_status) {
! 544: case BIOC_SBBLINK:
! 545: wantblink = 1;
! 546: break;
! 547: case BIOC_SBUNBLINK:
! 548: wantblink = 0;
! 549: break;
! 550: default:
! 551: return (EINVAL);
! 552: }
! 553:
! 554: rw_enter_read(&sc->sc_lock);
! 555: for (slot = 0; slot < sc->sc_nslots; slot++) {
! 556: if (sc->sc_slots[slot] == blink->bb_target)
! 557: break;
! 558: }
! 559: rw_exit_read(&sc->sc_lock);
! 560:
! 561: if (slot >= sc->sc_nslots)
! 562: return (ENODEV);
! 563:
! 564: op = malloc(sizeof(struct safte_slotop), M_TEMP, 0);
! 565:
! 566: memset(op, 0, sizeof(struct safte_slotop));
! 567: op->opcode = SAFTE_WRITE_SLOTOP;
! 568: op->slot = slot;
! 569: op->flags |= wantblink ? SAFTE_SLOTOP_IDENTIFY : 0;
! 570:
! 571: memset(&cmd, 0, sizeof(cmd));
! 572: cmd.opcode = WRITE_BUFFER;
! 573: cmd.flags |= SAFTE_WR_MODE;
! 574: cmd.length = htobe16(sizeof(struct safte_slotop));
! 575: flags = SCSI_DATA_OUT;
! 576: #ifndef SCSIDEBUG
! 577: flags |= SCSI_SILENT;
! 578: #endif
! 579: if (cold)
! 580: flags |= SCSI_AUTOCONF;
! 581:
! 582: if (scsi_scsi_cmd(sc->sc_link, (struct scsi_generic *)&cmd,
! 583: sizeof(cmd), (u_char *)op, sizeof(struct safte_slotop),
! 584: 2, 30000, NULL, flags) != 0) {
! 585: free(op, M_TEMP);
! 586: return (EIO);
! 587: }
! 588:
! 589: free(op, M_TEMP);
! 590:
! 591: return (0);
! 592: }
! 593: #endif /* NBIO > 0 */
! 594:
! 595: int64_t
! 596: safte_temp2uK(u_int8_t measured, int celsius)
! 597: {
! 598: int64_t temp;
! 599:
! 600: temp = (int64_t)measured;
! 601: temp += SAFTE_TEMP_OFFSET;
! 602: temp *= 1000000; /* convert to micro (mu) degrees */
! 603: if (!celsius)
! 604: temp = ((temp - 32000000) * 5) / 9; /* convert to Celsius */
! 605:
! 606: temp += 273150000; /* convert to kelvin */
! 607:
! 608: return (temp);
! 609: }
CVSweb