Revision 02e2da45 hw/i2c.c
b/hw/i2c.c | ||
---|---|---|
11 | 11 |
|
12 | 12 |
struct i2c_bus |
13 | 13 |
{ |
14 |
BusState qbus; |
|
14 | 15 |
i2c_slave *current_dev; |
15 | 16 |
i2c_slave *dev; |
16 | 17 |
int saved_address; |
... | ... | |
39 | 40 |
} |
40 | 41 |
|
41 | 42 |
/* Create a new I2C bus. */ |
42 |
i2c_bus *i2c_init_bus(void)
|
|
43 |
i2c_bus *i2c_init_bus(DeviceState *parent, const char *name)
|
|
43 | 44 |
{ |
44 | 45 |
i2c_bus *bus; |
45 | 46 |
|
46 |
bus = (i2c_bus *)qemu_mallocz(sizeof(i2c_bus)); |
|
47 |
bus = FROM_QBUS(i2c_bus, qbus_create(BUS_TYPE_I2C, sizeof(i2c_bus), |
|
48 |
parent, name)); |
|
47 | 49 |
register_savevm("i2c_bus", -1, 1, i2c_bus_save, i2c_bus_load, bus); |
48 | 50 |
return bus; |
49 | 51 |
} |
... | ... | |
63 | 65 |
/* TODO: Make this handle multiple masters. */ |
64 | 66 |
int i2c_start_transfer(i2c_bus *bus, int address, int recv) |
65 | 67 |
{ |
66 |
i2c_slave *dev; |
|
68 |
DeviceState *qdev; |
|
69 |
i2c_slave *slave = NULL; |
|
67 | 70 |
|
68 |
for (dev = bus->dev; dev; dev = dev->next) { |
|
69 |
if (dev->address == address) |
|
71 |
LIST_FOREACH(qdev, &bus->qbus.children, sibling) { |
|
72 |
slave = I2C_SLAVE_FROM_QDEV(qdev); |
|
73 |
if (slave->address == address) |
|
70 | 74 |
break; |
71 | 75 |
} |
72 | 76 |
|
73 |
if (!dev)
|
|
77 |
if (!slave)
|
|
74 | 78 |
return 1; |
75 | 79 |
|
76 | 80 |
/* If the bus is already busy, assume this is a repeated |
77 | 81 |
start condition. */ |
78 |
bus->current_dev = dev;
|
|
79 |
dev->info->event(dev, recv ? I2C_START_RECV : I2C_START_SEND);
|
|
82 |
bus->current_dev = slave;
|
|
83 |
slave->info->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
|
|
80 | 84 |
return 0; |
81 | 85 |
} |
82 | 86 |
|
... | ... | |
130 | 134 |
void i2c_slave_load(QEMUFile *f, i2c_slave *dev) |
131 | 135 |
{ |
132 | 136 |
i2c_bus *bus; |
133 |
bus = qdev_get_bus(&dev->qdev);
|
|
137 |
bus = FROM_QBUS(i2c_bus, qdev_get_parent_bus(&dev->qdev));
|
|
134 | 138 |
dev->address = qemu_get_byte(f); |
135 | 139 |
if (bus->saved_address == dev->address) { |
136 | 140 |
bus->current_dev = dev; |
137 | 141 |
} |
138 | 142 |
} |
139 | 143 |
|
140 |
static void i2c_slave_qdev_init(DeviceState *dev, void *opaque)
|
|
144 |
static void i2c_slave_qdev_init(DeviceState *dev, DeviceInfo *base)
|
|
141 | 145 |
{ |
142 |
I2CSlaveInfo *info = opaque;
|
|
146 |
I2CSlaveInfo *info = container_of(base, I2CSlaveInfo, qdev);
|
|
143 | 147 |
i2c_slave *s = I2C_SLAVE_FROM_QDEV(dev); |
144 | 148 |
|
145 | 149 |
s->info = info; |
146 |
s->bus = qdev_get_bus(dev); |
|
147 | 150 |
s->address = qdev_get_prop_int(dev, "address", 0); |
148 |
s->next = s->bus->dev; |
|
149 |
s->bus->dev = s; |
|
150 | 151 |
|
151 | 152 |
info->init(s); |
152 | 153 |
} |
... | ... | |
154 | 155 |
void i2c_register_slave(const char *name, int size, I2CSlaveInfo *info) |
155 | 156 |
{ |
156 | 157 |
assert(size >= sizeof(i2c_slave)); |
157 |
qdev_register(name, size, i2c_slave_qdev_init, info); |
|
158 |
info->qdev.init = i2c_slave_qdev_init; |
|
159 |
info->qdev.bus_type = BUS_TYPE_I2C; |
|
160 |
qdev_register(name, size, &info->qdev); |
|
158 | 161 |
} |
159 | 162 |
|
160 | 163 |
DeviceState *i2c_create_slave(i2c_bus *bus, const char *name, int addr) |
161 | 164 |
{ |
162 | 165 |
DeviceState *dev; |
163 | 166 |
|
164 |
dev = qdev_create(bus, name); |
|
167 |
dev = qdev_create(&bus->qbus, name);
|
|
165 | 168 |
qdev_set_prop_int(dev, "address", addr); |
166 | 169 |
qdev_init(dev); |
167 | 170 |
return dev; |
Also available in: Unified diff