···713713 INIT_LIST_HEAD(&report_enum->report_list);714714 }715715716716- kfree(device->rdesc);716716+ /*717717+ * If the HID driver had a rdesc_fixup() callback, dev->rdesc718718+ * will be allocated by hid-core and needs to be freed.719719+ * Otherwise, it is either equal to dev_rdesc or bpf_rdesc, in720720+ * which cases it'll be freed later on device removal or destroy.721721+ */722722+ if (device->rdesc != device->dev_rdesc && device->rdesc != device->bpf_rdesc)723723+ kfree(device->rdesc);717724 device->rdesc = NULL;718725 device->rsize = 0;719726···733726 device->status &= ~HID_STAT_PARSED;734727}735728729729+static inline void hid_free_bpf_rdesc(struct hid_device *hdev)730730+{731731+ /* bpf_rdesc is either equal to dev_rdesc or allocated by call_hid_bpf_rdesc_fixup() */732732+ if (hdev->bpf_rdesc != hdev->dev_rdesc)733733+ kfree(hdev->bpf_rdesc);734734+ hdev->bpf_rdesc = NULL;735735+}736736+736737/*737738 * Free a device structure, all reports, and all fields.738739 */···750735 struct hid_device *hid = container_of(ref, struct hid_device, ref);751736752737 hid_close_report(hid);738738+ hid_free_bpf_rdesc(hid);753739 kfree(hid->dev_rdesc);754740 kfree(hid);755741}···12431227 struct hid_item item;12441228 unsigned int size;12451229 const __u8 *start;12461246- __u8 *buf;12471230 const __u8 *end;12481231 const __u8 *next;12491232 int ret;···12581243 if (WARN_ON(device->status & HID_STAT_PARSED))12591244 return -EBUSY;1260124512611261- start = device->dev_rdesc;12461246+ start = device->bpf_rdesc;12621247 if (WARN_ON(!start))12631248 return -ENODEV;12641264- size = device->dev_rsize;12491249+ size = device->bpf_rsize;1265125012661266- /* call_hid_bpf_rdesc_fixup() ensures we work on a copy of rdesc */12671267- buf = call_hid_bpf_rdesc_fixup(device, start, &size);12681268- if (buf == NULL)12691269- return -ENOMEM;12511251+ if (device->driver->report_fixup) {12521252+ /*12531253+ * device->driver->report_fixup() needs to work12541254+ * on a copy of our report descriptor so it can12551255+ * change it.12561256+ */12571257+ __u8 *buf = kmemdup(start, size, GFP_KERNEL);1270125812711271- if (device->driver->report_fixup)12591259+ if (buf == NULL)12601260+ return -ENOMEM;12611261+12721262 start = device->driver->report_fixup(device, buf, &size);12731273- else12741274- start = buf;1275126312761276- start = kmemdup(start, size, GFP_KERNEL);12771277- kfree(buf);12781278- if (start == NULL)12791279- return -ENOMEM;12641264+ /*12651265+ * The second kmemdup is required in case report_fixup() returns12661266+ * a static read-only memory, but we have no idea if that memory12671267+ * needs to be cleaned up or not at the end.12681268+ */12691269+ start = kmemdup(start, size, GFP_KERNEL);12701270+ kfree(buf);12711271+ if (start == NULL)12721272+ return -ENOMEM;12731273+ }1280127412811275 device->rdesc = start;12821276 device->rsize = size;···26802656 /*26812657 * hid-generic implements .match(), so we must be dealing with a26822658 * different HID driver here, and can simply check if26832683- * hid_ignore_special_drivers is set or not.26592659+ * hid_ignore_special_drivers or HID_QUIRK_IGNORE_SPECIAL_DRIVER26602660+ * are set or not.26842661 */26852685- return !hid_ignore_special_drivers;26622662+ return !hid_ignore_special_drivers && !(hdev->quirks & HID_QUIRK_IGNORE_SPECIAL_DRIVER);26862663}2687266426882665static int __hid_device_probe(struct hid_device *hdev, struct hid_driver *hdrv)26892666{26902667 const struct hid_device_id *id;26912668 int ret;26692669+26702670+ if (!hdev->bpf_rsize) {26712671+ unsigned int quirks;26722672+26732673+ /* reset the quirks that has been previously set */26742674+ quirks = hid_lookup_quirk(hdev);26752675+ hdev->quirks = quirks;26762676+26772677+ /* in case a bpf program gets detached, we need to free the old one */26782678+ hid_free_bpf_rdesc(hdev);26792679+26802680+ /* keep this around so we know we called it once */26812681+ hdev->bpf_rsize = hdev->dev_rsize;26822682+26832683+ /* call_hid_bpf_rdesc_fixup will always return a valid pointer */26842684+ hdev->bpf_rdesc = call_hid_bpf_rdesc_fixup(hdev, hdev->dev_rdesc,26852685+ &hdev->bpf_rsize);26862686+ if (quirks ^ hdev->quirks)26872687+ hid_info(hdev, "HID-BPF toggled quirks on the device: %04x",26882688+ quirks ^ hdev->quirks);26892689+ }2692269026932691 if (!hid_check_device_match(hdev, hdrv, &id))26942692 return -ENODEV;···27192673 if (!hdev->devres_group_id)27202674 return -ENOMEM;2721267527222722- /* reset the quirks that has been previously set */27232723- hdev->quirks = hid_lookup_quirk(hdev);27242676 hdev->driver = hdrv;2725267727262678 if (hdrv->probe) {···29662922 hid_debug_unregister(hdev);29672923 hdev->status &= ~HID_STAT_ADDED;29682924 }29252925+ hid_free_bpf_rdesc(hdev);29692926 kfree(hdev->dev_rdesc);29702927 hdev->dev_rdesc = NULL;29712928 hdev->dev_rsize = 0;29292929+ hdev->bpf_rsize = 0;29722930}2973293129742932/**
+3
drivers/hid/hid-generic.c
···4040 if (ignore_special_driver)4141 return true;42424343+ if (hdev->quirks & HID_QUIRK_IGNORE_SPECIAL_DRIVER)4444+ return true;4545+4346 if (hdev->quirks & HID_QUIRK_HAVE_SPECIAL_DRIVER)4447 return false;4548
+12-8
include/linux/hid.h
···359359 * | @HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP:360360 * | @HID_QUIRK_HAVE_SPECIAL_DRIVER:361361 * | @HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE:362362+ * | @HID_QUIRK_IGNORE_SPECIAL_DRIVER362363 * | @HID_QUIRK_FULLSPEED_INTERVAL:363364 * | @HID_QUIRK_NO_INIT_REPORTS:364365 * | @HID_QUIRK_NO_IGNORE:···385384#define HID_QUIRK_HAVE_SPECIAL_DRIVER BIT(19)386385#define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE BIT(20)387386#define HID_QUIRK_NOINVERT BIT(21)387387+#define HID_QUIRK_IGNORE_SPECIAL_DRIVER BIT(22)388388#define HID_QUIRK_FULLSPEED_INTERVAL BIT(28)389389#define HID_QUIRK_NO_INIT_REPORTS BIT(29)390390#define HID_QUIRK_NO_IGNORE BIT(30)···601599struct hid_driver;602600struct hid_ll_driver;603601604604-struct hid_device { /* device report descriptor */605605- const __u8 *dev_rdesc;606606- unsigned dev_rsize;607607- const __u8 *rdesc;608608- unsigned rsize;602602+struct hid_device {603603+ const __u8 *dev_rdesc; /* device report descriptor */604604+ const __u8 *bpf_rdesc; /* bpf modified report descriptor, if any */605605+ const __u8 *rdesc; /* currently used report descriptor */606606+ unsigned int dev_rsize;607607+ unsigned int bpf_rsize;608608+ unsigned int rsize;609609+ unsigned int collection_size; /* Number of allocated hid_collections */609610 struct hid_collection *collection; /* List of HID collections */610610- unsigned collection_size; /* Number of allocated hid_collections */611611- unsigned maxcollection; /* Number of parsed collections */612612- unsigned maxapplication; /* Number of applications */611611+ unsigned int maxcollection; /* Number of parsed collections */612612+ unsigned int maxapplication; /* Number of applications */613613 __u16 bus; /* BUS ID */614614 __u16 group; /* Report group */615615 __u32 vendor; /* Vendor ID */
+3-8
include/linux/hid_bpf.h
···212212void hid_bpf_disconnect_device(struct hid_device *hdev);213213void hid_bpf_destroy_device(struct hid_device *hid);214214int hid_bpf_device_init(struct hid_device *hid);215215-u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size);215215+const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc, unsigned int *size);216216#else /* CONFIG_HID_BPF */217217static inline u8 *dispatch_hid_bpf_device_event(struct hid_device *hid, enum hid_report_type type,218218 u8 *data, u32 *size, int interrupt,···228228static inline void hid_bpf_disconnect_device(struct hid_device *hdev) {}229229static inline void hid_bpf_destroy_device(struct hid_device *hid) {}230230static inline int hid_bpf_device_init(struct hid_device *hid) { return 0; }231231-/*232232- * This specialized allocator has to be a macro for its allocations to be233233- * accounted separately (to have a separate alloc_tag). The typecast is234234- * intentional to enforce typesafety.235235- */236236-#define call_hid_bpf_rdesc_fixup(_hdev, _rdesc, _size) \237237- ((u8 *)kmemdup(_rdesc, *(_size), GFP_KERNEL))231231+static inline const u8 *call_hid_bpf_rdesc_fixup(struct hid_device *hdev, const u8 *rdesc,232232+ unsigned int *size) { return rdesc; }238233239234#endif /* CONFIG_HID_BPF */240235
+1-1
tools/testing/selftests/hid/Makefile
···232232 $(Q)$(BPFTOOL) gen object $(<:.o=.linked1.o) $<233233 $(Q)$(BPFTOOL) gen skeleton $(<:.o=.linked1.o) name $(notdir $(<:.bpf.o=)) > $@234234235235-$(OUTPUT)/%.o: %.c $(BPF_SKELS)235235+$(OUTPUT)/%.o: %.c $(BPF_SKELS) hid_common.h236236 $(call msg,CC,,$@)237237 $(Q)$(CC) $(CFLAGS) -c $(filter %.c,$^) $(LDLIBS) -o $@238238
+102-47
tools/testing/selftests/hid/hid_bpf.c
···44#include "hid_common.h"55#include <bpf/bpf.h>6677-struct attach_prog_args {88- int prog_fd;99- unsigned int hid;1010- int retval;1111- int insert_head;1212-};1313-147struct hid_hw_request_syscall_args {158 __u8 data[10];169 unsigned int hid;···1421};15221623FIXTURE(hid_bpf) {1717- int dev_id;1818- int uhid_fd;2424+ struct uhid_device hid;1925 int hidraw_fd;2020- int hid_id;2121- pthread_t tid;2226 struct hid *skel;2327 struct bpf_link *hid_links[3]; /* max number of programs loaded in a single test */2428};···4454FIXTURE_TEARDOWN(hid_bpf) {4555 void *uhid_err;46564747- uhid_destroy(_metadata, self->uhid_fd);5757+ uhid_destroy(_metadata, &self->hid);48584959 detach_bpf(self);5050- pthread_join(self->tid, &uhid_err);6060+ pthread_join(self->hid.tid, &uhid_err);5161}5262#define TEARDOWN_LOG(fmt, ...) do { \5363 TH_LOG(fmt, ##__VA_ARGS__); \5464 hid_bpf_teardown(_metadata, self, variant); \5565} while (0)56666767+struct specific_device {6868+ const char test_name[64];6969+ __u16 bus;7070+ __u32 vid;7171+ __u32 pid;7272+};7373+5774FIXTURE_SETUP(hid_bpf)5875{5959- time_t t;7676+ const struct specific_device *match = NULL;6077 int err;61786262- /* initialize random number generator */6363- srand((unsigned int)time(&t));7979+ const struct specific_device devices[] = {8080+ {8181+ .test_name = "test_hid_driver_probe",8282+ .bus = BUS_BLUETOOTH,8383+ .vid = 0x05ac, /* USB_VENDOR_ID_APPLE */8484+ .pid = 0x022c, /* USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI */8585+ }, {8686+ .test_name = "*",8787+ .bus = BUS_USB,8888+ .vid = 0x0001,8989+ .pid = 0x0a36,9090+ }};64916565- self->dev_id = rand() % 1024;9292+ for (int i = 0; i < ARRAY_SIZE(devices); i++) {9393+ match = &devices[i];9494+ if (!strncmp(_metadata->name, devices[i].test_name, sizeof(devices[i].test_name)))9595+ break;9696+ }66976767- self->uhid_fd = setup_uhid(_metadata, self->dev_id);9898+ ASSERT_OK_PTR(match);68996969- /* locate the uev, self, variant);ent file of the created device */7070- self->hid_id = get_hid_id(self->dev_id);7171- ASSERT_GT(self->hid_id, 0)7272- TEARDOWN_LOG("Could not locate uhid device id: %d", self->hid_id);7373-7474- err = uhid_start_listener(_metadata, &self->tid, self->uhid_fd);7575- ASSERT_EQ(0, err) TEARDOWN_LOG("could not start udev listener: %d", err);100100+ err = setup_uhid(_metadata, &self->hid, match->bus, match->vid, match->pid,101101+ rdesc, sizeof(rdesc));102102+ ASSERT_OK(err);76103}7710478105struct test_program {···136129 ops_hid_id = bpf_map__initial_value(map, NULL);137130 ASSERT_OK_PTR(ops_hid_id) TH_LOG("unable to retrieve struct_ops data");138131139139- *ops_hid_id = self->hid_id;132132+ *ops_hid_id = self->hid.hid_id;140133 }141134142135 /* we disable the auto-attach feature of all maps because we···164157165158 hid__attach(self->skel);166159167167- self->hidraw_fd = open_hidraw(self->dev_id);160160+ self->hidraw_fd = open_hidraw(&self->hid);168161 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");169162}170163···199192 /* inject one event */200193 buf[0] = 1;201194 buf[1] = 42;202202- uhid_send_event(_metadata, self->uhid_fd, buf, 6);195195+ uhid_send_event(_metadata, &self->hid, buf, 6);203196204197 /* check that hid_first_event() was executed */205198 ASSERT_EQ(self->skel->data->callback_check, 42) TH_LOG("callback_check1");···215208 memset(buf, 0, sizeof(buf));216209 buf[0] = 1;217210 buf[1] = 47;218218- uhid_send_event(_metadata, self->uhid_fd, buf, 6);211211+ uhid_send_event(_metadata, &self->hid, buf, 6);219212220213 /* check that hid_first_event() was executed */221214 ASSERT_EQ(self->skel->data->callback_check, 47) TH_LOG("callback_check1");···246239 /* inject one event */247240 buf[0] = 1;248241 buf[1] = 42;249249- uhid_send_event(_metadata, self->uhid_fd, buf, 6);242242+ uhid_send_event(_metadata, &self->hid, buf, 6);250243251244 /* read the data from hidraw */252245 memset(buf, 0, sizeof(buf));···259252 memset(buf, 0, sizeof(buf));260253 buf[0] = 1;261254 buf[1] = 47;262262- uhid_send_event(_metadata, self->uhid_fd, buf, 6);255255+ uhid_send_event(_metadata, &self->hid, buf, 6);263256264257 /* read the data from hidraw */265258 memset(buf, 0, sizeof(buf));···310303 /* inject one event */311304 buf[0] = 1;312305 buf[1] = 42;313313- uhid_send_event(_metadata, self->uhid_fd, buf, 6);306306+ uhid_send_event(_metadata, &self->hid, buf, 6);314307315308 /* read the data from hidraw */316309 memset(buf, 0, sizeof(buf));···333326 /* detach the program */334327 detach_bpf(self);335328336336- self->hidraw_fd = open_hidraw(self->dev_id);329329+ self->hidraw_fd = open_hidraw(&self->hid);337330 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");338331339332 /* inject another event */340333 memset(buf, 0, sizeof(buf));341334 buf[0] = 1;342335 buf[1] = 47;343343- uhid_send_event(_metadata, self->uhid_fd, buf, 6);336336+ uhid_send_event(_metadata, &self->hid, buf, 6);344337345338 /* read the data from hidraw */346339 memset(buf, 0, sizeof(buf));···359352 memset(buf, 0, sizeof(buf));360353 buf[0] = 1;361354 buf[1] = 42;362362- uhid_send_event(_metadata, self->uhid_fd, buf, 6);355355+ uhid_send_event(_metadata, &self->hid, buf, 6);363356364357 /* read the data from hidraw */365358 memset(buf, 0, sizeof(buf));···389382 /* inject one event */390383 buf[0] = 1;391384 buf[1] = 42;392392- uhid_send_event(_metadata, self->uhid_fd, buf, 6);385385+ uhid_send_event(_metadata, &self->hid, buf, 6);393386394387 /* read the data from hidraw */395388 memset(buf, 0, sizeof(buf));···419412420413 LOAD_BPF;421414422422- args.hid = self->hid_id;415415+ args.hid = self->hid.hid_id;423416 args.data[0] = 1; /* report ID */424417 args.data[1] = 2; /* report ID */425418 args.data[2] = 42; /* report ID */···465458466459 LOAD_BPF;467460468468- args.hid = self->hid_id;461461+ args.hid = self->hid.hid_id;469462 args.data[0] = 1; /* report ID */470463 args.data[1] = 2; /* report ID */471464 args.data[2] = 42; /* report ID */···513506514507 LOAD_BPF;515508516516- args.hid = self->hid_id;509509+ args.hid = self->hid.hid_id;517510 args.data[0] = 1; /* report ID */518511519512 prog_fd = bpf_program__fd(self->skel->progs.hid_user_raw_request);···546539 /* inject one event */547540 buf[0] = 1;548541 buf[1] = 42;549549- uhid_send_event(_metadata, self->uhid_fd, buf, 6);542542+ uhid_send_event(_metadata, &self->hid, buf, 6);550543551544 /* read the data from hidraw */552545 memset(buf, 0, sizeof(buf));···572565 /* detach the program */573566 detach_bpf(self);574567575575- self->hidraw_fd = open_hidraw(self->dev_id);568568+ self->hidraw_fd = open_hidraw(&self->hid);576569 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");577570578571 err = ioctl(self->hidraw_fd, HIDIOCGFEATURE(sizeof(buf)), buf);···648641 /* inject one event */649642 buf[0] = 1;650643 buf[1] = 42;651651- uhid_send_event(_metadata, self->uhid_fd, buf, 6);644644+ uhid_send_event(_metadata, &self->hid, buf, 6);652645653646 /* read the data from hidraw */654647 memset(buf, 0, sizeof(buf));···674667 /* detach the program */675668 detach_bpf(self);676669677677- self->hidraw_fd = open_hidraw(self->dev_id);670670+ self->hidraw_fd = open_hidraw(&self->hid);678671 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");679672680673 err = write(self->hidraw_fd, buf, 3);···749742 /* inject one event */750743 buf[0] = 1;751744 buf[1] = 42;752752- uhid_send_event(_metadata, self->uhid_fd, buf, 6);745745+ uhid_send_event(_metadata, &self->hid, buf, 6);753746754747 /* read the data from hidraw */755748 memset(buf, 0, sizeof(buf));···787780 /* inject one event */788781 buf[0] = 1;789782 buf[1] = 42;790790- uhid_send_event(_metadata, self->uhid_fd, buf, 6);783783+ uhid_send_event(_metadata, &self->hid, buf, 6);791784792785 /* read the data from hidraw */793786 memset(buf, 0, sizeof(buf));···823816 buf[1] = 2;824817 buf[2] = 42;825818826826- uhid_send_event(_metadata, self->uhid_fd, buf, 6);819819+ uhid_send_event(_metadata, &self->hid, buf, 6);827820828821 /* read the data from hidraw */829822 memset(buf, 0, sizeof(buf));···874867875868 /* inject one event */876869 buf[0] = 1;877877- uhid_send_event(_metadata, self->uhid_fd, buf, 6);870870+ uhid_send_event(_metadata, &self->hid, buf, 6);878871879872 /* read the data from hidraw */880873 memset(buf, 0, sizeof(buf));···883876 ASSERT_EQ(buf[1], 1);884877 ASSERT_EQ(buf[2], 2);885878 ASSERT_EQ(buf[3], 3);879879+}880880+881881+static bool is_using_driver(struct __test_metadata *_metadata, struct uhid_device *hid,882882+ const char *driver)883883+{884884+ char driver_line[512];885885+ char uevent[1024];886886+ char temp[512];887887+ int fd, nread;888888+ bool found = false;889889+890890+ sprintf(uevent, "/sys/bus/hid/devices/%04X:%04X:%04X.%04X/uevent",891891+ hid->bus, hid->vid, hid->pid, hid->hid_id);892892+893893+ fd = open(uevent, O_RDONLY | O_NONBLOCK);894894+ if (fd < 0) {895895+ TH_LOG("couldn't open '%s': %d, %d", uevent, fd, errno);896896+ return false;897897+ }898898+899899+ sprintf(driver_line, "DRIVER=%s", driver);900900+901901+ nread = read(fd, temp, ARRAY_SIZE(temp));902902+ if (nread > 0 && (strstr(temp, driver_line)) != NULL)903903+ found = true;904904+905905+ close(fd);906906+907907+ return found;908908+}909909+910910+/*911911+ * Attach hid_driver_probe to the given uhid device,912912+ * check that the device is now using hid-generic.913913+ */914914+TEST_F(hid_bpf, test_hid_driver_probe)915915+{916916+ const struct test_program progs[] = {917917+ {918918+ .name = "hid_test_driver_probe",919919+ },920920+ };921921+922922+ ASSERT_TRUE(is_using_driver(_metadata, &self->hid, "apple"));923923+924924+ LOAD_PROGRAMS(progs);925925+926926+ ASSERT_TRUE(is_using_driver(_metadata, &self->hid, "hid-generic"));886927}887928888929/*
+75-37
tools/testing/selftests/hid/hid_common.h
···1919 __typeof__(b) _b = (b); \2020 _a < _b ? _a : _b; })21212222+struct uhid_device {2323+ int dev_id; /* uniq (random) number to identify the device */2424+ int uhid_fd;2525+ int hid_id; /* HID device id in the system */2626+ __u16 bus;2727+ __u32 vid;2828+ __u32 pid;2929+ pthread_t tid; /* thread for reading uhid events */3030+};3131+2232static unsigned char rdesc[] = {2333 0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */2434 0x09, 0x21, /* Usage (Vendor Usage 0x21) */···132122 }133123}134124135135-static int uhid_create(struct __test_metadata *_metadata, int fd, int rand_nb)125125+static int uhid_create(struct __test_metadata *_metadata, int fd, int rand_nb,126126+ __u16 bus, __u32 vid, __u32 pid, __u8 *rdesc,127127+ size_t rdesc_size)136128{137129 struct uhid_event ev;138130 char buf[25];···145133 ev.type = UHID_CREATE;146134 strcpy((char *)ev.u.create.name, buf);147135 ev.u.create.rd_data = rdesc;148148- ev.u.create.rd_size = sizeof(rdesc);149149- ev.u.create.bus = BUS_USB;150150- ev.u.create.vendor = 0x0001;151151- ev.u.create.product = 0x0a37;136136+ ev.u.create.rd_size = rdesc_size;137137+ ev.u.create.bus = bus;138138+ ev.u.create.vendor = vid;139139+ ev.u.create.product = pid;152140 ev.u.create.version = 0;153141 ev.u.create.country = 0;154142···158146 return uhid_write(_metadata, fd, &ev);159147}160148161161-static void uhid_destroy(struct __test_metadata *_metadata, int fd)149149+static void uhid_destroy(struct __test_metadata *_metadata, struct uhid_device *hid)162150{163151 struct uhid_event ev;164152165153 memset(&ev, 0, sizeof(ev));166154 ev.type = UHID_DESTROY;167155168168- uhid_write(_metadata, fd, &ev);156156+ uhid_write(_metadata, hid->uhid_fd, &ev);169157}170158171159static int uhid_event(struct __test_metadata *_metadata, int fd)···293281 return 0;294282}295283296296-static int uhid_send_event(struct __test_metadata *_metadata, int fd, __u8 *buf, size_t size)284284+static int uhid_send_event(struct __test_metadata *_metadata, struct uhid_device *hid,285285+ __u8 *buf, size_t size)297286{298287 struct uhid_event ev;299288···307294308295 memcpy(ev.u.input2.data, buf, size);309296310310- return uhid_write(_metadata, fd, &ev);297297+ return uhid_write(_metadata, hid->uhid_fd, &ev);311298}312299313313-static int setup_uhid(struct __test_metadata *_metadata, int rand_nb)300300+static bool match_sysfs_device(struct uhid_device *hid, const char *workdir, struct dirent *dir)314301{315315- int fd;316316- const char *path = "/dev/uhid";317317- int ret;318318-319319- fd = open(path, O_RDWR | O_CLOEXEC);320320- ASSERT_GE(fd, 0) TH_LOG("open uhid-cdev failed; %d", fd);321321-322322- ret = uhid_create(_metadata, fd, rand_nb);323323- ASSERT_EQ(0, ret) {324324- TH_LOG("create uhid device failed: %d", ret);325325- close(fd);326326- }327327-328328- return fd;329329-}330330-331331-static bool match_sysfs_device(int dev_id, const char *workdir, struct dirent *dir)332332-{333333- const char *target = "0003:0001:0A37.*";302302+ char target[20] = "";334303 char phys[512];335304 char uevent[1024];336305 char temp[512];337306 int fd, nread;338307 bool found = false;308308+309309+ snprintf(target, sizeof(target), "%04X:%04X:%04X.*", hid->bus, hid->vid, hid->pid);339310340311 if (fnmatch(target, dir->d_name, 0))341312 return false;···331334 if (fd < 0)332335 return false;333336334334- sprintf(phys, "PHYS=%d", dev_id);337337+ sprintf(phys, "PHYS=%d", hid->dev_id);335338336339 nread = read(fd, temp, ARRAY_SIZE(temp));337340 if (nread > 0 && (strstr(temp, phys)) != NULL)···342345 return found;343346}344347345345-static int get_hid_id(int dev_id)348348+static int get_hid_id(struct uhid_device *hid)346349{347350 const char *workdir = "/sys/devices/virtual/misc/uhid";348351 const char *str_id;···357360 d = opendir(workdir);358361 if (d) {359362 while ((dir = readdir(d)) != NULL) {360360- if (!match_sysfs_device(dev_id, workdir, dir))363363+ if (!match_sysfs_device(hid, workdir, dir))361364 continue;362365363363- str_id = dir->d_name + sizeof("0003:0001:0A37.");366366+ str_id = dir->d_name + sizeof("0000:0000:0000.");364367 found = (int)strtol(str_id, NULL, 16);365368366369 break;···374377 return found;375378}376379377377-static int get_hidraw(int dev_id)380380+static int get_hidraw(struct uhid_device *hid)378381{379382 const char *workdir = "/sys/devices/virtual/misc/uhid";380383 char sysfs[1024];···391394 continue;392395393396 while ((dir = readdir(d)) != NULL) {394394- if (!match_sysfs_device(dev_id, workdir, dir))397397+ if (!match_sysfs_device(hid, workdir, dir))395398 continue;396399397400 sprintf(sysfs, "%s/%s/hidraw", workdir, dir->d_name);···418421 return found;419422}420423421421-static int open_hidraw(int dev_id)424424+static int open_hidraw(struct uhid_device *hid)422425{423426 int hidraw_number;424427 char hidraw_path[64] = { 0 };425428426426- hidraw_number = get_hidraw(dev_id);429429+ hidraw_number = get_hidraw(hid);427430 if (hidraw_number < 0)428431 return hidraw_number;429432430433 /* open hidraw node to check the other side of the pipe */431434 sprintf(hidraw_path, "/dev/hidraw%d", hidraw_number);432435 return open(hidraw_path, O_RDWR | O_NONBLOCK);436436+}437437+438438+static int setup_uhid(struct __test_metadata *_metadata, struct uhid_device *hid,439439+ __u16 bus, __u32 vid, __u32 pid, const __u8 *rdesc, size_t rdesc_size)440440+{441441+ const char *path = "/dev/uhid";442442+ time_t t;443443+ int ret;444444+445445+ /* initialize random number generator */446446+ srand((unsigned int)time(&t));447447+448448+ hid->dev_id = rand() % 1024;449449+ hid->bus = bus;450450+ hid->vid = vid;451451+ hid->pid = pid;452452+453453+ hid->uhid_fd = open(path, O_RDWR | O_CLOEXEC);454454+ ASSERT_GE(hid->uhid_fd, 0) TH_LOG("open uhid-cdev failed; %d", hid->uhid_fd);455455+456456+ ret = uhid_create(_metadata, hid->uhid_fd, hid->dev_id, bus, vid, pid,457457+ (__u8 *)rdesc, rdesc_size);458458+ ASSERT_EQ(0, ret) {459459+ TH_LOG("create uhid device failed: %d", ret);460460+ close(hid->uhid_fd);461461+ return ret;462462+ }463463+464464+ /* locate the uevent file of the created device */465465+ hid->hid_id = get_hid_id(hid);466466+ ASSERT_GT(hid->hid_id, 0)467467+ TH_LOG("Could not locate uhid device id: %d", hid->hid_id);468468+469469+ ret = uhid_start_listener(_metadata, &hid->tid, hid->uhid_fd);470470+ ASSERT_EQ(0, ret) {471471+ TH_LOG("could not start udev listener: %d", ret);472472+ close(hid->uhid_fd);473473+ return ret;474474+ }475475+476476+ return 0;433477}
+10-26
tools/testing/selftests/hid/hidraw.c
···99#endif /* HIDIOCREVOKE */10101111FIXTURE(hidraw) {1212- int dev_id;1313- int uhid_fd;1212+ struct uhid_device hid;1413 int hidraw_fd;1515- int hid_id;1616- pthread_t tid;1714};1815static void close_hidraw(FIXTURE_DATA(hidraw) * self)1916{···2225FIXTURE_TEARDOWN(hidraw) {2326 void *uhid_err;24272525- uhid_destroy(_metadata, self->uhid_fd);2828+ uhid_destroy(_metadata, &self->hid);26292730 close_hidraw(self);2828- pthread_join(self->tid, &uhid_err);3131+ pthread_join(self->hid.tid, &uhid_err);2932}3033#define TEARDOWN_LOG(fmt, ...) do { \3134 TH_LOG(fmt, ##__VA_ARGS__); \···34373538FIXTURE_SETUP(hidraw)3639{3737- time_t t;3840 int err;39414040- /* initialize random number generator */4141- srand((unsigned int)time(&t));4242+ err = setup_uhid(_metadata, &self->hid, BUS_USB, 0x0001, 0x0a37, rdesc, sizeof(rdesc));4343+ ASSERT_OK(err);42444343- self->dev_id = rand() % 1024;4444-4545- self->uhid_fd = setup_uhid(_metadata, self->dev_id);4646-4747- /* locate the uev, self, variant);ent file of the created device */4848- self->hid_id = get_hid_id(self->dev_id);4949- ASSERT_GT(self->hid_id, 0)5050- TEARDOWN_LOG("Could not locate uhid device id: %d", self->hid_id);5151-5252- err = uhid_start_listener(_metadata, &self->tid, self->uhid_fd);5353- ASSERT_EQ(0, err) TEARDOWN_LOG("could not start udev listener: %d", err);5454-5555- self->hidraw_fd = open_hidraw(self->dev_id);4545+ self->hidraw_fd = open_hidraw(&self->hid);5646 ASSERT_GE(self->hidraw_fd, 0) TH_LOG("open_hidraw");5747}5848···6379 /* inject one event */6480 buf[0] = 1;6581 buf[1] = 42;6666- uhid_send_event(_metadata, self->uhid_fd, buf, 6);8282+ uhid_send_event(_metadata, &self->hid, buf, 6);67836884 /* read the data from hidraw */6985 memset(buf, 0, sizeof(buf));···85101 /* inject one event */86102 buf[0] = 1;87103 buf[1] = 42;8888- uhid_send_event(_metadata, self->uhid_fd, buf, 6);104104+ uhid_send_event(_metadata, &self->hid, buf, 6);8910590106 /* read the data from hidraw */91107 memset(buf, 0, sizeof(buf));···101117 /* inject one other event */102118 buf[0] = 1;103119 buf[1] = 43;104104- uhid_send_event(_metadata, self->uhid_fd, buf, 6);120120+ uhid_send_event(_metadata, &self->hid, buf, 6);105121106122 /* read the data from hidraw */107123 memset(buf, 0, sizeof(buf));···145161 /* inject one event */146162 buf[0] = 1;147163 buf[1] = 42;148148- uhid_send_event(_metadata, self->uhid_fd, buf, 6);164164+ uhid_send_event(_metadata, &self->hid, buf, 6);149165150166 while (true) {151167 ready = poll(pfds, 1, 5000);