qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio
at master 398 lines 11 kB view raw
1/* 2 * Texas Instruments TMP421 temperature sensor. 3 * 4 * Copyright (c) 2016 IBM Corporation. 5 * 6 * Largely inspired by : 7 * 8 * Texas Instruments TMP105 temperature sensor. 9 * 10 * Copyright (C) 2008 Nokia Corporation 11 * Written by Andrzej Zaborowski <andrew@openedhand.com> 12 * 13 * This program is free software; you can redistribute it and/or 14 * modify it under the terms of the GNU General Public License as 15 * published by the Free Software Foundation; either version 2 or 16 * (at your option) version 3 of the License. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License along 24 * with this program; if not, see <http://www.gnu.org/licenses/>. 25 */ 26 27#include "qemu/osdep.h" 28#include "hw/i2c/i2c.h" 29#include "migration/vmstate.h" 30#include "qapi/error.h" 31#include "qapi/visitor.h" 32#include "qemu/module.h" 33 34/* Manufacturer / Device ID's */ 35#define TMP421_MANUFACTURER_ID 0x55 36#define TMP421_DEVICE_ID 0x21 37#define TMP422_DEVICE_ID 0x22 38#define TMP423_DEVICE_ID 0x23 39 40typedef struct DeviceInfo { 41 int model; 42 const char *name; 43} DeviceInfo; 44 45static const DeviceInfo devices[] = { 46 { TMP421_DEVICE_ID, "tmp421" }, 47 { TMP422_DEVICE_ID, "tmp422" }, 48 { TMP423_DEVICE_ID, "tmp423" }, 49}; 50 51typedef struct TMP421State { 52 /*< private >*/ 53 I2CSlave i2c; 54 /*< public >*/ 55 56 int16_t temperature[4]; 57 58 uint8_t status; 59 uint8_t config[2]; 60 uint8_t rate; 61 62 uint8_t len; 63 uint8_t buf[2]; 64 uint8_t pointer; 65 66} TMP421State; 67 68typedef struct TMP421Class { 69 I2CSlaveClass parent_class; 70 DeviceInfo *dev; 71} TMP421Class; 72 73#define TYPE_TMP421 "tmp421-generic" 74#define TMP421(obj) OBJECT_CHECK(TMP421State, (obj), TYPE_TMP421) 75 76#define TMP421_CLASS(klass) \ 77 OBJECT_CLASS_CHECK(TMP421Class, (klass), TYPE_TMP421) 78#define TMP421_GET_CLASS(obj) \ 79 OBJECT_GET_CLASS(TMP421Class, (obj), TYPE_TMP421) 80 81/* the TMP421 registers */ 82#define TMP421_STATUS_REG 0x08 83#define TMP421_STATUS_BUSY (1 << 7) 84#define TMP421_CONFIG_REG_1 0x09 85#define TMP421_CONFIG_RANGE (1 << 2) 86#define TMP421_CONFIG_SHUTDOWN (1 << 6) 87#define TMP421_CONFIG_REG_2 0x0A 88#define TMP421_CONFIG_RC (1 << 2) 89#define TMP421_CONFIG_LEN (1 << 3) 90#define TMP421_CONFIG_REN (1 << 4) 91#define TMP421_CONFIG_REN2 (1 << 5) 92#define TMP421_CONFIG_REN3 (1 << 6) 93 94#define TMP421_CONVERSION_RATE_REG 0x0B 95#define TMP421_ONE_SHOT 0x0F 96 97#define TMP421_RESET 0xFC 98#define TMP421_MANUFACTURER_ID_REG 0xFE 99#define TMP421_DEVICE_ID_REG 0xFF 100 101#define TMP421_TEMP_MSB0 0x00 102#define TMP421_TEMP_MSB1 0x01 103#define TMP421_TEMP_MSB2 0x02 104#define TMP421_TEMP_MSB3 0x03 105#define TMP421_TEMP_LSB0 0x10 106#define TMP421_TEMP_LSB1 0x11 107#define TMP421_TEMP_LSB2 0x12 108#define TMP421_TEMP_LSB3 0x13 109 110static const int32_t mins[2] = { -40000, -55000 }; 111static const int32_t maxs[2] = { 127000, 150000 }; 112 113static void tmp421_get_temperature(Object *obj, Visitor *v, const char *name, 114 void *opaque, Error **errp) 115{ 116 TMP421State *s = TMP421(obj); 117 bool ext_range = (s->config[0] & TMP421_CONFIG_RANGE); 118 int offset = ext_range * 64 * 256; 119 int64_t value; 120 int tempid; 121 122 if (sscanf(name, "temperature%d", &tempid) != 1) { 123 error_setg(errp, "error reading %s: %s", name, g_strerror(errno)); 124 return; 125 } 126 127 if (tempid >= 4 || tempid < 0) { 128 error_setg(errp, "error reading %s", name); 129 return; 130 } 131 132 value = ((s->temperature[tempid] - offset) * 1000 + 128) / 256; 133 134 visit_type_int(v, name, &value, errp); 135} 136 137/* Units are 0.001 centigrades relative to 0 C. s->temperature is 8.8 138 * fixed point, so units are 1/256 centigrades. A simple ratio will do. 139 */ 140static void tmp421_set_temperature(Object *obj, Visitor *v, const char *name, 141 void *opaque, Error **errp) 142{ 143 TMP421State *s = TMP421(obj); 144 int64_t temp; 145 bool ext_range = (s->config[0] & TMP421_CONFIG_RANGE); 146 int offset = ext_range * 64 * 256; 147 int tempid; 148 149 if (!visit_type_int(v, name, &temp, errp)) { 150 return; 151 } 152 153 if (temp >= maxs[ext_range] || temp < mins[ext_range]) { 154 error_setg(errp, "value %" PRId64 ".%03" PRIu64 " C is out of range", 155 temp / 1000, temp % 1000); 156 return; 157 } 158 159 if (sscanf(name, "temperature%d", &tempid) != 1) { 160 error_setg(errp, "error reading %s: %s", name, g_strerror(errno)); 161 return; 162 } 163 164 if (tempid >= 4 || tempid < 0) { 165 error_setg(errp, "error reading %s", name); 166 return; 167 } 168 169 s->temperature[tempid] = (int16_t) ((temp * 256 - 128) / 1000) + offset; 170} 171 172static void tmp421_read(TMP421State *s) 173{ 174 TMP421Class *sc = TMP421_GET_CLASS(s); 175 176 s->len = 0; 177 178 switch (s->pointer) { 179 case TMP421_MANUFACTURER_ID_REG: 180 s->buf[s->len++] = TMP421_MANUFACTURER_ID; 181 break; 182 case TMP421_DEVICE_ID_REG: 183 s->buf[s->len++] = sc->dev->model; 184 break; 185 case TMP421_CONFIG_REG_1: 186 s->buf[s->len++] = s->config[0]; 187 break; 188 case TMP421_CONFIG_REG_2: 189 s->buf[s->len++] = s->config[1]; 190 break; 191 case TMP421_CONVERSION_RATE_REG: 192 s->buf[s->len++] = s->rate; 193 break; 194 case TMP421_STATUS_REG: 195 s->buf[s->len++] = s->status; 196 break; 197 198 /* FIXME: check for channel enablement in config registers */ 199 case TMP421_TEMP_MSB0: 200 s->buf[s->len++] = (((uint16_t) s->temperature[0]) >> 8); 201 s->buf[s->len++] = (((uint16_t) s->temperature[0]) >> 0) & 0xf0; 202 break; 203 case TMP421_TEMP_MSB1: 204 s->buf[s->len++] = (((uint16_t) s->temperature[1]) >> 8); 205 s->buf[s->len++] = (((uint16_t) s->temperature[1]) >> 0) & 0xf0; 206 break; 207 case TMP421_TEMP_MSB2: 208 s->buf[s->len++] = (((uint16_t) s->temperature[2]) >> 8); 209 s->buf[s->len++] = (((uint16_t) s->temperature[2]) >> 0) & 0xf0; 210 break; 211 case TMP421_TEMP_MSB3: 212 s->buf[s->len++] = (((uint16_t) s->temperature[3]) >> 8); 213 s->buf[s->len++] = (((uint16_t) s->temperature[3]) >> 0) & 0xf0; 214 break; 215 case TMP421_TEMP_LSB0: 216 s->buf[s->len++] = (((uint16_t) s->temperature[0]) >> 0) & 0xf0; 217 break; 218 case TMP421_TEMP_LSB1: 219 s->buf[s->len++] = (((uint16_t) s->temperature[1]) >> 0) & 0xf0; 220 break; 221 case TMP421_TEMP_LSB2: 222 s->buf[s->len++] = (((uint16_t) s->temperature[2]) >> 0) & 0xf0; 223 break; 224 case TMP421_TEMP_LSB3: 225 s->buf[s->len++] = (((uint16_t) s->temperature[3]) >> 0) & 0xf0; 226 break; 227 } 228} 229 230static void tmp421_reset(I2CSlave *i2c); 231 232static void tmp421_write(TMP421State *s) 233{ 234 switch (s->pointer) { 235 case TMP421_CONVERSION_RATE_REG: 236 s->rate = s->buf[0]; 237 break; 238 case TMP421_CONFIG_REG_1: 239 s->config[0] = s->buf[0]; 240 break; 241 case TMP421_CONFIG_REG_2: 242 s->config[1] = s->buf[0]; 243 break; 244 case TMP421_RESET: 245 tmp421_reset(I2C_SLAVE(s)); 246 break; 247 } 248} 249 250static uint8_t tmp421_rx(I2CSlave *i2c) 251{ 252 TMP421State *s = TMP421(i2c); 253 254 if (s->len < 2) { 255 return s->buf[s->len++]; 256 } else { 257 return 0xff; 258 } 259} 260 261static int tmp421_tx(I2CSlave *i2c, uint8_t data) 262{ 263 TMP421State *s = TMP421(i2c); 264 265 if (s->len == 0) { 266 /* first byte is the register pointer for a read or write 267 * operation */ 268 s->pointer = data; 269 s->len++; 270 } else if (s->len == 1) { 271 /* second byte is the data to write. The device only supports 272 * one byte writes */ 273 s->buf[0] = data; 274 tmp421_write(s); 275 } 276 277 return 0; 278} 279 280static int tmp421_event(I2CSlave *i2c, enum i2c_event event) 281{ 282 TMP421State *s = TMP421(i2c); 283 284 if (event == I2C_START_RECV) { 285 tmp421_read(s); 286 } 287 288 s->len = 0; 289 return 0; 290} 291 292static const VMStateDescription vmstate_tmp421 = { 293 .name = "TMP421", 294 .version_id = 0, 295 .minimum_version_id = 0, 296 .fields = (VMStateField[]) { 297 VMSTATE_UINT8(len, TMP421State), 298 VMSTATE_UINT8_ARRAY(buf, TMP421State, 2), 299 VMSTATE_UINT8(pointer, TMP421State), 300 VMSTATE_UINT8_ARRAY(config, TMP421State, 2), 301 VMSTATE_UINT8(status, TMP421State), 302 VMSTATE_UINT8(rate, TMP421State), 303 VMSTATE_INT16_ARRAY(temperature, TMP421State, 4), 304 VMSTATE_I2C_SLAVE(i2c, TMP421State), 305 VMSTATE_END_OF_LIST() 306 } 307}; 308 309static void tmp421_reset(I2CSlave *i2c) 310{ 311 TMP421State *s = TMP421(i2c); 312 TMP421Class *sc = TMP421_GET_CLASS(s); 313 314 memset(s->temperature, 0, sizeof(s->temperature)); 315 s->pointer = 0; 316 317 s->config[0] = 0; /* TMP421_CONFIG_RANGE */ 318 319 /* resistance correction and channel enablement */ 320 switch (sc->dev->model) { 321 case TMP421_DEVICE_ID: 322 s->config[1] = 0x1c; 323 break; 324 case TMP422_DEVICE_ID: 325 s->config[1] = 0x3c; 326 break; 327 case TMP423_DEVICE_ID: 328 s->config[1] = 0x7c; 329 break; 330 } 331 332 s->rate = 0x7; /* 8Hz */ 333 s->status = 0; 334} 335 336static void tmp421_realize(DeviceState *dev, Error **errp) 337{ 338 TMP421State *s = TMP421(dev); 339 340 tmp421_reset(&s->i2c); 341} 342 343static void tmp421_initfn(Object *obj) 344{ 345 object_property_add(obj, "temperature0", "int", 346 tmp421_get_temperature, 347 tmp421_set_temperature, NULL, NULL); 348 object_property_add(obj, "temperature1", "int", 349 tmp421_get_temperature, 350 tmp421_set_temperature, NULL, NULL); 351 object_property_add(obj, "temperature2", "int", 352 tmp421_get_temperature, 353 tmp421_set_temperature, NULL, NULL); 354 object_property_add(obj, "temperature3", "int", 355 tmp421_get_temperature, 356 tmp421_set_temperature, NULL, NULL); 357} 358 359static void tmp421_class_init(ObjectClass *klass, void *data) 360{ 361 DeviceClass *dc = DEVICE_CLASS(klass); 362 I2CSlaveClass *k = I2C_SLAVE_CLASS(klass); 363 TMP421Class *sc = TMP421_CLASS(klass); 364 365 dc->realize = tmp421_realize; 366 k->event = tmp421_event; 367 k->recv = tmp421_rx; 368 k->send = tmp421_tx; 369 dc->vmsd = &vmstate_tmp421; 370 sc->dev = (DeviceInfo *) data; 371} 372 373static const TypeInfo tmp421_info = { 374 .name = TYPE_TMP421, 375 .parent = TYPE_I2C_SLAVE, 376 .instance_size = sizeof(TMP421State), 377 .class_size = sizeof(TMP421Class), 378 .instance_init = tmp421_initfn, 379 .abstract = true, 380}; 381 382static void tmp421_register_types(void) 383{ 384 int i; 385 386 type_register_static(&tmp421_info); 387 for (i = 0; i < ARRAY_SIZE(devices); ++i) { 388 TypeInfo ti = { 389 .name = devices[i].name, 390 .parent = TYPE_TMP421, 391 .class_init = tmp421_class_init, 392 .class_data = (void *) &devices[i], 393 }; 394 type_register(&ti); 395 } 396} 397 398type_init(tmp421_register_types)