예제 #1
0
/* ARGSUSED */
static void
btbc_attach(device_t parent, device_t self, void *aux)
{
	struct btbc_softc *sc = device_private(self);
	struct pcmcia_attach_args *pa = aux;
	struct pcmcia_config_entry *cfe;
	int error;

	sc->sc_dev = self;
	sc->sc_pf = pa->pf;

	MBUFQ_INIT(&sc->sc_cmdq);
	MBUFQ_INIT(&sc->sc_aclq);
	MBUFQ_INIT(&sc->sc_scoq);

	if ((error = pcmcia_function_configure(pa->pf,
	    btbc_pcmcia_validate_config)) != 0) {
		aprint_error_dev(self, "configure failed, error=%d\n", error);
		return;
	}

	cfe = pa->pf->cfe;
	sc->sc_pcioh = cfe->iospace[0].handle;

	/* Attach Bluetooth unit */
	sc->sc_unit = hci_attach(&btbc_hci, self, 0);
	if (sc->sc_unit == NULL)
		aprint_error_dev(self, "HCI attach failed\n");

	if (!pmf_device_register(self, btbc_suspend, btbc_resume))
		aprint_error_dev(self, "couldn't establish power handler\n");

	callout_init(&sc->sc_ledch, 0);
	callout_setfunc(&sc->sc_ledch, btbc_activity_led_timeout, sc);

	return;
}
예제 #2
0
static void
bthidev_attach(device_t parent, device_t self, void *aux)
{
	struct bthidev_softc *sc = device_private(self);
	prop_dictionary_t dict = aux;
	prop_object_t obj;
	device_t dev;
	struct bthidev_attach_args bha;
	struct bthidev *hidev;
	struct hid_data *d;
	struct hid_item h;
	const void *desc;
	int locs[BTHIDBUSCF_NLOCS];
	int maxid, rep, dlen;
	int vendor, product;
	int err;

	/*
	 * Init softc
	 */
	sc->sc_dev = self;
	LIST_INIT(&sc->sc_list);
	MBUFQ_INIT(&sc->sc_inq);
	callout_init(&sc->sc_reconnect, 0);
	callout_setfunc(&sc->sc_reconnect, bthidev_timeout, sc);
	sc->sc_state = BTHID_CLOSED;
	sc->sc_flags = BTHID_CONNECTING;
	sc->sc_ctlpsm = L2CAP_PSM_HID_CNTL;
	sc->sc_intpsm = L2CAP_PSM_HID_INTR;

	sockopt_init(&sc->sc_mode, BTPROTO_L2CAP, SO_L2CAP_LM, 0);
	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE);
	cv_init(&sc->sc_cv, device_xname(self));

	/*
	 * extract config from proplist
	 */
	obj = prop_dictionary_get(dict, BTDEVladdr);
	bdaddr_copy(&sc->sc_laddr, prop_data_data_nocopy(obj));

	obj = prop_dictionary_get(dict, BTDEVraddr);
	bdaddr_copy(&sc->sc_raddr, prop_data_data_nocopy(obj));

	obj = prop_dictionary_get(dict, BTDEVvendor);
	vendor = (int)prop_number_integer_value(obj);

	obj = prop_dictionary_get(dict, BTDEVproduct);
	product = (int)prop_number_integer_value(obj);

	obj = prop_dictionary_get(dict, BTDEVmode);
	if (prop_object_type(obj) == PROP_TYPE_STRING) {
		if (prop_string_equals_cstring(obj, BTDEVauth))
			sockopt_setint(&sc->sc_mode, L2CAP_LM_AUTH);
		else if (prop_string_equals_cstring(obj, BTDEVencrypt))
			sockopt_setint(&sc->sc_mode, L2CAP_LM_ENCRYPT);
		else if (prop_string_equals_cstring(obj, BTDEVsecure))
			sockopt_setint(&sc->sc_mode, L2CAP_LM_SECURE);
		else  {
			aprint_error(" unknown %s\n", BTDEVmode);
			return;
		}

		aprint_verbose(" %s %s", BTDEVmode,
					 prop_string_cstring_nocopy(obj));
	} else
		sockopt_setint(&sc->sc_mode, 0);

	obj = prop_dictionary_get(dict, BTHIDEVcontrolpsm);
	if (prop_object_type(obj) == PROP_TYPE_NUMBER) {
		sc->sc_ctlpsm = prop_number_integer_value(obj);
		if (L2CAP_PSM_INVALID(sc->sc_ctlpsm)) {
			aprint_error(" invalid %s\n", BTHIDEVcontrolpsm);
			return;
		}
	}

	obj = prop_dictionary_get(dict, BTHIDEVinterruptpsm);
	if (prop_object_type(obj) == PROP_TYPE_NUMBER) {
		sc->sc_intpsm = prop_number_integer_value(obj);
		if (L2CAP_PSM_INVALID(sc->sc_intpsm)) {
			aprint_error(" invalid %s\n", BTHIDEVinterruptpsm);
			return;
		}
	}

	obj = prop_dictionary_get(dict, BTHIDEVdescriptor);
	if (prop_object_type(obj) == PROP_TYPE_DATA) {
		dlen = prop_data_size(obj);
		desc = prop_data_data_nocopy(obj);
	} else {
		aprint_error(" no %s\n", BTHIDEVdescriptor);
		return;
	}

	obj = prop_dictionary_get(dict, BTHIDEVreconnect);
	if (prop_object_type(obj) == PROP_TYPE_BOOL
	    && !prop_bool_true(obj))
		sc->sc_flags |= BTHID_RECONNECT;

	/*
	 * Parse the descriptor and attach child devices, one per report.
	 */
	maxid = -1;
	h.report_ID = 0;
	d = hid_start_parse(desc, dlen, hid_none);
	while (hid_get_item(d, &h)) {
		if (h.report_ID > maxid)
			maxid = h.report_ID;
	}
	hid_end_parse(d);

	if (maxid < 0) {
		aprint_error(" no reports found\n");
		return;
	}

	aprint_normal("\n");

	if (kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL, bthidev_process,
	    sc, &sc->sc_lwp, "%s", device_xname(self)) != 0) {
		aprint_error_dev(self, "failed to create input thread\n");
		return;
	}

	for (rep = 0 ; rep <= maxid ; rep++) {
		if (hid_report_size(desc, dlen, hid_feature, rep) == 0
		    && hid_report_size(desc, dlen, hid_input, rep) == 0
		    && hid_report_size(desc, dlen, hid_output, rep) == 0)
			continue;

		bha.ba_vendor = vendor;
		bha.ba_product = product;
		bha.ba_desc = desc;
		bha.ba_dlen = dlen;
		bha.ba_input = bthidev_null;
		bha.ba_feature = bthidev_null;
		bha.ba_output = bthidev_output;
		bha.ba_id = rep;

		locs[BTHIDBUSCF_REPORTID] = rep;

		dev = config_found_sm_loc(self, "bthidbus",
					locs, &bha, bthidev_print, config_stdsubmatch);
		if (dev != NULL) {
			hidev = device_private(dev);
			hidev->sc_dev = dev;
			hidev->sc_parent = self;
			hidev->sc_id = rep;
			hidev->sc_input = bha.ba_input;
			hidev->sc_feature = bha.ba_feature;
			LIST_INSERT_HEAD(&sc->sc_list, hidev, sc_next);
		}
	}

	pmf_device_register(self, NULL, NULL);

	/*
	 * start bluetooth connections
	 */
	mutex_enter(bt_lock);
	if ((sc->sc_flags & BTHID_RECONNECT) == 0
	    && (err = bthidev_listen(sc)) != 0)
		aprint_error_dev(self, "failed to listen (%d)\n", err);

	if (sc->sc_flags & BTHID_CONNECTING)
		bthidev_connect(sc);
	mutex_exit(bt_lock);
}