Instead of abusing struct attribute_group to control initialization of struct mdev_type, just define the actual attributes in the mdev_driver, allocate the mdev_type structures in the caller and pass them to mdev_register_parent. This allows the caller to use container_of to get at the containing structure and thus significantly simplify the code.
Showing the changes to samples (3 of 17 files). Show all
Unified · Split
| @@ -99,23 +99,27 @@ MODULE_PARM_DESC(mem, "megabytes available to " MBOCHS_NAME " devices"); · 98 unmodified lines | ||
| 99 | 99 | #define MBOCHS_TYPE_2 "medium" |
| 100 | 100 | #define MBOCHS_TYPE_3 "large" |
| 101 | 101 | |
| 102 | −static const struct mbochs_type { | |
| 102 | +static struct mbochs_type { | |
| 103 | + struct mdev_type type; | |
| 103 | 104 | const char *name; |
| 104 | 105 | u32 mbytes; |
| 105 | 106 | u32 max_x; |
| 106 | 107 | u32 max_y; |
| 107 | 108 | } mbochs_types[] = { |
| 108 | 109 | { |
| 110 | + .type.sysfs_name = MBOCHS_TYPE_1, | |
| 109 | 111 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_1, |
| 110 | 112 | .mbytes = 4, |
| 111 | 113 | .max_x = 800, |
| 112 | 114 | .max_y = 600, |
| 113 | 115 | }, { |
| 116 | + .type.sysfs_name = MBOCHS_TYPE_2, | |
| 114 | 117 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_2, |
| 115 | 118 | .mbytes = 16, |
| 116 | 119 | .max_x = 1920, |
| 117 | 120 | .max_y = 1440, |
| 118 | 121 | }, { |
| 122 | + .type.sysfs_name = MBOCHS_TYPE_3, | |
| 119 | 123 | .name = MBOCHS_CLASS_NAME "-" MBOCHS_TYPE_3, |
| 120 | 124 | .mbytes = 64, |
| 121 | 125 | .max_x = 0, |
| @@ -123,6 +127,11 @@ static const struct mbochs_type { · 1 unmodified line | ||
| 123 | 127 | }, |
| 124 | 128 | }; |
| 125 | 129 | |
| 130 | +static struct mdev_type *mbochs_mdev_types[] = { | |
| 131 | + &mbochs_types[0].type, | |
| 132 | + &mbochs_types[1].type, | |
| 133 | + &mbochs_types[2].type, | |
| 134 | +}; | |
| 126 | 135 | |
| 127 | 136 | static dev_t mbochs_devt; |
| 128 | 137 | static struct class *mbochs_class; |
| @@ -510,8 +519,8 @@ static int mbochs_init_dev(struct vfio_device *vdev) · 381 unmodified lines | ||
| 510 | 519 | struct mdev_state *mdev_state = |
| 511 | 520 | container_of(vdev, struct mdev_state, vdev); |
| 512 | 521 | struct mdev_device *mdev = to_mdev_device(vdev->dev); |
| 513 | − const struct mbochs_type *type = | |
| 514 | − &mbochs_types[mdev_get_type_group_id(mdev)]; | |
| 522 | + struct mbochs_type *type = | |
| 523 | + container_of(mdev->type, struct mbochs_type, type); | |
| 515 | 524 | int avail_mbytes = atomic_read(&mbochs_avail_mbytes); |
| 516 | 525 | int ret = -ENOMEM; |
| 517 | 526 | |
| @@ -1345,8 +1354,8 @@ static const struct attribute_group *mdev_dev_groups[] = { · 827 unmodified lines | ||
| 1345 | 1354 | static ssize_t name_show(struct mdev_type *mtype, |
| 1346 | 1355 | struct mdev_type_attribute *attr, char *buf) |
| 1347 | 1356 | { |
| 1348 | − const struct mbochs_type *type = | |
| 1349 | − &mbochs_types[mtype_get_type_group_id(mtype)]; | |
| 1357 | + struct mbochs_type *type = | |
| 1358 | + container_of(mtype, struct mbochs_type, type); | |
| 1350 | 1359 | |
| 1351 | 1360 | return sprintf(buf, "%s\n", type->name); |
| 1352 | 1361 | } |
| @@ -1355,8 +1364,8 @@ static MDEV_TYPE_ATTR_RO(name); · 2 unmodified lines | ||
| 1355 | 1364 | static ssize_t description_show(struct mdev_type *mtype, |
| 1356 | 1365 | struct mdev_type_attribute *attr, char *buf) |
| 1357 | 1366 | { |
| 1358 | − const struct mbochs_type *type = | |
| 1359 | − &mbochs_types[mtype_get_type_group_id(mtype)]; | |
| 1367 | + struct mbochs_type *type = | |
| 1368 | + container_of(mtype, struct mbochs_type, type); | |
| 1360 | 1369 | |
| 1361 | 1370 | return sprintf(buf, "virtual display, %d MB video memory\n", |
| 1362 | 1371 | type ? type->mbytes : 0); |
| @@ -1367,8 +1376,8 @@ static ssize_t available_instances_show(struct mdev_type *mtype, · 4 unmodified lines | ||
| 1367 | 1376 | struct mdev_type_attribute *attr, |
| 1368 | 1377 | char *buf) |
| 1369 | 1378 | { |
| 1370 | − const struct mbochs_type *type = | |
| 1371 | − &mbochs_types[mtype_get_type_group_id(mtype)]; | |
| 1379 | + struct mbochs_type *type = | |
| 1380 | + container_of(mtype, struct mbochs_type, type); | |
| 1372 | 1381 | int count = atomic_read(&mbochs_avail_mbytes) / type->mbytes; |
| 1373 | 1382 | |
| 1374 | 1383 | return sprintf(buf, "%d\n", count); |
| @@ -1382,7 +1391,7 @@ static ssize_t device_api_show(struct mdev_type *mtype, · 7 unmodified lines | ||
| 1382 | 1391 | } |
| 1383 | 1392 | static MDEV_TYPE_ATTR_RO(device_api); |
| 1384 | 1393 | |
| 1385 | −static struct attribute *mdev_types_attrs[] = { | |
| 1394 | +static const struct attribute *mdev_types_attrs[] = { | |
| 1386 | 1395 | &mdev_type_attr_name.attr, |
| 1387 | 1396 | &mdev_type_attr_description.attr, |
| 1388 | 1397 | &mdev_type_attr_device_api.attr, |
| @@ -1390,28 +1399,6 @@ static struct attribute *mdev_types_attrs[] = { · 1 unmodified line | ||
| 1390 | 1399 | NULL, |
| 1391 | 1400 | }; |
| 1392 | 1401 | |
| 1393 | −static struct attribute_group mdev_type_group1 = { | |
| 1394 | − .name = MBOCHS_TYPE_1, | |
| 1395 | − .attrs = mdev_types_attrs, | |
| 1396 | −}; | |
| 1397 | − | |
| 1398 | −static struct attribute_group mdev_type_group2 = { | |
| 1399 | − .name = MBOCHS_TYPE_2, | |
| 1400 | − .attrs = mdev_types_attrs, | |
| 1401 | −}; | |
| 1402 | − | |
| 1403 | −static struct attribute_group mdev_type_group3 = { | |
| 1404 | − .name = MBOCHS_TYPE_3, | |
| 1405 | − .attrs = mdev_types_attrs, | |
| 1406 | −}; | |
| 1407 | − | |
| 1408 | −static struct attribute_group *mdev_type_groups[] = { | |
| 1409 | − &mdev_type_group1, | |
| 1410 | − &mdev_type_group2, | |
| 1411 | − &mdev_type_group3, | |
| 1412 | − NULL, | |
| 1413 | −}; | |
| 1414 | − | |
| 1415 | 1402 | static const struct vfio_device_ops mbochs_dev_ops = { |
| 1416 | 1403 | .close_device = mbochs_close_device, |
| 1417 | 1404 | .init = mbochs_init_dev, |
| @@ -1431,7 +1418,7 @@ static struct mdev_driver mbochs_driver = { · 13 unmodified lines | ||
| 1431 | 1418 | }, |
| 1432 | 1419 | .probe = mbochs_probe, |
| 1433 | 1420 | .remove = mbochs_remove, |
| 1434 | − .supported_type_groups = mdev_type_groups, | |
| 1421 | + .types_attrs = mdev_types_attrs, | |
| 1435 | 1422 | }; |
| 1436 | 1423 | |
| 1437 | 1424 | static const struct file_operations vd_fops = { |
| @@ -1476,7 +1463,9 @@ static int __init mbochs_dev_init(void) · 38 unmodified lines | ||
| 1476 | 1463 | if (ret) |
| 1477 | 1464 | goto err_class; |
| 1478 | 1465 | |
| 1479 | − ret = mdev_register_parent(&mbochs_parent, &mbochs_dev, &mbochs_driver); | |
| 1466 | + ret = mdev_register_parent(&mbochs_parent, &mbochs_dev, &mbochs_driver, | |
| 1467 | + mbochs_mdev_types, | |
| 1468 | + ARRAY_SIZE(mbochs_mdev_types)); | |
| 1480 | 1469 | if (ret) |
| 1481 | 1470 | goto err_device; |
| 1482 | 1471 | |
| @@ -51,7 +51,8 @@ MODULE_PARM_DESC(count, "number of " MDPY_NAME " devices"); · 50 unmodified lines | ||
| 51 | 51 | #define MDPY_TYPE_2 "xga" |
| 52 | 52 | #define MDPY_TYPE_3 "hd" |
| 53 | 53 | |
| 54 | −static const struct mdpy_type { | |
| 54 | +static struct mdpy_type { | |
| 55 | + struct mdev_type type; | |
| 55 | 56 | const char *name; |
| 56 | 57 | u32 format; |
| 57 | 58 | u32 bytepp; |
| @@ -59,18 +60,21 @@ static const struct mdpy_type { · 1 unmodified line | ||
| 59 | 60 | u32 height; |
| 60 | 61 | } mdpy_types[] = { |
| 61 | 62 | { |
| 63 | + .type.sysfs_name = MDPY_TYPE_1, | |
| 62 | 64 | .name = MDPY_CLASS_NAME "-" MDPY_TYPE_1, |
| 63 | 65 | .format = DRM_FORMAT_XRGB8888, |
| 64 | 66 | .bytepp = 4, |
| 65 | 67 | .width = 640, |
| 66 | 68 | .height = 480, |
| 67 | 69 | }, { |
| 70 | + .type.sysfs_name = MDPY_TYPE_2, | |
| 68 | 71 | .name = MDPY_CLASS_NAME "-" MDPY_TYPE_2, |
| 69 | 72 | .format = DRM_FORMAT_XRGB8888, |
| 70 | 73 | .bytepp = 4, |
| 71 | 74 | .width = 1024, |
| 72 | 75 | .height = 768, |
| 73 | 76 | }, { |
| 77 | + .type.sysfs_name = MDPY_TYPE_3, | |
| 74 | 78 | .name = MDPY_CLASS_NAME "-" MDPY_TYPE_3, |
| 75 | 79 | .format = DRM_FORMAT_XRGB8888, |
| 76 | 80 | .bytepp = 4, |
| @@ -79,6 +83,12 @@ static const struct mdpy_type { · 2 unmodified lines | ||
| 79 | 83 | }, |
| 80 | 84 | }; |
| 81 | 85 | |
| 86 | +static struct mdev_type *mdpy_mdev_types[] = { | |
| 87 | + &mdpy_types[0].type, | |
| 88 | + &mdpy_types[1].type, | |
| 89 | + &mdpy_types[2].type, | |
| 90 | +}; | |
| 91 | + | |
| 82 | 92 | static dev_t mdpy_devt; |
| 83 | 93 | static struct class *mdpy_class; |
| 84 | 94 | static struct cdev mdpy_cdev; |
| @@ -222,7 +232,7 @@ static int mdpy_init_dev(struct vfio_device *vdev) · 137 unmodified lines | ||
| 222 | 232 | container_of(vdev, struct mdev_state, vdev); |
| 223 | 233 | struct mdev_device *mdev = to_mdev_device(vdev->dev); |
| 224 | 234 | const struct mdpy_type *type = |
| 225 | − &mdpy_types[mdev_get_type_group_id(mdev)]; | |
| 235 | + container_of(mdev->type, struct mdpy_type, type); | |
| 226 | 236 | u32 fbsize; |
| 227 | 237 | int ret = -ENOMEM; |
| 228 | 238 | |
| @@ -655,8 +665,7 @@ static const struct attribute_group *mdev_dev_groups[] = { · 426 unmodified lines | ||
| 655 | 665 | static ssize_t name_show(struct mdev_type *mtype, |
| 656 | 666 | struct mdev_type_attribute *attr, char *buf) |
| 657 | 667 | { |
| 658 | − const struct mdpy_type *type = | |
| 659 | − &mdpy_types[mtype_get_type_group_id(mtype)]; | |
| 668 | + struct mdpy_type *type = container_of(mtype, struct mdpy_type, type); | |
| 660 | 669 | |
| 661 | 670 | return sprintf(buf, "%s\n", type->name); |
| 662 | 671 | } |
| @@ -665,8 +674,7 @@ static MDEV_TYPE_ATTR_RO(name); · 2 unmodified lines | ||
| 665 | 674 | static ssize_t description_show(struct mdev_type *mtype, |
| 666 | 675 | struct mdev_type_attribute *attr, char *buf) |
| 667 | 676 | { |
| 668 | − const struct mdpy_type *type = | |
| 669 | − &mdpy_types[mtype_get_type_group_id(mtype)]; | |
| 677 | + struct mdpy_type *type = container_of(mtype, struct mdpy_type, type); | |
| 670 | 678 | |
| 671 | 679 | return sprintf(buf, "virtual display, %dx%d framebuffer\n", |
| 672 | 680 | type->width, type->height); |
| @@ -688,7 +696,7 @@ static ssize_t device_api_show(struct mdev_type *mtype, · 15 unmodified lines | ||
| 688 | 696 | } |
| 689 | 697 | static MDEV_TYPE_ATTR_RO(device_api); |
| 690 | 698 | |
| 691 | −static struct attribute *mdev_types_attrs[] = { | |
| 699 | +static const struct attribute *mdev_types_attrs[] = { | |
| 692 | 700 | &mdev_type_attr_name.attr, |
| 693 | 701 | &mdev_type_attr_description.attr, |
| 694 | 702 | &mdev_type_attr_device_api.attr, |
| @@ -696,28 +704,6 @@ static struct attribute *mdev_types_attrs[] = { · 1 unmodified line | ||
| 696 | 704 | NULL, |
| 697 | 705 | }; |
| 698 | 706 | |
| 699 | −static struct attribute_group mdev_type_group1 = { | |
| 700 | − .name = MDPY_TYPE_1, | |
| 701 | − .attrs = mdev_types_attrs, | |
| 702 | −}; | |
| 703 | − | |
| 704 | −static struct attribute_group mdev_type_group2 = { | |
| 705 | − .name = MDPY_TYPE_2, | |
| 706 | − .attrs = mdev_types_attrs, | |
| 707 | −}; | |
| 708 | − | |
| 709 | −static struct attribute_group mdev_type_group3 = { | |
| 710 | − .name = MDPY_TYPE_3, | |
| 711 | − .attrs = mdev_types_attrs, | |
| 712 | −}; | |
| 713 | − | |
| 714 | −static struct attribute_group *mdev_type_groups[] = { | |
| 715 | − &mdev_type_group1, | |
| 716 | − &mdev_type_group2, | |
| 717 | − &mdev_type_group3, | |
| 718 | − NULL, | |
| 719 | −}; | |
| 720 | − | |
| 721 | 707 | static const struct vfio_device_ops mdpy_dev_ops = { |
| 722 | 708 | .init = mdpy_init_dev, |
| 723 | 709 | .release = mdpy_release_dev, |
| @@ -736,7 +722,7 @@ static struct mdev_driver mdpy_driver = { · 12 unmodified lines | ||
| 736 | 722 | }, |
| 737 | 723 | .probe = mdpy_probe, |
| 738 | 724 | .remove = mdpy_remove, |
| 739 | − .supported_type_groups = mdev_type_groups, | |
| 725 | + .types_attrs = mdev_types_attrs, | |
| 740 | 726 | }; |
| 741 | 727 | |
| 742 | 728 | static const struct file_operations vd_fops = { |
| @@ -779,7 +765,9 @@ static int __init mdpy_dev_init(void) · 36 unmodified lines | ||
| 779 | 765 | if (ret) |
| 780 | 766 | goto err_class; |
| 781 | 767 | |
| 782 | − ret = mdev_register_parent(&mdpy_parent, &mdpy_dev, &mdpy_driver); | |
| 768 | + ret = mdev_register_parent(&mdpy_parent, &mdpy_dev, &mdpy_driver, | |
| 769 | + mdpy_mdev_types, | |
| 770 | + ARRAY_SIZE(mdpy_mdev_types)); | |
| 783 | 771 | if (ret) |
| 784 | 772 | goto err_device; |
| 785 | 773 | |
| @@ -143,6 +143,20 @@ struct mdev_state { · 142 unmodified lines | ||
| 143 | 143 | int nr_ports; |
| 144 | 144 | }; |
| 145 | 145 | |
| 146 | +static struct mtty_type { | |
| 147 | + struct mdev_type type; | |
| 148 | + int nr_ports; | |
| 149 | + const char *name; | |
| 150 | +} mtty_types[2] = { | |
| 151 | + { .nr_ports = 1, .type.sysfs_name = "1", .name = "Single port serial" }, | |
| 152 | + { .nr_ports = 2, .type.sysfs_name = "2", .name = "Dual port serial" }, | |
| 153 | +}; | |
| 154 | + | |
| 155 | +static struct mdev_type *mtty_mdev_types[] = { | |
| 156 | + &mtty_types[0].type, | |
| 157 | + &mtty_types[1].type, | |
| 158 | +}; | |
| 159 | + | |
| 146 | 160 | static atomic_t mdev_avail_ports = ATOMIC_INIT(MAX_MTTYS); |
| 147 | 161 | |
| 148 | 162 | static const struct file_operations vd_fops = { |
| @@ -707,17 +721,19 @@ static int mtty_init_dev(struct vfio_device *vdev) · 558 unmodified lines | ||
| 707 | 721 | struct mdev_state *mdev_state = |
| 708 | 722 | container_of(vdev, struct mdev_state, vdev); |
| 709 | 723 | struct mdev_device *mdev = to_mdev_device(vdev->dev); |
| 710 | − int nr_ports = mdev_get_type_group_id(mdev) + 1; | |
| 724 | + struct mtty_type *type = | |
| 725 | + container_of(mdev->type, struct mtty_type, type); | |
| 711 | 726 | int avail_ports = atomic_read(&mdev_avail_ports); |
| 712 | 727 | int ret; |
| 713 | 728 | |
| 714 | 729 | do { |
| 715 | − if (avail_ports < nr_ports) | |
| 730 | + if (avail_ports < type->nr_ports) | |
| 716 | 731 | return -ENOSPC; |
| 717 | 732 | } while (!atomic_try_cmpxchg(&mdev_avail_ports, |
| 718 | − &avail_ports, avail_ports - nr_ports)); | |
| 733 | + &avail_ports, | |
| 734 | + avail_ports - type->nr_ports)); | |
| 719 | 735 | |
| 720 | − mdev_state->nr_ports = nr_ports; | |
| 736 | + mdev_state->nr_ports = type->nr_ports; | |
| 721 | 737 | mdev_state->irq_index = -1; |
| 722 | 738 | mdev_state->s[0].max_fifo_size = MAX_FIFO_SIZE; |
| 723 | 739 | mdev_state->s[1].max_fifo_size = MAX_FIFO_SIZE; |
| @@ -735,7 +751,7 @@ static int mtty_init_dev(struct vfio_device *vdev) · 11 unmodified lines | ||
| 735 | 751 | return 0; |
| 736 | 752 | |
| 737 | 753 | err_nr_ports: |
| 738 | − atomic_add(nr_ports, &mdev_avail_ports); | |
| 754 | + atomic_add(type->nr_ports, &mdev_avail_ports); | |
| 739 | 755 | return ret; |
| 740 | 756 | } |
| 741 | 757 | |
| @@ -1242,11 +1258,9 @@ static const struct attribute_group *mdev_dev_groups[] = { · 500 unmodified lines | ||
| 1242 | 1258 | static ssize_t name_show(struct mdev_type *mtype, |
| 1243 | 1259 | struct mdev_type_attribute *attr, char *buf) |
| 1244 | 1260 | { |
| 1245 | − static const char *name_str[2] = { "Single port serial", | |
| 1246 | − "Dual port serial" }; | |
| 1261 | + struct mtty_type *type = container_of(mtype, struct mtty_type, type); | |
| 1247 | 1262 | |
| 1248 | − return sysfs_emit(buf, "%s\n", | |
| 1249 | − name_str[mtype_get_type_group_id(mtype)]); | |
| 1263 | + return sysfs_emit(buf, "%s\n", type->name); | |
| 1250 | 1264 | } |
| 1251 | 1265 | |
| 1252 | 1266 | static MDEV_TYPE_ATTR_RO(name); |
| @@ -1255,9 +1269,10 @@ static ssize_t available_instances_show(struct mdev_type *mtype, · 2 unmodified lines | ||
| 1255 | 1269 | struct mdev_type_attribute *attr, |
| 1256 | 1270 | char *buf) |
| 1257 | 1271 | { |
| 1258 | − unsigned int ports = mtype_get_type_group_id(mtype) + 1; | |
| 1272 | + struct mtty_type *type = container_of(mtype, struct mtty_type, type); | |
| 1259 | 1273 | |
| 1260 | − return sprintf(buf, "%d\n", atomic_read(&mdev_avail_ports) / ports); | |
| 1274 | + return sprintf(buf, "%d\n", atomic_read(&mdev_avail_ports) / | |
| 1275 | + type->nr_ports); | |
| 1261 | 1276 | } |
| 1262 | 1277 | |
| 1263 | 1278 | static MDEV_TYPE_ATTR_RO(available_instances); |
| @@ -1270,29 +1285,13 @@ static ssize_t device_api_show(struct mdev_type *mtype, · 6 unmodified lines | ||
| 1270 | 1285 | |
| 1271 | 1286 | static MDEV_TYPE_ATTR_RO(device_api); |
| 1272 | 1287 | |
| 1273 | −static struct attribute *mdev_types_attrs[] = { | |
| 1288 | +static const struct attribute *mdev_types_attrs[] = { | |
| 1274 | 1289 | &mdev_type_attr_name.attr, |
| 1275 | 1290 | &mdev_type_attr_device_api.attr, |
| 1276 | 1291 | &mdev_type_attr_available_instances.attr, |
| 1277 | 1292 | NULL, |
| 1278 | 1293 | }; |
| 1279 | 1294 | |
| 1280 | −static struct attribute_group mdev_type_group1 = { | |
| 1281 | − .name = "1", | |
| 1282 | − .attrs = mdev_types_attrs, | |
| 1283 | −}; | |
| 1284 | − | |
| 1285 | −static struct attribute_group mdev_type_group2 = { | |
| 1286 | − .name = "2", | |
| 1287 | − .attrs = mdev_types_attrs, | |
| 1288 | −}; | |
| 1289 | − | |
| 1290 | −static struct attribute_group *mdev_type_groups[] = { | |
| 1291 | − &mdev_type_group1, | |
| 1292 | − &mdev_type_group2, | |
| 1293 | − NULL, | |
| 1294 | −}; | |
| 1295 | − | |
| 1296 | 1295 | static const struct vfio_device_ops mtty_dev_ops = { |
| 1297 | 1296 | .name = "vfio-mtty", |
| 1298 | 1297 | .init = mtty_init_dev, |
| @@ -1311,7 +1310,7 @@ static struct mdev_driver mtty_driver = { · 12 unmodified lines | ||
| 1311 | 1310 | }, |
| 1312 | 1311 | .probe = mtty_probe, |
| 1313 | 1312 | .remove = mtty_remove, |
| 1314 | − .supported_type_groups = mdev_type_groups, | |
| 1313 | + .types_attrs = mdev_types_attrs, | |
| 1315 | 1314 | }; |
| 1316 | 1315 | |
| 1317 | 1316 | static void mtty_device_release(struct device *dev) |
| @@ -1363,7 +1362,8 @@ static int __init mtty_dev_init(void) · 45 unmodified lines | ||
| 1363 | 1362 | goto err_class; |
| 1364 | 1363 | |
| 1365 | 1364 | ret = mdev_register_parent(&mtty_dev.parent, &mtty_dev.dev, |
| 1366 | − &mtty_driver); | |
| 1365 | + &mtty_driver, mtty_mdev_types, | |
| 1366 | + ARRAY_SIZE(mtty_mdev_types)); | |
| 1367 | 1367 | if (ret) |
| 1368 | 1368 | goto err_device; |
| 1369 | 1369 | return 0; |