--- hald/freebsd/hf-usb2.c.orig 2010-01-21 11:13:33.000000000 +1300 +++ hald/freebsd/hf-usb2.c 2010-01-21 11:22:12.000000000 +1300 @@ -0,0 +1,296 @@ +/*************************************************************************** + * CVSID: $Id$ + * + * hf-usb.c : USB support + * + * Copyright (C) 2009 Joe Marcus Clarke + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + **************************************************************************/ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "../logger.h" +#include "../osspec.h" + +#include "hf-usb.h" +#include "hf-usb2.h" +#include "hf-devtree.h" +#include "hf-util.h" + +static struct libusb20_backend *hf_usb2_be = NULL; + +static void +hf_usb2_probe_interfaces(HalDevice *parent) +{ + int num_interfaces; + int i; + + g_return_if_fail(HAL_IS_DEVICE(parent)); + + if (hal_device_property_get_bool(parent, "info.ignore")) + return; + + num_interfaces = hal_device_property_get_int(parent, + "usb_device.num_interfaces"); + + for (i = 0; i < num_interfaces; i++) + { + HalDevice *device; + + device = hf_device_new(parent); + + hal_device_property_set_string(device, "info.subsystem", "usb"); + hal_device_property_set_int(device, "usb.interface.number", i); + hal_device_copy_property(parent, "info.product", device, "info.product"); + hal_device_copy_property(parent, "info.vendor", device, "info.vendor"); + hal_device_merge_with_rewrite(device, parent, "usb.", "usb_device."); + + if (hf_device_preprobe(device)) + { + const char *driver, *devname; + + hf_runner_run_sync(device, 0, "hald-probe-usb2-interface", NULL); + + devname = hal_device_property_get_string(device, + "usb.freebsd.devname"); + if (devname) + hf_devtree_device_set_name(device, devname); + + driver = hal_device_property_get_string(device, "freebsd.driver"); + if (driver) + { + if (! strcmp(driver, "ukbd")) + hf_device_set_input(device, "keyboard", NULL); + else if (! strcmp(driver, "ums") || ! strcmp(driver, "atp")) + { + hf_device_set_input(device, "mouse", devname); + hf_runner_run_sync(device, 0, "hald-probe-mouse", NULL); + } + else if (! strcmp(driver, "uhid")) + { + hal_device_property_set_string(device, "info.category", + "hiddev"); + hal_device_add_capability(device, "hiddev"); + hf_device_property_set_string_printf(device, "hiddev.device", + "/dev/%s", devname); + hal_device_copy_property(device, "info.product", device, + "hiddev.product"); + hf_runner_run_sync(device, 0, "hald-probe-hiddev", NULL); + } + else if (! strcmp(driver, "ldev")) + { + /* Linux driver (webcam) */ + + /* + * XXX This is a hack. Currently, all ldev devices are + * webcams. That may not always be the case. Hopefully, + * when other Linux driver support is added, there will be + * a sysctl or some other way to determine device class. + */ + hf_usb_add_webcam_properties(device); + } + else if (! strcmp(driver, "pwc")) + { + /* Phillips Web Cam */ + hf_usb_add_webcam_properties(device); + } + } + + hf_usb_device_compute_udi(device); + hf_device_add(device); + } + } +} + +static void +hf_usb2_probe_device (HalDevice *parent, int bus, int addr) +{ + HalDevice *device; + + g_return_if_fail(HAL_IS_DEVICE(parent)); + + device = hf_device_new(parent); + + hal_device_property_set_string(device, "info.subsystem", "usb_device"); + hal_device_property_set_int(device, "usb_device.bus_number", bus); + hal_device_property_set_int(device, "usb_device.level_number", addr - 1); + hal_device_property_set_int(device, "usb_device.port_number", addr); + + if (hf_device_preprobe(device)) + { + hf_runner_run_sync(device, 0, "hald-probe-usb2-device", NULL); + hf_usb_device_compute_udi(device); + + hf_device_add(device); + } + else + return; + + hf_usb2_probe_interfaces(device); +} + +static void +hf_usb2_privileged_init (void) +{ + hf_usb2_be = libusb20_be_alloc_default(); + if (hf_usb2_be == NULL) + HAL_INFO(("unable to open USB backend: %s", g_strerror(errno))); +} + +static void +hf_usb2_probe (void) +{ + struct libusb20_device *pdev = NULL; + + if (hf_usb2_be == NULL) + return; + + while ((pdev = libusb20_be_device_foreach(hf_usb2_be, pdev))) + { + HalDevice *parent; + int bus, addr; + + bus = libusb20_dev_get_bus_number(pdev); + addr = libusb20_dev_get_address(pdev); + + if (addr == 1) + parent = hf_devtree_find_from_info(hald_get_gdl(), "usbus", bus); + else + parent = hf_device_store_match(hald_get_gdl(), "usb_device.bus_number", + HAL_PROPERTY_TYPE_INT32, bus, "usb_device.port_number", + HAL_PROPERTY_TYPE_INT32, addr - 1, "info.bus", + HAL_PROPERTY_TYPE_STRING, "usb_device", NULL); + if (! parent || hal_device_property_get_bool(parent, "info.ignore")) + continue; + + hf_usb2_probe_device(parent, bus, addr); + } + + libusb20_be_free(hf_usb2_be); + hf_usb2_be = NULL; +} + +static gboolean +hf_usb2_devd_add (const char *name, + GHashTable *params, + GHashTable *at, + const char *parent) +{ + HalDevice *parent_device; + int bus, addr, pbus, paddr; + + if (! parent) + return FALSE; + + if (strncmp(name, "ugen", strlen("ugen")) && + ! strncmp(parent, "uhub", strlen("uhub"))) + return TRUE; + else if (strncmp(name, "ugen", strlen("ugen"))) + return FALSE; + else if (strncmp(parent, "ugen", strlen("ugen"))) + return TRUE; + + if (sscanf(name, "ugen%i.%i", &bus, &addr) != 2) + return FALSE; + + if (sscanf(parent, "ugen%i.%i", &pbus, &paddr) != 2) + return FALSE; + + HAL_INFO(("received devd add event for device '%s' with parent '%s'", + name, parent)); + + parent_device = hf_device_store_match(hald_get_gdl(), + "usb_device.bus_number", HAL_PROPERTY_TYPE_INT32, pbus, + "usb_device.port_number", HAL_PROPERTY_TYPE_INT32, paddr, "info.bus", + HAL_PROPERTY_TYPE_STRING, "usb_device", NULL); + + if (parent_device && ! hal_device_property_get_bool(parent_device, + "info.ignore")) + { + hf_usb2_probe_device(parent_device, bus, addr); + return TRUE; + } + + return FALSE; +} + +static gboolean +hf_usb2_devd_remove (const char *name, + GHashTable *params, + GHashTable *at, + const char *parent) +{ + HalDevice *device; + int bus, addr; + + if (strncmp(name, "ugen", strlen("ugen"))) + return FALSE; + + if (sscanf(name, "ugen%i.%i", &bus, &addr) != 2) + return FALSE; + + HAL_INFO(("received devd remove event, device %s", name)); + + device = hf_device_store_match(hald_get_gdl(), "usb_device.bus_number", + HAL_PROPERTY_TYPE_INT32, bus, "usb_device.port_number", + HAL_PROPERTY_TYPE_INT32, addr, "info.bus", + HAL_PROPERTY_TYPE_STRING, "usb_device", NULL); + + if (device) + { + hf_device_remove_tree(device); + return TRUE; + } + + return FALSE; +} + +static gboolean +hf_usb2_devd_notify (const char *system, + const char *subsystem, + const char *type, + const char *data) +{ + if (! data || strcmp(system, "DEVFS") || strcmp(subsystem, "CDEV") || + (strcmp(type, "CREATE") && strcmp(type, "DESTROY"))) + return FALSE; + + if (! strncmp(data, "cdev=ugen", strlen("cdev=ugen")) || + ! strncmp(data, "cdev=usb", strlen("cdev=usb"))) + return TRUE; + + return FALSE; +} + +HFHandler hf_usb2_handler = { + .privileged_init = hf_usb2_privileged_init, + .probe = hf_usb2_probe +}; + +HFDevdHandler hf_usb2_devd_handler = { + .add = hf_usb2_devd_add, + .remove = hf_usb2_devd_remove, + .notify = hf_usb2_devd_notify +};