1 /* 2 * QEMU SMBus device emulation. 3 * 4 * This code is a helper for SMBus device emulation. It implements an 5 * I2C device inteface and runs the SMBus protocol from the device 6 * point of view and maps those to simple calls to emulate. 7 * 8 * Copyright (c) 2007 CodeSourcery. 9 * Written by Paul Brook 10 * 11 * This code is licensed under the LGPL. 12 */ 13 14 /* TODO: Implement PEC. */ 15 16 #include "qemu/osdep.h" 17 #include "hw/hw.h" 18 #include "hw/i2c/i2c.h" 19 #include "hw/i2c/smbus_slave.h" 20 21 //#define DEBUG_SMBUS 1 22 23 #ifdef DEBUG_SMBUS 24 #define DPRINTF(fmt, ...) \ 25 do { printf("smbus(%02x): " fmt , dev->i2c.address, ## __VA_ARGS__); } while (0) 26 #define BADF(fmt, ...) \ 27 do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__); exit(1);} while (0) 28 #else 29 #define DPRINTF(fmt, ...) do {} while(0) 30 #define BADF(fmt, ...) \ 31 do { fprintf(stderr, "smbus: error: " fmt , ## __VA_ARGS__);} while (0) 32 #endif 33 34 enum { 35 SMBUS_IDLE, 36 SMBUS_WRITE_DATA, 37 SMBUS_READ_DATA, 38 SMBUS_DONE, 39 SMBUS_CONFUSED = -1 40 }; 41 42 static void smbus_do_quick_cmd(SMBusDevice *dev, int recv) 43 { 44 SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); 45 46 DPRINTF("Quick Command %d\n", recv); 47 if (sc->quick_cmd) { 48 sc->quick_cmd(dev, recv); 49 } 50 } 51 52 static void smbus_do_write(SMBusDevice *dev) 53 { 54 SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); 55 56 DPRINTF("Command %d len %d\n", dev->data_buf[0], dev->data_len); 57 if (sc->write_data) { 58 sc->write_data(dev, dev->data_buf, dev->data_len); 59 } 60 } 61 62 static int smbus_i2c_event(I2CSlave *s, enum i2c_event event) 63 { 64 SMBusDevice *dev = SMBUS_DEVICE(s); 65 66 switch (event) { 67 case I2C_START_SEND: 68 switch (dev->mode) { 69 case SMBUS_IDLE: 70 DPRINTF("Incoming data\n"); 71 dev->mode = SMBUS_WRITE_DATA; 72 break; 73 default: 74 BADF("Unexpected send start condition in state %d\n", dev->mode); 75 dev->mode = SMBUS_CONFUSED; 76 break; 77 } 78 break; 79 80 case I2C_START_RECV: 81 switch (dev->mode) { 82 case SMBUS_IDLE: 83 DPRINTF("Read mode\n"); 84 dev->mode = SMBUS_READ_DATA; 85 break; 86 case SMBUS_WRITE_DATA: 87 if (dev->data_len == 0) { 88 BADF("Read after write with no data\n"); 89 dev->mode = SMBUS_CONFUSED; 90 } else { 91 smbus_do_write(dev); 92 DPRINTF("Read mode\n"); 93 dev->mode = SMBUS_READ_DATA; 94 } 95 break; 96 default: 97 BADF("Unexpected recv start condition in state %d\n", dev->mode); 98 dev->mode = SMBUS_CONFUSED; 99 break; 100 } 101 break; 102 103 case I2C_FINISH: 104 if (dev->data_len == 0) { 105 if (dev->mode == SMBUS_WRITE_DATA || dev->mode == SMBUS_READ_DATA) { 106 smbus_do_quick_cmd(dev, dev->mode == SMBUS_READ_DATA); 107 } 108 } else { 109 switch (dev->mode) { 110 case SMBUS_WRITE_DATA: 111 smbus_do_write(dev); 112 break; 113 114 case SMBUS_READ_DATA: 115 BADF("Unexpected stop during receive\n"); 116 break; 117 118 default: 119 /* Nothing to do. */ 120 break; 121 } 122 } 123 dev->mode = SMBUS_IDLE; 124 dev->data_len = 0; 125 break; 126 127 case I2C_NACK: 128 switch (dev->mode) { 129 case SMBUS_DONE: 130 /* Nothing to do. */ 131 break; 132 case SMBUS_READ_DATA: 133 dev->mode = SMBUS_DONE; 134 break; 135 default: 136 BADF("Unexpected NACK in state %d\n", dev->mode); 137 dev->mode = SMBUS_CONFUSED; 138 break; 139 } 140 } 141 142 return 0; 143 } 144 145 static uint8_t smbus_i2c_recv(I2CSlave *s) 146 { 147 SMBusDevice *dev = SMBUS_DEVICE(s); 148 SMBusDeviceClass *sc = SMBUS_DEVICE_GET_CLASS(dev); 149 uint8_t ret = 0xff; 150 151 switch (dev->mode) { 152 case SMBUS_READ_DATA: 153 if (sc->receive_byte) { 154 ret = sc->receive_byte(dev); 155 } 156 DPRINTF("Read data %02x\n", ret); 157 break; 158 default: 159 BADF("Unexpected read in state %d\n", dev->mode); 160 dev->mode = SMBUS_CONFUSED; 161 break; 162 } 163 return ret; 164 } 165 166 static int smbus_i2c_send(I2CSlave *s, uint8_t data) 167 { 168 SMBusDevice *dev = SMBUS_DEVICE(s); 169 170 switch (dev->mode) { 171 case SMBUS_WRITE_DATA: 172 DPRINTF("Write data %02x\n", data); 173 if (dev->data_len >= sizeof(dev->data_buf)) { 174 BADF("Too many bytes sent\n"); 175 } else { 176 dev->data_buf[dev->data_len++] = data; 177 } 178 break; 179 default: 180 BADF("Unexpected write in state %d\n", dev->mode); 181 break; 182 } 183 return 0; 184 } 185 186 static void smbus_device_class_init(ObjectClass *klass, void *data) 187 { 188 I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass); 189 190 sc->event = smbus_i2c_event; 191 sc->recv = smbus_i2c_recv; 192 sc->send = smbus_i2c_send; 193 } 194 195 static const TypeInfo smbus_device_type_info = { 196 .name = TYPE_SMBUS_DEVICE, 197 .parent = TYPE_I2C_SLAVE, 198 .instance_size = sizeof(SMBusDevice), 199 .abstract = true, 200 .class_size = sizeof(SMBusDeviceClass), 201 .class_init = smbus_device_class_init, 202 }; 203 204 static void smbus_device_register_types(void) 205 { 206 type_register_static(&smbus_device_type_info); 207 } 208 209 type_init(smbus_device_register_types) 210