Writing HID driver
Alexandr Matveev
timon at timon.net.nz
Wed Oct 19 12:06:39 UTC 2011
Hi,
I'm writing the driver for the USB keyboard, which has two interfaces:
first is generic keyboard and second is HID device. If I load driver and
then attach the keyboard - everything is OK. But if I attach keyboard
and then kldload driver, it won't attach to the device because the default
uhid driver already attached to it first. To prevent this, driver
searches for
uhid devices after being loaded and compares a pnpinfo string to search
for suitable devices and detach them.
Everything works fine, but I have two questions:
1) Is there any simpler way to do the same thing?
2) Is there a way to get device vendor & product without using device
bus-specific functions?
Code which I use now:
DRIVER_MODULE(lkbd, uhub, lkbd_driver, lkbd_devclass, lkbd_modevent, 0);
static int
lkbd_modevent(module_t mod, int what, void *arg)
{
switch (what) {
case MOD_LOAD:
lkbd_detach_uhid();
break;
case MOD_UNLOAD:
break;
default:
return (EOPNOTSUPP);
}
return (0);
}
static void
lkbd_detach_uhid(void)
{
struct u_businfo ubus;
size_t ub_size = sizeof(ubus);
struct u_device udev;
size_t ud_size = sizeof(udev);
int name2oid[2];
int oid[CTL_MAXNAME];
size_t oid_size, plen;
char *name;
int dev_ptr;
int error;
if (kernel_sysctlbyname(curthread, "hw.bus.info", &ubus,
&ub_size, NULL, 0, NULL, 0) != 0) {
DPRINTFN(3, "Can't get hw.bus.info sysctl node\n");
return;
}
/* Here is some magic from
kern/kern_sysctl.c:kernel_sysctlbyname */
name2oid[0] = 0;
name2oid[1] = 3;
oid_size = sizeof(oid);
name = "hw.bus.devices";
error = kernel_sysctl(curthread, name2oid, 2, oid, &oid_size,
name, strlen(name), &plen, 0);
if (error) {
DPRINTFN(3, "Can't find hw.bus.devices sysctl node\n");
return;
}
plen /= sizeof(int);
/* End of magic */
oid[plen++] = ubus.ub_generation;
dev_ptr = plen++;
oid[dev_ptr] = 0;
while (kernel_sysctl(curthread, oid, plen, &udev, &ud_size,
NULL, 0, NULL, 0) == 0) {
if (
strncmp(udev.dv_drivername, "uhid", 4) == 0
&& strstr(udev.dv_pnpinfo, "vendor=0x046d product=0xc228") != NULL
&& device_is_attached((device_t)udev.dv_handle)
) {
device_detach((device_t)udev.dv_handle);
}
oid[dev_ptr]++;
}
return;
}
--
Alexandr Matveev
More information about the freebsd-drivers
mailing list