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; /* * Init softc */ sc->sc_dev = self; LIST_INIT(&sc->sc_list); 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); /* * 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, 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)); } 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"); 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_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); } } /* * start bluetooth connections */ mutex_enter(bt_lock); if ((sc->sc_flags & BTHID_RECONNECT) == 0) bthidev_listen(sc); if (sc->sc_flags & BTHID_CONNECTING) bthidev_connect(sc); mutex_exit(bt_lock); }
void bthidev_attach(struct device *parent, struct device *self, void *aux) { struct bthidev_softc *sc = (struct bthidev_softc *)self; struct btdev_attach_args *bda = (struct btdev_attach_args *)aux; struct bthidev_attach_args bha; struct bthidev *hidev; struct hid_data *d; struct hid_item h; int maxid, rep; /* * Init softc */ LIST_INIT(&sc->sc_list); timeout_set(&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; sc->sc_mode = 0; /* * copy in our configuration info */ bdaddr_copy(&sc->sc_laddr, &bda->bd_laddr); bdaddr_copy(&sc->sc_raddr, &bda->bd_raddr); if (bda->bd_mode != BTDEV_MODE_NONE) { if (bda->bd_mode == BTDEV_MODE_AUTH) { sc->sc_mode = L2CAP_LM_AUTH; printf(" auth"); } else if (bda->bd_mode == BTDEV_MODE_ENCRYPT) { sc->sc_mode = L2CAP_LM_ENCRYPT; printf(" encrypt"); } else if (bda->bd_mode == BTDEV_MODE_SECURE) { sc->sc_mode = L2CAP_LM_SECURE; printf(" secure"); } else { printf(" unknown link-mode: %d\n", bda->bd_mode); return; } } if (!L2CAP_PSM_INVALID(bda->bd_hid.hid_ctl)) sc->sc_ctlpsm = bda->bd_hid.hid_ctl; if (!L2CAP_PSM_INVALID(bda->bd_hid.hid_int)) sc->sc_intpsm = bda->bd_hid.hid_int; if (bda->bd_hid.hid_flags & BTHID_INITIATE) sc->sc_flags |= BTHID_RECONNECT; if (bda->bd_hid.hid_desc == NULL || bda->bd_hid.hid_dlen == 0 || bda->bd_hid.hid_dlen > MAX_DESCRIPTOR_LEN) { printf(": no descriptor\n"); return; } sc->sc_dlen = bda->bd_hid.hid_dlen; sc->sc_desc = malloc(bda->bd_hid.hid_dlen, M_BTHIDEV, M_WAITOK | M_CANFAIL); if (sc->sc_desc == NULL) { printf(": no memory\n"); return; } if (copyin(bda->bd_hid.hid_desc, sc->sc_desc, bda->bd_hid.hid_dlen)) { free(sc->sc_desc, M_BTHIDEV); printf(": no descriptor"); return; } /* * Parse the descriptor and attach child devices, one per report. */ maxid = -1; h.report_ID = 0; d = hid_start_parse(sc->sc_desc, sc->sc_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) { printf(": no reports found\n"); return; } printf("\n"); for (rep = 0 ; rep <= maxid ; rep++) { if (hid_report_size(sc->sc_desc, sc->sc_dlen, hid_feature, rep) == 0 && hid_report_size(sc->sc_desc, sc->sc_dlen, hid_input, rep) == 0 && hid_report_size(sc->sc_desc, sc->sc_dlen, hid_output, rep) == 0) continue; bha.ba_desc = sc->sc_desc; bha.ba_dlen = sc->sc_dlen; bha.ba_input = bthidev_null; bha.ba_feature = bthidev_null; bha.ba_output = bthidev_output; bha.ba_id = rep; hidev = (struct bthidev *)config_found_sm(self, &bha, bthidev_print, bthidevsubmatch); if (hidev != NULL) { hidev->sc_parent = &sc->sc_btdev; 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); } } /* * start bluetooth connections */ mutex_enter(&bt_lock); if ((sc->sc_flags & BTHID_RECONNECT) == 0) bthidev_listen(sc); if (sc->sc_flags & BTHID_CONNECTING) bthidev_connect(sc); mutex_exit(&bt_lock); }