16
16
#include <linux/i2c.h>
17
17
#include <linux/i2c-dev.h>
18
18
#include <sys/ioctl.h>
19
+ #include <sys/queue.h>
20
+ #include <stdbool.h>
21
+ #include <pthread.h>
22
+ #include <fcntl.h>
23
+ #include <unistd.h>
19
24
20
25
#include "dm.h"
21
26
#include "pci_core.h"
@@ -57,12 +62,24 @@ static int virtio_i2c_debug=0;
57
62
do { if (virtio_i2c_debug) printf(VIRTIO_I2C_PREF fmt, ##args); } while (0)
58
63
#define WPRINTF (fmt , args ...) printf(VIRTIO_I2C_PREF fmt, ##args)
59
64
65
+ #define MAX_I2C_VDEV 128
66
+ #define MAX_NATIVE_I2C_ADAPTER 16
67
+
68
+ struct native_i2c_adapter {
69
+ int fd ;
70
+ int bus ;
71
+ bool i2cdev_enable [MAX_I2C_VDEV ];
72
+ };
73
+
60
74
/*
61
75
* Per-device struct
62
76
*/
63
77
struct virtio_i2c {
64
78
struct virtio_base base ;
65
79
pthread_mutex_t mtx ;
80
+ struct native_i2c_adapter * native_adapter [MAX_NATIVE_I2C_ADAPTER ];
81
+ int native_adapter_num ;
82
+ uint16_t adapter_map [MAX_I2C_VDEV ];
66
83
struct virtio_vq_info vq ;
67
84
char ident [256 ];
68
85
};
@@ -82,6 +99,177 @@ static struct virtio_ops virtio_i2c_ops = {
82
99
NULL , /* called on guest set status */
83
100
};
84
101
102
+ static bool
103
+ native_slave_access_ok (struct native_i2c_adapter * adapter , uint16_t addr )
104
+ {
105
+ if (ioctl (adapter -> fd , I2C_SLAVE , addr ) < 0 ) {
106
+ if (errno == EBUSY ) {
107
+ WPRINTF ("i2c_core: slave device %x is busy!\n" , addr );
108
+ } else {
109
+ WPRINTF ("i2c_core: slave device %d is not exsit!\n" , addr );
110
+ }
111
+ return false;
112
+ }
113
+ return true;
114
+ }
115
+
116
+ static struct native_i2c_adapter *
117
+ native_adapter_create (int bus , uint16_t slave_addr [], int n_slave )
118
+ {
119
+ int fd ;
120
+ struct native_i2c_adapter * native_adapter ;
121
+ char native_path [20 ];
122
+ int i ;
123
+
124
+ if (bus < 0 )
125
+ return NULL ;
126
+
127
+ native_adapter = calloc (1 , sizeof (struct native_i2c_adapter ));
128
+ if (native_adapter == NULL ) {
129
+ WPRINTF ("i2c_core: failed to calloc struct virtio_i2c_vdev" );
130
+ return NULL ;
131
+ }
132
+
133
+ sprintf (native_path , "/dev/i2c-%d" , bus );
134
+ fd = open (native_path , O_RDWR );
135
+ if (fd < 0 ) {
136
+ WPRINTF ("virtio_i2c: failed to open %s\n" , native_path );
137
+ return NULL ;
138
+ }
139
+ native_adapter -> fd = fd ;
140
+ native_adapter -> bus = bus ;
141
+ for (i = 0 ; i < n_slave ; i ++ ) {
142
+ if (slave_addr [i ]) {
143
+ if (native_slave_access_ok (native_adapter , slave_addr [i ])) {
144
+ if (native_adapter -> i2cdev_enable [slave_addr [i ]]) {
145
+ WPRINTF ("slave addr 0x%x repeat, not allowed.\n" , slave_addr [i ]);
146
+ goto fail ;
147
+ }
148
+ native_adapter -> i2cdev_enable [slave_addr [i ]] = true;
149
+ DPRINTF ("virtio_i2c: add slave 0x%x\n" , slave_addr [i ]);
150
+ } else {
151
+ goto fail ;
152
+ }
153
+ }
154
+ }
155
+ return native_adapter ;
156
+
157
+ fail :
158
+ free (native_adapter );
159
+ return NULL ;
160
+ }
161
+
162
+ static void
163
+ native_adapter_remove (struct virtio_i2c * vi2c )
164
+ {
165
+ int i ;
166
+ struct native_i2c_adapter * native_adapter ;
167
+
168
+ for (i = 0 ; i < MAX_NATIVE_I2C_ADAPTER ; i ++ ) {
169
+ native_adapter = vi2c -> native_adapter [i ];
170
+ if (native_adapter ) {
171
+ if (native_adapter -> fd > 0 )
172
+ close (native_adapter -> fd );
173
+ free (native_adapter );
174
+ vi2c -> native_adapter [i ] = NULL ;
175
+ }
176
+ }
177
+ }
178
+
179
+ static int
180
+ virtio_i2c_map (struct virtio_i2c * vi2c )
181
+ {
182
+ int i , slave_addr ;
183
+ struct native_i2c_adapter * native_adapter ;
184
+
185
+ /*
186
+ * Flatten the map for slave address and native adapter to the array:
187
+ *
188
+ * adapter_map[MAX_I2C_VDEV]:
189
+ *
190
+ * Native Adapter | adapter2 | none | adapter1 | adapter3 | none | none| (val)
191
+ * |----------|-------|----------|----------|------|-----|
192
+ * Slave Address | addr 1 | none | addr 2 | addr 3 | none | none| (idx)
193
+ * |<-----------------------MAX_I2C_VDEV---------------->|
194
+ */
195
+ for (i = 0 ; i < vi2c -> native_adapter_num ; i ++ ) {
196
+ native_adapter = vi2c -> native_adapter [i ];
197
+ for (slave_addr = 0 ; slave_addr < MAX_I2C_VDEV ; slave_addr ++ ) {
198
+ if (native_adapter -> i2cdev_enable [slave_addr ]) {
199
+ if (vi2c -> adapter_map [slave_addr ]) {
200
+ WPRINTF ("slave addr %x repeat, not support!\n" , slave_addr );
201
+ return -1 ;
202
+ }
203
+ /* As 0 is the initiate value, + 1 for index */
204
+ vi2c -> adapter_map [slave_addr ] = i + 1 ;
205
+ DPRINTF ("slave:%d -> native adapter: %d \n" ,
206
+ slave_addr ,
207
+ native_adapter -> bus );
208
+ }
209
+ }
210
+ }
211
+ return 0 ;
212
+ }
213
+
214
+ static int
215
+ virtio_i2c_parse (struct virtio_i2c * vi2c , char * optstr )
216
+ {
217
+ char * cp , * t ;
218
+ uint16_t slave_addr [MAX_I2C_VDEV ];
219
+ int addr , bus , n_adapter , n_slave ;
220
+
221
+ /*
222
+ * virtio-i2c,<bus>:<slave_addr>[:<slave_addr>],
223
+ * [<bus>:<slave_addr>[:<slave_addr>]]
224
+ *
225
+ * bus (dec): native adatper bus number.
226
+ * e.g. 2 for /dev/i2c-2
227
+ * slave_addr (hex): address for native slave device
228
+ * e.g. 0x1C or 1C
229
+ *
230
+ * Note: slave address can not repeat.
231
+ */
232
+ n_adapter = 0 ;
233
+ while (optstr != NULL ) {
234
+ cp = strsep (& optstr , "," );
235
+ /*
236
+ * <bus>:<slave_addr>[:<slave_addr>]...
237
+ */
238
+ n_slave = 0 ;
239
+ bus = -1 ;
240
+ while (cp != NULL && * cp != '\0' ) {
241
+ if (* cp == ':' )
242
+ cp ++ ;
243
+ if (bus == -1 ) {
244
+ if (dm_strtoi (cp , & t , 10 , & bus ) || bus < 0 )
245
+ return -1 ;
246
+ } else {
247
+ if (dm_strtoi (cp , & t , 16 , & addr ) || addr < 0 )
248
+ return -1 ;
249
+ if (n_slave > MAX_I2C_VDEV ) {
250
+ WPRINTF ("too many devices, only support %d \n" , MAX_I2C_VDEV );
251
+ return -1 ;
252
+ }
253
+ slave_addr [n_slave ] = (uint16_t )(addr & (MAX_I2C_VDEV - 1 ));
254
+ DPRINTF ("native i2c adapter %d:0x%x\n" , bus , slave_addr [n_slave ]);
255
+ n_slave ++ ;
256
+ }
257
+ cp = t ;
258
+ }
259
+ if (n_adapter > MAX_NATIVE_I2C_ADAPTER ) {
260
+ WPRINTF ("too many adapter, only support %d \n" , MAX_NATIVE_I2C_ADAPTER );
261
+ return -1 ;
262
+ }
263
+ vi2c -> native_adapter [n_adapter ] = native_adapter_create (bus , slave_addr , n_slave );
264
+ if (!vi2c -> native_adapter [n_adapter ])
265
+ return -1 ;
266
+ n_adapter ++ ;
267
+ }
268
+ vi2c -> native_adapter_num = n_adapter ;
269
+
270
+ return 0 ;
271
+ }
272
+
85
273
static void
86
274
virtio_i2c_reset (void * vdev )
87
275
{
@@ -104,14 +292,22 @@ virtio_i2c_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
104
292
u_char digest [16 ];
105
293
struct virtio_i2c * vi2c ;
106
294
pthread_mutexattr_t attr ;
107
- int rc ;
295
+ int rc = -1 ;
108
296
109
297
vi2c = calloc (1 , sizeof (struct virtio_i2c ));
110
298
if (!vi2c ) {
111
299
WPRINTF ("calloc returns NULL\n" );
112
300
return - ENOMEM ;
113
301
}
114
302
303
+ if (virtio_i2c_parse (vi2c , opts )) {
304
+ WPRINTF ("failed to parse parameters %s \n" , opts );
305
+ goto mtx_fail ;
306
+ }
307
+
308
+ if (virtio_i2c_map (vi2c ))
309
+ goto mtx_fail ;
310
+
115
311
/* init mutex attribute properly to avoid deadlock */
116
312
rc = pthread_mutexattr_init (& attr );
117
313
if (rc ) {
@@ -136,6 +332,7 @@ virtio_i2c_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
136
332
virtio_linkup (& vi2c -> base , & virtio_i2c_ops , vi2c , dev , & vi2c -> vq , BACKEND_VBSU );
137
333
vi2c -> base .mtx = & vi2c -> mtx ;
138
334
vi2c -> vq .qsize = 64 ;
335
+ vi2c -> native_adapter_num = 0 ;
139
336
140
337
MD5_Init (& mdctx );
141
338
MD5_Update (& mdctx , "vi2c" , strlen ("vi2c" ));
@@ -169,6 +366,7 @@ virtio_i2c_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
169
366
fail :
170
367
pthread_mutex_destroy (& vi2c -> mtx );
171
368
mtx_fail :
369
+ native_adapter_remove (vi2c );
172
370
free (vi2c );
173
371
return rc ;
174
372
}
@@ -181,6 +379,7 @@ virtio_i2c_deinit(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
181
379
if (dev -> arg ) {
182
380
DPRINTF ("deinit\n" );
183
381
vi2c = (struct virtio_i2c * ) dev -> arg ;
382
+ native_adapter_remove (vi2c );
184
383
pthread_mutex_destroy (& vi2c -> mtx );
185
384
free (vi2c );
186
385
dev -> arg = NULL ;
0 commit comments