1 // SPDX-License-Identifier: GPL-2.0 2 #include <kunit/test.h> 3 #include <kunit/test-bug.h> 4 #include <linux/module.h> 5 #include <linux/miscdevice.h> 6 #include <linux/fs.h> 7 #include <linux/file.h> 8 #include <linux/fs_struct.h> 9 #include <linux/init_syscalls.h> 10 11 /* static minor (LCD_MINOR) */ 12 static struct miscdevice dev_static_minor = { 13 .minor = LCD_MINOR, 14 .name = "dev_static_minor", 15 }; 16 17 /* misc dynamic minor */ 18 static struct miscdevice dev_misc_dynamic_minor = { 19 .minor = MISC_DYNAMIC_MINOR, 20 .name = "dev_misc_dynamic_minor", 21 }; 22 23 static void kunit_static_minor(struct kunit *test) 24 { 25 int ret; 26 27 ret = misc_register(&dev_static_minor); 28 KUNIT_EXPECT_EQ(test, 0, ret); 29 KUNIT_EXPECT_EQ(test, LCD_MINOR, dev_static_minor.minor); 30 misc_deregister(&dev_static_minor); 31 } 32 33 static void kunit_misc_dynamic_minor(struct kunit *test) 34 { 35 int ret; 36 37 ret = misc_register(&dev_misc_dynamic_minor); 38 KUNIT_EXPECT_EQ(test, 0, ret); 39 misc_deregister(&dev_misc_dynamic_minor); 40 } 41 42 struct miscdev_test_case { 43 const char *str; 44 int minor; 45 }; 46 47 static struct miscdev_test_case miscdev_test_ranges[] = { 48 { 49 .str = "lower static range, top", 50 .minor = 15, 51 }, 52 { 53 .str = "upper static range, bottom", 54 .minor = 130, 55 }, 56 { 57 .str = "lower static range, bottom", 58 .minor = 0, 59 }, 60 { 61 .str = "upper static range, top", 62 .minor = MISC_DYNAMIC_MINOR - 1, 63 }, 64 }; 65 66 KUNIT_ARRAY_PARAM_DESC(miscdev, miscdev_test_ranges, str); 67 68 static int miscdev_find_minors(struct kunit_suite *suite) 69 { 70 int ret; 71 struct miscdevice miscstat = { 72 .name = "miscstat", 73 }; 74 int i; 75 76 for (i = 15; i >= 0; i--) { 77 miscstat.minor = i; 78 ret = misc_register(&miscstat); 79 if (ret == 0) 80 break; 81 } 82 83 if (ret == 0) { 84 kunit_info(suite, "found misc device minor %d available\n", 85 miscstat.minor); 86 miscdev_test_ranges[0].minor = miscstat.minor; 87 misc_deregister(&miscstat); 88 } else { 89 return ret; 90 } 91 92 for (i = 128; i < MISC_DYNAMIC_MINOR; i++) { 93 miscstat.minor = i; 94 ret = misc_register(&miscstat); 95 if (ret == 0) 96 break; 97 } 98 99 if (ret == 0) { 100 kunit_info(suite, "found misc device minor %d available\n", 101 miscstat.minor); 102 miscdev_test_ranges[1].minor = miscstat.minor; 103 misc_deregister(&miscstat); 104 } else { 105 return ret; 106 } 107 108 for (i = 0; i < miscdev_test_ranges[0].minor; i++) { 109 miscstat.minor = i; 110 ret = misc_register(&miscstat); 111 if (ret == 0) 112 break; 113 } 114 115 if (ret == 0) { 116 kunit_info(suite, "found misc device minor %d available\n", 117 miscstat.minor); 118 miscdev_test_ranges[2].minor = miscstat.minor; 119 misc_deregister(&miscstat); 120 } else { 121 return ret; 122 } 123 124 for (i = MISC_DYNAMIC_MINOR - 1; i > miscdev_test_ranges[1].minor; i--) { 125 miscstat.minor = i; 126 ret = misc_register(&miscstat); 127 if (ret == 0) 128 break; 129 } 130 131 if (ret == 0) { 132 kunit_info(suite, "found misc device minor %d available\n", 133 miscstat.minor); 134 miscdev_test_ranges[3].minor = miscstat.minor; 135 misc_deregister(&miscstat); 136 } 137 138 return ret; 139 } 140 141 static bool is_valid_dynamic_minor(int minor) 142 { 143 if (minor < 0) 144 return false; 145 return minor > MISC_DYNAMIC_MINOR; 146 } 147 148 static int miscdev_test_open(struct inode *inode, struct file *file) 149 { 150 return 0; 151 } 152 153 static const struct file_operations miscdev_test_fops = { 154 .open = miscdev_test_open, 155 }; 156 157 static void __init miscdev_test_can_open(struct kunit *test, struct miscdevice *misc) 158 { 159 int ret; 160 struct file *filp; 161 char *devname; 162 163 devname = kasprintf(GFP_KERNEL, "/dev/%s", misc->name); 164 165 /* Tests run in a nullfs kthread; borrow the init fs to resolve /dev. */ 166 scoped_with_init_fs() { 167 ret = init_mknod(devname, S_IFCHR | 0600, 168 new_encode_dev(MKDEV(MISC_MAJOR, misc->minor))); 169 if (ret != 0) 170 KUNIT_FAIL(test, "failed to create node\n"); 171 172 filp = filp_open(devname, O_RDONLY, 0); 173 if (IS_ERR(filp)) 174 KUNIT_FAIL(test, "failed to open misc device: %ld\n", PTR_ERR(filp)); 175 else 176 fput(filp); 177 178 init_unlink(devname); 179 } 180 kfree(devname); 181 } 182 183 static void __init miscdev_test_static_basic(struct kunit *test) 184 { 185 struct miscdevice misc_test = { 186 .name = "misc_test", 187 .fops = &miscdev_test_fops, 188 }; 189 int ret; 190 const struct miscdev_test_case *params = test->param_value; 191 192 misc_test.minor = params->minor; 193 194 ret = misc_register(&misc_test); 195 KUNIT_EXPECT_EQ(test, ret, 0); 196 KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor); 197 198 if (ret == 0) { 199 miscdev_test_can_open(test, &misc_test); 200 misc_deregister(&misc_test); 201 } 202 } 203 204 static void __init miscdev_test_dynamic_basic(struct kunit *test) 205 { 206 struct miscdevice misc_test = { 207 .minor = MISC_DYNAMIC_MINOR, 208 .name = "misc_test", 209 .fops = &miscdev_test_fops, 210 }; 211 int ret; 212 213 ret = misc_register(&misc_test); 214 KUNIT_EXPECT_EQ(test, ret, 0); 215 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc_test.minor)); 216 217 if (ret == 0) { 218 miscdev_test_can_open(test, &misc_test); 219 misc_deregister(&misc_test); 220 } 221 } 222 223 static void miscdev_test_twice(struct kunit *test) 224 { 225 struct miscdevice misc_test = { 226 .name = "misc_test", 227 .fops = &miscdev_test_fops, 228 }; 229 int ret; 230 const struct miscdev_test_case *params = test->param_value; 231 232 misc_test.minor = params->minor; 233 234 ret = misc_register(&misc_test); 235 KUNIT_EXPECT_EQ(test, ret, 0); 236 KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor); 237 if (ret == 0) 238 misc_deregister(&misc_test); 239 240 ret = misc_register(&misc_test); 241 KUNIT_EXPECT_EQ(test, ret, 0); 242 KUNIT_EXPECT_EQ(test, misc_test.minor, params->minor); 243 if (ret == 0) 244 misc_deregister(&misc_test); 245 } 246 247 static void miscdev_test_duplicate_minor(struct kunit *test) 248 { 249 struct miscdevice misc1 = { 250 .name = "misc1", 251 .fops = &miscdev_test_fops, 252 }; 253 struct miscdevice misc2 = { 254 .name = "misc2", 255 .fops = &miscdev_test_fops, 256 }; 257 int ret; 258 const struct miscdev_test_case *params = test->param_value; 259 260 misc1.minor = params->minor; 261 misc2.minor = params->minor; 262 263 ret = misc_register(&misc1); 264 KUNIT_EXPECT_EQ(test, ret, 0); 265 KUNIT_EXPECT_EQ(test, misc1.minor, params->minor); 266 267 ret = misc_register(&misc2); 268 KUNIT_EXPECT_EQ(test, ret, -EBUSY); 269 if (ret == 0) 270 misc_deregister(&misc2); 271 272 misc_deregister(&misc1); 273 } 274 275 static void miscdev_test_duplicate_name(struct kunit *test) 276 { 277 struct miscdevice misc1 = { 278 .minor = MISC_DYNAMIC_MINOR, 279 .name = "misc1", 280 .fops = &miscdev_test_fops, 281 }; 282 struct miscdevice misc2 = { 283 .minor = MISC_DYNAMIC_MINOR, 284 .name = "misc1", 285 .fops = &miscdev_test_fops, 286 }; 287 int ret; 288 289 ret = misc_register(&misc1); 290 KUNIT_EXPECT_EQ(test, ret, 0); 291 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc1.minor)); 292 293 ret = misc_register(&misc2); 294 KUNIT_EXPECT_EQ(test, ret, -EEXIST); 295 if (ret == 0) 296 misc_deregister(&misc2); 297 298 misc_deregister(&misc1); 299 } 300 301 /* 302 * Test that after a duplicate name failure, the reserved minor number is 303 * freed to be allocated next. 304 */ 305 static void miscdev_test_duplicate_name_leak(struct kunit *test) 306 { 307 struct miscdevice misc1 = { 308 .minor = MISC_DYNAMIC_MINOR, 309 .name = "misc1", 310 .fops = &miscdev_test_fops, 311 }; 312 struct miscdevice misc2 = { 313 .minor = MISC_DYNAMIC_MINOR, 314 .name = "misc1", 315 .fops = &miscdev_test_fops, 316 }; 317 struct miscdevice misc3 = { 318 .minor = MISC_DYNAMIC_MINOR, 319 .name = "misc3", 320 .fops = &miscdev_test_fops, 321 }; 322 int ret; 323 int dyn_minor; 324 325 ret = misc_register(&misc1); 326 KUNIT_EXPECT_EQ(test, ret, 0); 327 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc1.minor)); 328 329 /* 330 * Find out what is the next minor number available. 331 */ 332 ret = misc_register(&misc3); 333 KUNIT_EXPECT_EQ(test, ret, 0); 334 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc3.minor)); 335 dyn_minor = misc3.minor; 336 misc_deregister(&misc3); 337 misc3.minor = MISC_DYNAMIC_MINOR; 338 339 ret = misc_register(&misc2); 340 KUNIT_EXPECT_EQ(test, ret, -EEXIST); 341 if (ret == 0) 342 misc_deregister(&misc2); 343 344 /* 345 * Now check that we can still get the same minor we found before. 346 */ 347 ret = misc_register(&misc3); 348 KUNIT_EXPECT_EQ(test, ret, 0); 349 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(misc3.minor)); 350 KUNIT_EXPECT_EQ(test, misc3.minor, dyn_minor); 351 misc_deregister(&misc3); 352 353 misc_deregister(&misc1); 354 } 355 356 /* 357 * Try to register a static minor with a duplicate name. That might not 358 * deallocate the minor, preventing it from being used again. 359 */ 360 static void miscdev_test_duplicate_error(struct kunit *test) 361 { 362 struct miscdevice miscdyn = { 363 .minor = MISC_DYNAMIC_MINOR, 364 .name = "name1", 365 .fops = &miscdev_test_fops, 366 }; 367 struct miscdevice miscstat = { 368 .name = "name1", 369 .fops = &miscdev_test_fops, 370 }; 371 struct miscdevice miscnew = { 372 .name = "name2", 373 .fops = &miscdev_test_fops, 374 }; 375 int ret; 376 const struct miscdev_test_case *params = test->param_value; 377 378 miscstat.minor = params->minor; 379 miscnew.minor = params->minor; 380 381 ret = misc_register(&miscdyn); 382 KUNIT_EXPECT_EQ(test, ret, 0); 383 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor)); 384 385 ret = misc_register(&miscstat); 386 KUNIT_EXPECT_EQ(test, ret, -EEXIST); 387 if (ret == 0) 388 misc_deregister(&miscstat); 389 390 ret = misc_register(&miscnew); 391 KUNIT_EXPECT_EQ(test, ret, 0); 392 KUNIT_EXPECT_EQ(test, miscnew.minor, params->minor); 393 if (ret == 0) 394 misc_deregister(&miscnew); 395 396 misc_deregister(&miscdyn); 397 } 398 399 static void __init miscdev_test_dynamic_only_range(struct kunit *test) 400 { 401 int ret; 402 struct miscdevice *miscdev; 403 const int dynamic_minors = 256; 404 int i; 405 406 miscdev = kunit_kmalloc_array(test, dynamic_minors, 407 sizeof(struct miscdevice), 408 GFP_KERNEL | __GFP_ZERO); 409 410 for (i = 0; i < dynamic_minors; i++) { 411 miscdev[i].minor = MISC_DYNAMIC_MINOR; 412 miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i); 413 miscdev[i].fops = &miscdev_test_fops; 414 ret = misc_register(&miscdev[i]); 415 if (ret != 0) 416 break; 417 /* 418 * This is the bug we are looking for! 419 * We asked for a dynamic minor and got a minor in the static range space. 420 */ 421 if (miscdev[i].minor >= 0 && miscdev[i].minor <= 15) { 422 KUNIT_FAIL(test, "misc_register allocated minor %d\n", miscdev[i].minor); 423 i++; 424 break; 425 } 426 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor)); 427 } 428 429 for (i--; i >= 0; i--) { 430 miscdev_test_can_open(test, &miscdev[i]); 431 misc_deregister(&miscdev[i]); 432 kfree_const(miscdev[i].name); 433 } 434 435 KUNIT_EXPECT_EQ(test, ret, 0); 436 } 437 438 static void __init miscdev_test_collision(struct kunit *test) 439 { 440 int ret; 441 struct miscdevice *miscdev; 442 struct miscdevice miscstat = { 443 .name = "miscstat", 444 .fops = &miscdev_test_fops, 445 }; 446 const int dynamic_minors = 256; 447 int i; 448 449 miscdev = kunit_kmalloc_array(test, dynamic_minors, 450 sizeof(struct miscdevice), 451 GFP_KERNEL | __GFP_ZERO); 452 453 miscstat.minor = miscdev_test_ranges[0].minor; 454 ret = misc_register(&miscstat); 455 KUNIT_ASSERT_EQ(test, ret, 0); 456 KUNIT_EXPECT_EQ(test, miscstat.minor, miscdev_test_ranges[0].minor); 457 458 for (i = 0; i < dynamic_minors; i++) { 459 miscdev[i].minor = MISC_DYNAMIC_MINOR; 460 miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i); 461 miscdev[i].fops = &miscdev_test_fops; 462 ret = misc_register(&miscdev[i]); 463 if (ret != 0) 464 break; 465 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor)); 466 } 467 468 for (i--; i >= 0; i--) { 469 miscdev_test_can_open(test, &miscdev[i]); 470 misc_deregister(&miscdev[i]); 471 kfree_const(miscdev[i].name); 472 } 473 474 misc_deregister(&miscstat); 475 476 KUNIT_EXPECT_EQ(test, ret, 0); 477 } 478 479 static void __init miscdev_test_collision_reverse(struct kunit *test) 480 { 481 int ret; 482 struct miscdevice *miscdev; 483 struct miscdevice miscstat = { 484 .name = "miscstat", 485 .fops = &miscdev_test_fops, 486 }; 487 const int dynamic_minors = 256; 488 int i; 489 490 miscdev = kunit_kmalloc_array(test, dynamic_minors, 491 sizeof(struct miscdevice), 492 GFP_KERNEL | __GFP_ZERO); 493 494 for (i = 0; i < dynamic_minors; i++) { 495 miscdev[i].minor = MISC_DYNAMIC_MINOR; 496 miscdev[i].name = kasprintf(GFP_KERNEL, "misc_test%d", i); 497 miscdev[i].fops = &miscdev_test_fops; 498 ret = misc_register(&miscdev[i]); 499 if (ret != 0) 500 break; 501 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdev[i].minor)); 502 } 503 504 KUNIT_EXPECT_EQ(test, ret, 0); 505 506 miscstat.minor = miscdev_test_ranges[0].minor; 507 ret = misc_register(&miscstat); 508 KUNIT_EXPECT_EQ(test, ret, 0); 509 KUNIT_EXPECT_EQ(test, miscstat.minor, miscdev_test_ranges[0].minor); 510 if (ret == 0) 511 misc_deregister(&miscstat); 512 513 for (i--; i >= 0; i--) { 514 miscdev_test_can_open(test, &miscdev[i]); 515 misc_deregister(&miscdev[i]); 516 kfree_const(miscdev[i].name); 517 } 518 } 519 520 static void __init miscdev_test_conflict(struct kunit *test) 521 { 522 int ret; 523 struct miscdevice miscdyn = { 524 .name = "miscdyn", 525 .minor = MISC_DYNAMIC_MINOR, 526 .fops = &miscdev_test_fops, 527 }; 528 struct miscdevice miscstat = { 529 .name = "miscstat", 530 .fops = &miscdev_test_fops, 531 }; 532 533 ret = misc_register(&miscdyn); 534 KUNIT_ASSERT_EQ(test, ret, 0); 535 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor)); 536 537 /* 538 * Try to register a static minor with the same minor as the 539 * dynamic one. 540 */ 541 miscstat.minor = miscdyn.minor; 542 ret = misc_register(&miscstat); 543 KUNIT_EXPECT_EQ(test, ret, -EINVAL); 544 if (ret == 0) 545 misc_deregister(&miscstat); 546 547 miscdev_test_can_open(test, &miscdyn); 548 549 misc_deregister(&miscdyn); 550 } 551 552 static void __init miscdev_test_conflict_reverse(struct kunit *test) 553 { 554 int ret; 555 struct miscdevice miscdyn = { 556 .name = "miscdyn", 557 .minor = MISC_DYNAMIC_MINOR, 558 .fops = &miscdev_test_fops, 559 }; 560 struct miscdevice miscstat = { 561 .name = "miscstat", 562 .fops = &miscdev_test_fops, 563 }; 564 565 /* 566 * Find the first available dynamic minor to use it as a static 567 * minor later on. 568 */ 569 ret = misc_register(&miscdyn); 570 KUNIT_ASSERT_EQ(test, ret, 0); 571 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor)); 572 miscstat.minor = miscdyn.minor; 573 misc_deregister(&miscdyn); 574 575 ret = misc_register(&miscstat); 576 KUNIT_EXPECT_EQ(test, ret, -EINVAL); 577 if (ret == 0) 578 misc_deregister(&miscstat); 579 580 /* 581 * Try to register a dynamic minor after registering a static minor 582 * within the dynamic range. It should work but get a different 583 * minor. 584 */ 585 miscdyn.minor = MISC_DYNAMIC_MINOR; 586 ret = misc_register(&miscdyn); 587 KUNIT_EXPECT_EQ(test, ret, 0); 588 KUNIT_EXPECT_EQ(test, miscdyn.minor, miscstat.minor); 589 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn.minor)); 590 if (ret == 0) 591 misc_deregister(&miscdyn); 592 } 593 594 /* Take minor(> MISC_DYNAMIC_MINOR) as invalid when register miscdevice */ 595 static void miscdev_test_invalid_input(struct kunit *test) 596 { 597 struct miscdevice misc_test = { 598 .minor = MISC_DYNAMIC_MINOR + 1, 599 .name = "misc_test", 600 .fops = &miscdev_test_fops, 601 }; 602 int ret; 603 604 ret = misc_register(&misc_test); 605 KUNIT_EXPECT_EQ(test, ret, -EINVAL); 606 if (ret == 0) 607 misc_deregister(&misc_test); 608 } 609 610 /* 611 * Verify if @miscdyn_a can still be registered successfully without 612 * reinitialization even if its minor ever owned was requested by 613 * another miscdevice such as @miscdyn_b. 614 */ 615 static void miscdev_test_dynamic_reentry(struct kunit *test) 616 { 617 struct miscdevice miscdyn_a = { 618 .name = "miscdyn_a", 619 .minor = MISC_DYNAMIC_MINOR, 620 .fops = &miscdev_test_fops, 621 }; 622 struct miscdevice miscdyn_b = { 623 .name = "miscdyn_b", 624 .minor = MISC_DYNAMIC_MINOR, 625 .fops = &miscdev_test_fops, 626 }; 627 int ret, minor_a; 628 629 ret = misc_register(&miscdyn_a); 630 KUNIT_ASSERT_EQ(test, ret, 0); 631 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn_a.minor)); 632 minor_a = miscdyn_a.minor; 633 if (ret != 0) 634 return; 635 misc_deregister(&miscdyn_a); 636 637 ret = misc_register(&miscdyn_b); 638 KUNIT_ASSERT_EQ(test, ret, 0); 639 KUNIT_EXPECT_EQ(test, miscdyn_b.minor, minor_a); 640 if (ret != 0) 641 return; 642 643 ret = misc_register(&miscdyn_a); 644 KUNIT_ASSERT_EQ(test, ret, 0); 645 KUNIT_EXPECT_TRUE(test, is_valid_dynamic_minor(miscdyn_a.minor)); 646 KUNIT_EXPECT_NE(test, miscdyn_a.minor, miscdyn_b.minor); 647 if (ret == 0) 648 misc_deregister(&miscdyn_a); 649 650 misc_deregister(&miscdyn_b); 651 } 652 653 static struct kunit_case test_cases[] = { 654 KUNIT_CASE(kunit_static_minor), 655 KUNIT_CASE(kunit_misc_dynamic_minor), 656 KUNIT_CASE(miscdev_test_invalid_input), 657 KUNIT_CASE_PARAM(miscdev_test_twice, miscdev_gen_params), 658 KUNIT_CASE_PARAM(miscdev_test_duplicate_minor, miscdev_gen_params), 659 KUNIT_CASE(miscdev_test_duplicate_name), 660 KUNIT_CASE(miscdev_test_duplicate_name_leak), 661 KUNIT_CASE_PARAM(miscdev_test_duplicate_error, miscdev_gen_params), 662 KUNIT_CASE(miscdev_test_dynamic_reentry), 663 {} 664 }; 665 666 static struct kunit_suite test_suite = { 667 .name = "miscdev", 668 .suite_init = miscdev_find_minors, 669 .test_cases = test_cases, 670 }; 671 kunit_test_suite(test_suite); 672 673 static struct kunit_case __refdata test_init_cases[] = { 674 KUNIT_CASE_PARAM(miscdev_test_static_basic, miscdev_gen_params), 675 KUNIT_CASE(miscdev_test_dynamic_basic), 676 KUNIT_CASE(miscdev_test_dynamic_only_range), 677 KUNIT_CASE(miscdev_test_collision), 678 KUNIT_CASE(miscdev_test_collision_reverse), 679 KUNIT_CASE(miscdev_test_conflict), 680 KUNIT_CASE(miscdev_test_conflict_reverse), 681 {} 682 }; 683 684 static struct kunit_suite test_init_suite = { 685 .name = "miscdev_init", 686 .suite_init = miscdev_find_minors, 687 .test_cases = test_init_cases, 688 }; 689 kunit_test_init_section_suite(test_init_suite); 690 691 MODULE_LICENSE("GPL"); 692 MODULE_AUTHOR("Vimal Agrawal"); 693 MODULE_AUTHOR("Thadeu Lima de Souza Cascardo <cascardo@igalia.com>"); 694 MODULE_DESCRIPTION("Test module for misc character devices"); 695