========== Test ioctl ========== .. code-block:: c #include #include #include #include #include #include #include #include #include #include "tst_test.h" #include "hwbus-io.h" #define DEV_PATH "/dev/hwbusc" #define SYSFS_PCI_PATH "/sys/bus/pci/devices/0000:02:00.0/" static int fd = -1; static uint16_t read_sysfs_hex16(const char *rel_path) { FILE *fp; uint16_t val = 0; char full_path[256]; snprintf(full_path, sizeof(full_path), "%s%s", SYSFS_PCI_PATH, rel_path); fp = fopen(full_path, "r"); if (!fp) tst_brk(TBROK | TERRNO, "Failed to open %s", full_path); if (fscanf(fp, "0x%" SCNx16, &val) != 1) { fclose(fp); tst_brk(TBROK, "Failed to parse hex value from %s", full_path); } fclose(fp); return val; } static uint8_t read_sysfs_hex8(const char *rel_path) { FILE *fp; unsigned int val = 0; char full_path[256]; snprintf(full_path, sizeof(full_path), "%s%s", SYSFS_PCI_PATH, rel_path); fp = fopen(full_path, "r"); if (!fp) tst_brk(TBROK | TERRNO, "Failed to open %s", full_path); if (fscanf(fp, "0x%x", &val) != 1) { fclose(fp); tst_brk(TBROK, "Failed to parse hex value from %s", full_path); } fclose(fp); return (uint8_t)val; } static void setup(void) { fd = open(DEV_PATH, O_RDWR); if (fd < 0) fd = open(DEV_PATH, O_RDONLY); if (fd < 0) tst_brk(TBROK | TERRNO, "Failed to open %s", DEV_PATH); } static void cleanup(void) { if (fd >= 0) close(fd); } static void test_pci_ids_ioctl(void) { uint16_t exp_vendor = read_sysfs_hex16("vendor"); uint16_t exp_device = read_sysfs_hex16("device"); uint16_t act_vendor = 0, act_device = 0; if (ioctl(fd, HWBUS_IOC_READ_VENDOR, &act_vendor) < 0) { tst_res(TFAIL | TERRNO, "HWBUS_IOC_READ_VENDOR ioctl failed"); return; } if (ioctl(fd, HWBUS_IOC_READ_DEVICE, &act_device) < 0) { tst_res(TFAIL | TERRNO, "HWBUS_IOC_READ_DEVICE ioctl failed"); return; } if (act_vendor == exp_vendor && act_device == exp_device) { tst_res(TPASS, "IOCTL PCI IDs match SysFS (Vendor: 0x%04x, Device: 0x%04x)", act_vendor, act_device); } else { tst_res(TFAIL, "IOCTL PCI IDs mismatch: got Vendor=0x%04x Device=0x%04x, exp Vendor=0x%04x Device=0x%04x", act_vendor, act_device, exp_vendor, exp_device); } } static void test_data_widths(void) { uint8_t exp_rev = read_sysfs_hex8("revision"); uint8_t act_rev = 0; uint16_t cmd_reg = 0; uint32_t bar0_reg = 0; /* 8-bit read (Revision ID at offset 0x08) */ if (ioctl(fd, HWBUS_IOC_READ_REVISION, &act_rev) < 0) { tst_res(TFAIL | TERRNO, "8-bit IOCTL read failed"); } else if (act_rev == exp_rev) { tst_res(TPASS, "8-bit IOCTL read (Revision ID: 0x%02x) matches SysFS", act_rev); } else { tst_res(TFAIL, "8-bit IOCTL read mismatch: got 0x%02x, expected 0x%02x", act_rev, exp_rev); } /* 16-bit read (Command Register at offset 0x04) */ if (ioctl(fd, _IOR('L', 0x04, uint16_t), &cmd_reg) < 0) { tst_res(TFAIL | TERRNO, "16-bit IOCTL read (Command Reg) failed"); } else { tst_res(TPASS, "16-bit IOCTL read executed successfully (Cmd: 0x%04x)", cmd_reg); } /* 32-bit read (BAR0 Register at offset 0x10) */ if (ioctl(fd, _IOR('L', 0x10, uint32_t), &bar0_reg) < 0) { tst_res(TFAIL | TERRNO, "32-bit IOCTL read (BAR0) failed"); } else { tst_res(TPASS, "32-bit IOCTL read executed successfully (BAR0: 0x%08x)", bar0_reg); } } static void test_invalid_ioctl(void) { uint32_t dummy = 0; unsigned int invalid_cmd = _IOR('L', 0xFF, uint32_t); // Offset fuera de rango (> 0x3c) TST_EXP_FAIL(ioctl(fd, invalid_cmd, &dummy), ENOTTY, "Invalid IOCTL command rejection"); } static void run_tests(void) { test_pci_ids_ioctl(); test_data_widths(); test_invalid_ioctl(); } static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = run_tests, };