@@ -64,6 +64,15 @@ static int virtio_i2c_debug=0;
64
64
65
65
#define MAX_I2C_VDEV 128
66
66
#define MAX_NATIVE_I2C_ADAPTER 16
67
+ #define I2C_MSG_OK 0
68
+ #define I2C_MSG_ERR 1
69
+ #define I2C_NO_DEV 2
70
+
71
+ struct virtio_i2c_hdr {
72
+ uint16_t addr ; /* slave address */
73
+ uint16_t flags ;
74
+ uint16_t len ; /*msg length*/
75
+ }__attribute__((packed ));
67
76
68
77
struct native_i2c_adapter {
69
78
int fd ;
@@ -82,6 +91,11 @@ struct virtio_i2c {
82
91
uint16_t adapter_map [MAX_I2C_VDEV ];
83
92
struct virtio_vq_info vq ;
84
93
char ident [256 ];
94
+ pthread_t req_tid ;
95
+ pthread_mutex_t req_mtx ;
96
+ pthread_cond_t req_cond ;
97
+ int in_process ;
98
+ int closing ;
85
99
};
86
100
87
101
static void virtio_i2c_reset (void * );
@@ -113,6 +127,53 @@ native_slave_access_ok(struct native_i2c_adapter *adapter, uint16_t addr)
113
127
return true;
114
128
}
115
129
130
+ static struct native_i2c_adapter *
131
+ native_adapter_find (struct virtio_i2c * vi2c , uint16_t addr )
132
+ {
133
+ int idx ;
134
+
135
+ if (addr < MAX_I2C_VDEV && ((idx = vi2c -> adapter_map [addr ]) != 0 )) {
136
+ return vi2c -> native_adapter [idx - 1 ];
137
+ }
138
+ return NULL ;
139
+ }
140
+
141
+ static uint8_t
142
+ native_adapter_proc (struct virtio_i2c * vi2c , struct i2c_msg * msg )
143
+ {
144
+ int ret ;
145
+ uint16_t addr ;
146
+ struct i2c_rdwr_ioctl_data work_queue ;
147
+ struct native_i2c_adapter * adapter ;
148
+ uint8_t status ;
149
+
150
+ addr = msg -> addr ;
151
+ adapter = native_adapter_find (vi2c , addr );
152
+ if (!adapter )
153
+ return I2C_NO_DEV ;
154
+
155
+ work_queue .nmsgs = 1 ;
156
+ work_queue .msgs = msg ;
157
+
158
+ ret = ioctl (adapter -> fd , I2C_RDWR , & work_queue );
159
+ if (ret < 0 )
160
+ status = I2C_MSG_ERR ;
161
+ else
162
+ status = I2C_MSG_OK ;
163
+ if (msg -> len )
164
+ DPRINTF ("i2c_core: i2c msg: flags=0x%x, addr=0x%x, len=0x%x buf=%x\n" ,
165
+ msg -> flags ,
166
+ msg -> addr ,
167
+ msg -> len ,
168
+ msg -> buf [0 ]);
169
+ else
170
+ DPRINTF ("i2c_core: i2c msg: flags=0x%x, addr=0x%x, len=0x%x\n" ,
171
+ msg -> flags ,
172
+ msg -> addr ,
173
+ msg -> len );
174
+ return status ;
175
+ }
176
+
116
177
static struct native_i2c_adapter *
117
178
native_adapter_create (int bus , uint16_t slave_addr [], int n_slave )
118
179
{
@@ -176,6 +237,68 @@ native_adapter_remove(struct virtio_i2c *vi2c)
176
237
}
177
238
}
178
239
240
+ static void
241
+ virtio_i2c_req_stop (struct virtio_i2c * vi2c )
242
+ {
243
+ void * jval ;
244
+
245
+ pthread_mutex_lock (& vi2c -> req_mtx );
246
+ vi2c -> closing = 1 ;
247
+ pthread_cond_broadcast (& vi2c -> req_cond );
248
+ pthread_mutex_unlock (& vi2c -> req_mtx );
249
+ pthread_join (vi2c -> req_tid , & jval );
250
+ }
251
+
252
+ static void *
253
+ virtio_i2c_proc_thread (void * arg )
254
+ {
255
+ struct virtio_i2c * vi2c = arg ;
256
+ struct virtio_vq_info * vq = & vi2c -> vq ;
257
+ struct iovec iov [3 ];
258
+ uint16_t idx , flags [3 ];
259
+ struct virtio_i2c_hdr * hdr ;
260
+ struct i2c_msg msg ;
261
+ uint8_t * status ;
262
+ int n ;
263
+
264
+ for (;;) {
265
+ pthread_mutex_lock (& vi2c -> req_mtx );
266
+
267
+ vi2c -> in_process = 0 ;
268
+ while (!vq_has_descs (vq ) && !vi2c -> closing )
269
+ pthread_cond_wait (& vi2c -> req_cond , & vi2c -> req_mtx );
270
+
271
+ if (vi2c -> closing ) {
272
+ pthread_mutex_unlock (& vi2c -> req_mtx );
273
+ return NULL ;
274
+ }
275
+ vi2c -> in_process = 1 ;
276
+ pthread_mutex_unlock (& vi2c -> req_mtx );
277
+ do {
278
+ n = vq_getchain (vq , & idx , iov , 3 , flags );
279
+ if (n < 2 || n > 3 ) {
280
+ WPRINTF ("virtio_i2c_proc: failed to get iov from virtqueue\n" );
281
+ continue ;
282
+ }
283
+ hdr = iov [0 ].iov_base ;
284
+ msg .addr = hdr -> addr ;
285
+ msg .flags = hdr -> flags ;
286
+ if (hdr -> len ) {
287
+ msg .buf = iov [1 ].iov_base ;
288
+ msg .len = iov [1 ].iov_len ;
289
+ status = iov [2 ].iov_base ;
290
+ } else {
291
+ msg .buf = NULL ;
292
+ msg .len = 0 ;
293
+ status = iov [1 ].iov_base ;
294
+ }
295
+ * status = native_adapter_proc (vi2c , & msg );
296
+ vq_relchain (vq , idx , 1 );
297
+ } while (vq_has_descs (vq ));
298
+ vq_endchains (vq , 0 );
299
+ }
300
+ }
301
+
179
302
static int
180
303
virtio_i2c_map (struct virtio_i2c * vi2c )
181
304
{
@@ -282,7 +405,15 @@ virtio_i2c_reset(void *vdev)
282
405
static void
283
406
virtio_i2c_notify (void * vdev , struct virtio_vq_info * vq )
284
407
{
285
- /* TODO: Add notify logic */
408
+ struct virtio_i2c * vi2c = vdev ;
409
+
410
+ if (!vq_has_descs (vq ))
411
+ return ;
412
+
413
+ pthread_mutex_lock (& vi2c -> req_mtx );
414
+ if (!vi2c -> in_process )
415
+ pthread_cond_signal (& vi2c -> req_cond );
416
+ pthread_mutex_unlock (& vi2c -> req_mtx );
286
417
}
287
418
288
419
static int
@@ -361,6 +492,12 @@ virtio_i2c_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
361
492
goto fail ;
362
493
}
363
494
virtio_set_io_bar (& vi2c -> base , 0 );
495
+ vi2c -> in_process = 0 ;
496
+ vi2c -> closing = 0 ;
497
+ pthread_mutex_init (& vi2c -> req_mtx , NULL );
498
+ pthread_cond_init (& vi2c -> req_cond , NULL );
499
+ pthread_create (& vi2c -> req_tid , NULL , virtio_i2c_proc_thread , vi2c );
500
+ pthread_setname_np (vi2c -> req_tid , "virtio-i2c" );
364
501
return 0 ;
365
502
366
503
fail :
@@ -379,7 +516,9 @@ virtio_i2c_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
379
516
if (dev -> arg ) {
380
517
DPRINTF ("deinit\n" );
381
518
vi2c = (struct virtio_i2c * ) dev -> arg ;
519
+ virtio_i2c_req_stop (vi2c );
382
520
native_adapter_remove (vi2c );
521
+ pthread_mutex_destroy (& vi2c -> req_mtx );
383
522
pthread_mutex_destroy (& vi2c -> mtx );
384
523
free (vi2c );
385
524
dev -> arg = NULL ;
0 commit comments