@@ -107,13 +107,93 @@ struct virtio_gpio_config {
107
107
uint16_t ngpio ; /* number of gpios */
108
108
} __attribute__((packed ));
109
109
110
+ struct gpio_line {
111
+ char name [32 ]; /* native gpio name */
112
+ char vname [32 ]; /* virtual gpio name */
113
+ int offset ; /* offset in real chip */
114
+ int voffset ; /* offset in virtual chip */
115
+ int fd ; /* native gpio line fd */
116
+ int dir ; /* gpio direction */
117
+ bool busy ; /* gpio line request by kernel */
118
+ struct native_gpio_chip * chip ; /* parent gpio chip */
119
+ };
120
+
121
+ struct native_gpio_chip {
122
+ char name [32 ]; /* gpio chip name */
123
+ char label [32 ]; /* gpio chip label name */
124
+ char dev_name [32 ]; /* device node name */
125
+ int fd ; /* native gpio chip fd */
126
+ uint32_t ngpio ; /* gpio line numbers */
127
+ struct gpio_line * lines ; /* gpio lines in the chip */
128
+ };
129
+
110
130
struct virtio_gpio {
111
131
pthread_mutex_t mtx ;
112
132
struct virtio_base base ;
113
133
struct virtio_vq_info queues [VIRTIO_GPIO_MAXQ ];
134
+ struct native_gpio_chip chips [VIRTIO_GPIO_MAX_CHIPS ];
135
+ uint32_t nchip ;
136
+ struct gpio_line * vlines [VIRTIO_GPIO_MAX_VLINES ];
137
+ uint32_t nvline ;
114
138
struct virtio_gpio_config config ;
115
139
};
116
140
141
+ static void
142
+ native_gpio_update_line_info (struct gpio_line * line )
143
+ {
144
+ struct gpioline_info info ;
145
+ int rc ;
146
+
147
+ memset (& info , 0 , sizeof (info ));
148
+ info .line_offset = line -> offset ;
149
+ rc = ioctl (line -> chip -> fd , GPIO_GET_LINEINFO_IOCTL , & info );
150
+ if (rc ) {
151
+ DPRINTF ("ioctl GPIO_GET_LINEINFO_IOCTL error %s\n" ,
152
+ strerror (errno ));
153
+ return ;
154
+ }
155
+
156
+ line -> busy = info .flags & GPIOLINE_FLAG_KERNEL ;
157
+
158
+ /*
159
+ * if it is already used by virtio gpio model,
160
+ * it is not set to busy state
161
+ */
162
+ if (line -> fd > 0 )
163
+ line -> busy = false;
164
+
165
+ /* 0 means output, 1 means input */
166
+ line -> dir = info .flags & GPIOLINE_FLAG_IS_OUT ? 0 : 1 ;
167
+ strncpy (line -> name , info .name , sizeof (line -> name ) - 1 );
168
+ }
169
+
170
+ static int
171
+ native_gpio_open_line (struct gpio_line * line , unsigned int flags ,
172
+ unsigned int value )
173
+ {
174
+ struct gpiohandle_request req ;
175
+ int rc ;
176
+
177
+ memset (& req , 0 , sizeof (req ));
178
+ req .lineoffsets [0 ] = line -> offset ;
179
+ req .lines = 1 ;
180
+ strncpy (req .consumer_label , "acrn_dm" , sizeof (req .consumer_label ) - 1 );
181
+ if (flags ) {
182
+ req .flags = flags ;
183
+ if (flags & GPIOHANDLE_REQUEST_OUTPUT )
184
+ req .default_values [0 ] = value ;
185
+ }
186
+ rc = ioctl (line -> chip -> fd , GPIO_GET_LINEHANDLE_IOCTL , & req );
187
+ if (rc < 0 ) {
188
+ DPRINTF ("ioctl GPIO_GET_LINEHANDLE_IOCTL error %s\n" ,
189
+ strerror (errno ));
190
+ return -1 ;
191
+ }
192
+
193
+ line -> fd = req .fd ;
194
+ return 0 ;
195
+ }
196
+
117
197
static void virtio_gpio_reset (void * vdev )
118
198
{
119
199
struct virtio_gpio * gpio ;
@@ -176,12 +256,229 @@ virtio_gpio_notify(void *vdev, struct virtio_vq_info *vq)
176
256
}
177
257
}
178
258
259
+ static int
260
+ native_gpio_open_chip (struct native_gpio_chip * chip , const char * name )
261
+ {
262
+ struct gpiochip_info info ;
263
+ struct gpio_line * line ;
264
+ char path [64 ] = {0 };
265
+ int fd , rc , i ;
266
+
267
+ snprintf (path , sizeof (path ), "/dev/%s" , name );
268
+ fd = open (path , O_RDWR );
269
+ if (fd < 0 ) {
270
+ DPRINTF ("Can't open gpio device: %s, error %s\n" ,
271
+ path , strerror (errno ));
272
+ return -1 ;
273
+ }
274
+
275
+ memset (& info , 0 , sizeof (info ));
276
+ rc = ioctl (fd , GPIO_GET_CHIPINFO_IOCTL , & info );
277
+ if (rc < 0 ) {
278
+ DPRINTF ("Can't ioctl gpio device: %s, error %s\n" ,
279
+ path , strerror (errno ));
280
+ goto fail ;
281
+ }
282
+
283
+ chip -> lines = calloc (1 , info .lines * sizeof (* chip -> lines ));
284
+ if (!chip -> lines ) {
285
+ DPRINTF ("Alloc chip lines error, %s:%d, error %s\n" ,
286
+ path , chip -> ngpio , strerror (errno ));
287
+ goto fail ;
288
+ }
289
+ chip -> fd = fd ;
290
+ chip -> ngpio = info .lines ;
291
+ strncpy (chip -> name , info .name , sizeof (chip -> name ) - 1 );
292
+ strncpy (chip -> label , info .label , sizeof (chip -> label ) - 1 );
293
+ strncpy (chip -> dev_name , name , sizeof (chip -> dev_name ) - 1 );
294
+
295
+ /* initialize all lines of the chip */
296
+ for (i = 0 ; i < chip -> ngpio ; i ++ ) {
297
+ line = & chip -> lines [i ];
298
+ line -> offset = i ;
299
+ line -> chip = chip ;
300
+
301
+ /*
302
+ * The line's fd and voffset will be initialized
303
+ * when virtual gpio line connects to the real line.
304
+ */
305
+ line -> fd = -1 ;
306
+ line -> voffset = -1 ;
307
+
308
+ /* Set line state and name via ioctl*/
309
+ native_gpio_update_line_info (line );
310
+ }
311
+
312
+ return 0 ;
313
+
314
+ fail :
315
+ if (fd > 0 )
316
+ close (fd );
317
+ chip -> fd = -1 ;
318
+ chip -> ngpio = 0 ;
319
+ return -1 ;
320
+ }
321
+
322
+ static void
323
+ native_gpio_close_chip (struct native_gpio_chip * chip )
324
+ {
325
+ if (chip ) {
326
+ memset (chip -> name , 0 , sizeof (chip -> name ));
327
+ memset (chip -> label , 0 , sizeof (chip -> label ));
328
+ memset (chip -> dev_name , 0 , sizeof (chip -> dev_name ));
329
+ if (chip -> fd > 0 ) {
330
+ close (chip -> fd );
331
+ chip -> fd = -1 ;
332
+ }
333
+ if (chip -> lines ) {
334
+ free (chip -> lines );
335
+ chip -> lines = NULL ;
336
+ }
337
+ chip -> ngpio = 0 ;
338
+ }
339
+ }
340
+
341
+ static int
342
+ native_gpio_get_offset (struct native_gpio_chip * chip , char * name )
343
+ {
344
+ int rc ;
345
+ int i ;
346
+
347
+ /* try to find a gpio index by offset or name */
348
+ if (isalpha (name [0 ])) {
349
+ for (i = 0 ; i < chip -> ngpio ; i ++ ) {
350
+ if (!strcmp (chip -> lines [i ].name , name ))
351
+ return i ;
352
+ }
353
+ } else if (isdigit (name [0 ])) {
354
+ rc = dm_strtoi (name , NULL , 10 , & i );
355
+ if (rc == 0 && i < chip -> ngpio )
356
+ return i ;
357
+ }
358
+ return -1 ;
359
+ }
360
+
361
+ static struct gpio_line *
362
+ native_gpio_find_line (struct native_gpio_chip * chip , const char * name )
363
+ {
364
+ int offset ;
365
+ char * b , * o , * c ;
366
+ struct gpio_line * line = NULL ;
367
+
368
+ b = o = strdup (name );
369
+ c = strsep (& o , "=" );
370
+
371
+ /* find the line's offset in the chip by name or number */
372
+ offset = native_gpio_get_offset (chip , c );
373
+ if (offset < 0 ) {
374
+ DPRINTF ("the %s line has not been found in %s chip\n" ,
375
+ c , chip -> dev_name );
376
+ goto out ;
377
+ }
378
+
379
+ line = & chip -> lines [offset ];
380
+ if (line -> busy || native_gpio_open_line (line , 0 , 0 ) < 0 ) {
381
+ line = NULL ;
382
+ goto out ;
383
+ }
384
+
385
+ /* If the user sets the name of the GPIO, copy it to vname */
386
+ if (o )
387
+ strncpy (line -> vname , o , sizeof (line -> vname ) - 1 );
388
+
389
+ out :
390
+ free (b );
391
+ return line ;
392
+ }
393
+
394
+
395
+ static int
396
+ native_gpio_init (struct virtio_gpio * gpio , char * opts )
397
+ {
398
+ struct gpio_line * line ;
399
+ char * cstr , * lstr , * tmp , * b , * o ;
400
+ int rc ;
401
+ int cn = 0 ;
402
+ int ln = 0 ;
403
+
404
+ /*
405
+ * -s <slot>,virtio-gpio,<gpio resources>
406
+ * <gpio resources> format
407
+ * <@chip_name0{offset|name[=vname]:offset|name[=vname]:...}
408
+ * [@chip_name1{offset|name[=vname]:offset|name[=vname]:...}]
409
+ * [@chip_name2{offset|name[=vname]:offset|name[=vname]:...}]
410
+ * ...>
411
+ */
412
+
413
+ b = o = strdup (opts );
414
+ while ((tmp = strsep (& o , "@" )) != NULL ) {
415
+
416
+ /* discard subsequent chips */
417
+ if (cn >= VIRTIO_GPIO_MAX_CHIPS ||
418
+ ln >= VIRTIO_GPIO_MAX_VLINES ) {
419
+ DPRINTF ("gpio chips or lines reach max, cn %d, ln %d\n" ,
420
+ cn , ln );
421
+ break ;
422
+ }
423
+
424
+ /* ignore the null string */
425
+ if (tmp [0 ] == '\0' )
426
+ continue ;
427
+
428
+ /*
429
+ * parse gpio chip name
430
+ * if there is no gpiochip information, like "@{...}"
431
+ * ignore all of the lines.
432
+ */
433
+ cstr = strsep (& tmp , "{" );
434
+ if (!tmp || !cstr || cstr [0 ] == '\0' )
435
+ continue ;
436
+
437
+ /* get chip information with its name */
438
+ rc = native_gpio_open_chip (& gpio -> chips [cn ], cstr );
439
+ if (rc < 0 )
440
+ continue ;
441
+
442
+ /* parse all gpio lines in one chip */
443
+ cstr = strsep (& tmp , "}" );
444
+ while ((lstr = strsep (& cstr , ":" )) != NULL ) {
445
+
446
+ /* safety check, to avoid "@gpiochip0{::0:1...}" */
447
+ if (lstr [0 ] == '\0' )
448
+ continue ;
449
+
450
+ /* discard subsequent lines */
451
+ if (ln >= VIRTIO_GPIO_MAX_VLINES ) {
452
+ DPRINTF ("Virtual gpio lines reach max:%d\n" ,
453
+ ln );
454
+ break ;
455
+ }
456
+
457
+ /*
458
+ * If the line provided by gpio command line is found
459
+ * assign one virtual gpio offset for it.
460
+ */
461
+ line = native_gpio_find_line (& gpio -> chips [cn ], lstr );
462
+ if (line ) {
463
+ gpio -> vlines [ln ] = line ;
464
+ line -> voffset = ln ;
465
+ ln ++ ;
466
+ }
467
+ }
468
+ cn ++ ;
469
+ }
470
+ gpio -> nchip = cn ;
471
+ gpio -> nvline = ln ;
472
+ free (b );
473
+ return ln == 0 ? -1 : 0 ;
474
+ }
475
+
179
476
static int
180
477
virtio_gpio_init (struct vmctx * ctx , struct pci_vdev * dev , char * opts )
181
478
{
182
479
struct virtio_gpio * gpio ;
183
480
pthread_mutexattr_t attr ;
184
- int rc ;
481
+ int rc , i ;
185
482
186
483
/* Just support one bdf */
187
484
if (virtio_gpio_is_active )
@@ -202,6 +499,12 @@ virtio_gpio_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
202
499
goto init_fail ;
203
500
}
204
501
502
+ rc = native_gpio_init (gpio , opts );
503
+ if (rc ) {
504
+ DPRINTF ("%s" , "virtio gpio: failed to initialize gpio\n" );
505
+ goto gpio_fail ;
506
+ }
507
+
205
508
/* init mutex attribute properly to avoid deadlock */
206
509
rc = pthread_mutexattr_init (& attr );
207
510
if (rc ) {
@@ -226,6 +529,9 @@ virtio_gpio_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
226
529
/* gpio base for frontend gpio chip */
227
530
gpio -> config .base = 0 ;
228
531
532
+ /* gpio numbers for frontend gpio chip */
533
+ gpio -> config .ngpio = gpio -> nvline ;
534
+
229
535
gpio -> base .device_caps = VIRTIO_GPIO_S_HOSTCAPS ;
230
536
gpio -> base .mtx = & gpio -> mtx ;
231
537
gpio -> queues [0 ].qsize = 64 ;
@@ -254,6 +560,10 @@ virtio_gpio_init(struct vmctx *ctx, struct pci_vdev *dev, char *opts)
254
560
pthread_mutex_destroy (& gpio -> mtx );
255
561
256
562
mtx_fail :
563
+ for (i = 0 ; i < gpio -> nchip ; i ++ )
564
+ native_gpio_close_chip (& gpio -> chips [i ]);
565
+
566
+ gpio_fail :
257
567
free (gpio );
258
568
dev -> arg = NULL ;
259
569
@@ -266,12 +576,15 @@ static void
266
576
virtio_gpio_deinit (struct vmctx * ctx , struct pci_vdev * dev , char * opts )
267
577
{
268
578
struct virtio_gpio * gpio ;
579
+ int i ;
269
580
270
581
DPRINTF ("%s" , "virtio gpio: pci_gpio_deinit\r\n" );
271
582
virtio_gpio_is_active = false;
272
583
gpio = (struct virtio_gpio * )dev -> arg ;
273
584
if (gpio ) {
274
585
pthread_mutex_destroy (& gpio -> mtx );
586
+ for (i = 0 ; i < gpio -> nchip ; i ++ )
587
+ native_gpio_close_chip (& gpio -> chips [i ]);
275
588
free (gpio );
276
589
dev -> arg = NULL ;
277
590
}
0 commit comments