/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Cyril Plisko. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% CP" /* * Bluetooth HCI event handling */ #include #include #include #include #include "hci.h" #include "hci_impl.h" /* * HCI Inquiry Complete Event handler */ static void hci_event_inquiry_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Inquiry Complete Event\n"); #endif } /* * HCI Inquiry Result Event handler */ static void hci_event_inquiry_result(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Inquiry Result Event\n"); #endif } /* * HCI Connection Complete Event handler */ static void hci_event_connection_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Connection Complete Event\n"); #endif } /* * HCI Connection Request Event handler */ static void hci_event_connection_request(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Connection Request Event\n"); #endif } /* * HCI Disconnect Complete handler */ static void hci_event_disconnect_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Disconnect Complete Event\n"); #endif } /* * HCI Authentication Complete handler */ static void hci_event_auth_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Authentication Complete Event\n"); #endif } /* * HCI Remote Name Request Complete handler */ static void hci_event_remote_name_req_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Remote Name Request Complete Event\n"); #endif } /* * HCI Encryption Change handler */ static void hci_event_encryption_change(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Encryption Change Event\n"); #endif } /* * HCI Change Connection Link Key Complete handler */ static void hci_event_change_connection_link_key_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Change Connection Link Key Complete Event\n"); #endif } /* * HCI Master Link Key Complete handler */ static void hci_event_master_link_key_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Master Link Key Complete Event\n"); #endif } /* * HCI Read Remote Features Complete handler */ static void hci_event_read_remote_features_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Read Remote Features Complete Event\n"); #endif } /* * HCI Read Remote Version Info Complete handler */ static void hci_event_read_remote_version_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Read Remote Version Info Complete Event\n"); #endif } /* * HCI QoS Setup Complete handler */ static void hci_event_qos_setup_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI QoS Setup Complete Event\n"); #endif } /* * HCI Reset command completion handler */ static void hci_reset_complete(hci_state_t *sp, mblk_t *mp) { hci_status_rp *rp; rp = (hci_status_rp *)mp->b_rptr; #ifdef DEBUG cmn_err(CE_CONT, "Command Complete Status 0x%02x\n", rp->status); #endif mutex_enter(&sp->lock); sp->hci_num_acl_pkts = 0; sp->hci_num_sco_pkts = 0; mutex_exit(&sp->lock); } /* * HCI Read Local Name completion handler */ static void hci_read_local_name_complete(hci_state_t *sp, mblk_t *mp) { hci_read_local_name_rp *rp; rp = (hci_read_local_name_rp *)mp->b_rptr; if (rp->status == 0) { mutex_enter(&sp->lock); bcopy(rp->name, sp->name, HCI_UNIT_NAME_SIZE); mutex_exit(&sp->lock); } #ifdef DEBUG cmn_err(CE_CONT, "My name is %s\n", sp->name); #endif } static void hci_read_local_ver_complete(hci_state_t *sp, mblk_t *mp) { hci_read_local_ver_rp *rp; rp = (hci_read_local_ver_rp *)mp->b_rptr; if (rp->status == 0) { #ifdef DEBUG cmn_err(CE_CONT, "HCI version %d(0x%02x), revision %d(0x%04x)," " LMP version %d(0x%02x), mfg %d(0x%04x)," " LMP subversion %d(0x%04x)\n", rp->hci_version, rp->hci_version, rp->hci_revision, rp->hci_revision, rp->lmp_version, rp->lmp_version, rp->manufacturer, rp->manufacturer, rp->lmp_subversion, rp->lmp_subversion); #endif } } static void hci_read_buffer_size_complete(hci_state_t *sp, mblk_t *mp) { hci_read_buffer_size_rp *rp; rp = (hci_read_buffer_size_rp *)mp->b_rptr; if (rp->status == 0) { mutex_enter(&sp->lock); sp->hci_max_acl_size = rp->max_acl_size; sp->hci_num_acl_pkts = rp->num_acl_pkts; sp->hci_max_sco_size = rp->max_sco_size; sp->hci_num_sco_pkts = rp->num_sco_pkts; cv_broadcast(&sp->cv); mutex_exit(&sp->lock); } } static void hci_read_bdaddr_complete(hci_state_t *sp, mblk_t *mp) { hci_read_bdaddr_rp *rp; rp = (hci_read_bdaddr_rp *)mp->b_rptr; if (rp->status == 0) { mutex_enter(&sp->lock); bcopy(rp->bdaddr.b, sp->bdaddr.b, BLUETOOTH_BDADDR_SIZE); mutex_exit(&sp->lock); } #ifdef DEBUG cmn_err(CE_CONT, "My bdaddr %02x:%02x:%02x:%02x:%02x:%02x\n", sp->bdaddr.b[5], sp->bdaddr.b[4], sp->bdaddr.b[3], sp->bdaddr.b[2], sp->bdaddr.b[1], sp->bdaddr.b[0]); #endif } static void hci_event_command_complete(hci_state_t *sp, mblk_t *mp) { hci_event_hdr_t *eh; hci_command_compl_ep *ep; eh = (hci_event_hdr_t *)mp->b_rptr; mp->b_rptr += sizeof (hci_event_hdr_t); ep = (hci_command_compl_ep *)mp->b_rptr; mp->b_rptr += sizeof (hci_command_compl_ep); #ifdef DEBUG cmn_err(CE_CONT, "Command Complete Event: num cmd pkts" " %d, opcode 0x%04x\n", ep->num_cmd_pkts, LE_16(ep->opcode)); #endif mutex_enter(&sp->lock); sp->hci_num_cmd_pkts = ep->num_cmd_pkts; cv_broadcast(&sp->cv); mutex_exit(&sp->lock); switch (LE_16(ep->opcode)) { case HCI_CMD_RESET: hci_reset_complete(sp, mp); break; case HCI_CMD_READ_LOCAL_NAME: hci_read_local_name_complete(sp, mp); break; case HCI_CMD_READ_LOCAL_VER: hci_read_local_ver_complete(sp, mp); break; case HCI_CMD_READ_LOCAL_FEATURES: break; case HCI_CMD_READ_BUFFER_SIZE: hci_read_buffer_size_complete(sp, mp); break; case HCI_CMD_READ_BDADDR: hci_read_bdaddr_complete(sp, mp); break; default: cmn_err(CE_WARN, "Unexpected command (0x%04x) completion", LE_16(ep->opcode)); break; } } static void hci_event_command_status(hci_state_t *sp, mblk_t *mp) { hci_event_hdr_t *eh; hci_command_status_ep *ep; eh = (hci_event_hdr_t *)mp->b_rptr; mp->b_rptr += sizeof (hci_event_hdr_t); ep = (hci_command_status_ep *)mp->b_rptr; mp->b_rptr += sizeof (hci_command_status_ep); #ifdef DEBUG cmn_err(CE_CONT, "Command Status Event: status 0x%02x, num cmd pkts" " %d, opcode 0x%04x\n", ep->status, ep->num_cmd_pkts, LE_16(ep->opcode)); #endif mutex_enter(&sp->lock); sp->hci_num_cmd_pkts = ep->num_cmd_pkts; cv_broadcast(&sp->cv); mutex_exit(&sp->lock); } /* * HCI Hardware Error handler */ static void hci_event_hardware_error(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Hardware Error Event\n"); #endif } /* * HCI Flush Occur handler */ static void hci_event_flush_occur(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Flush Occur Event\n"); #endif } /* * HCI Role Change handler */ static void hci_event_role_change(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Role Change Event\n"); #endif } /* * HCI Number of Completed Packets handler */ static void hci_event_num_completed_packets(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Number of Completed Packets Event\n"); #endif } /* * HCI Mode Change handler */ static void hci_event_mode_change(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Mode Change Event\n"); #endif } /* * HCI Return Link Keys handler */ static void hci_event_return_link_keys(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Return Link Keys Event\n"); #endif } /* * HCI PIN Code Request handler */ static void hci_event_pin_code_request(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI PIN Code Request Event\n"); #endif } /* * HCI Link Key Request handler */ static void hci_event_link_key_request(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Link Key Request Event\n"); #endif } /* * HCI Link Key Notification handler */ static void hci_event_link_key_notification(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Link Key Notification Event\n"); #endif } /* * HCI Loopback Command handler */ static void hci_event_loopback_command(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Loopback Command Event\n"); #endif } /* * HCI Data Buffer Overflow handler */ static void hci_event_data_buf_overflow(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Data Buffer Overflow Event\n"); #endif } /* * HCI Max Slot Change handler */ static void hci_event_max_slot_change(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Max Slot Change Event\n"); #endif } /* * HCI Read Clock Offset Complete handler */ static void hci_event_read_clock_offset_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Read Clock Offset Complete Event\n"); #endif } /* * HCI Connection Packet Type Changed handler */ static void hci_event_connection_pkt_type_changed(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Connection Packet Type Changed Event\n"); #endif } /* * HCI QoS Violation handler */ static void hci_event_qos_violation(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Violation Event\n"); #endif } /* * HCI Page Scan Mode Change handler */ static void hci_event_page_scan_mode_change(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Page Scan Mode Change Event\n"); #endif } /* * HCI Page Scan Repetition Mode Change handler */ static void hci_event_page_scan_rep_mode_change(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Page Scan Repetition Mode Change Event\n"); #endif } /* * HCI Flow Specification Complete handler */ static void hci_event_flow_spec_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Flow Specification Complete Event\n"); #endif } /* * HCI RSSI Result handler */ static void hci_event_rssi_result(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI RSSI Result Event\n"); #endif } /* * HCI Read Remote Extended Features omplete handler */ static void hci_event_read_remote_ext_features_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI Read Remote Extended Features Complete Event\n"); #endif } /* * HCI SCO Connection Complete handler */ static void hci_event_sco_connection_complete(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI SCO Connection Complete Event\n"); #endif } /* * HCI SCO Connection Changed handler */ static void hci_event_sco_connection_changed(hci_state_t *sp, mblk_t *mp) { #ifdef DEBUG cmn_err(CE_CONT, "HCI SCO Connection Changed Event\n"); #endif } void hci_process_event(hci_state_t *sp, mblk_t *mp) { hci_event_hdr_t *eh; eh = (hci_event_hdr_t *)mp->b_rptr; ASSERT(eh->type == HCI_EVENT_PKT); #ifdef DEBUG cmn_err(CE_CONT, "HCI Event of %d bytes has arrived\n", eh->length); #endif switch (eh->event) { case HCI_EVENT_INQUIRY_COMPL: hci_event_inquiry_complete(sp, mp); break; case HCI_EVENT_INQUIRY_RESULT: hci_event_inquiry_result(sp, mp); break; case HCI_EVENT_CON_COMPL: hci_event_connection_complete(sp, mp); break; case HCI_EVENT_CON_REQ: hci_event_connection_request(sp, mp); break; case HCI_EVENT_DISCON_COMPL: hci_event_disconnect_complete(sp, mp); break; case HCI_EVENT_AUTH_COMPL: hci_event_auth_complete(sp, mp); break; case HCI_EVENT_REMOTE_NAME_REQ_COMPL: hci_event_remote_name_req_complete(sp, mp); break; case HCI_EVENT_ENCRYPTION_CHANGE: hci_event_encryption_change(sp, mp); break; case HCI_EVENT_CHANGE_CON_LINK_KEY_COMPL: hci_event_change_connection_link_key_complete(sp, mp); break; case HCI_EVENT_MASTER_LINK_KEY_COMPL: hci_event_master_link_key_complete(sp, mp); break; case HCI_EVENT_READ_REMOTE_FEATURES_COMPL: hci_event_read_remote_features_complete(sp, mp); break; case HCI_EVENT_READ_REMOTE_VER_INFO_COMPL: hci_event_read_remote_version_complete(sp, mp); break; case HCI_EVENT_QOS_SETUP_COMPL: hci_event_qos_setup_complete(sp, mp); break; case HCI_EVENT_COMMAND_COMPL: hci_event_command_complete(sp, mp); break; case HCI_EVENT_COMMAND_STATUS: hci_event_command_status(sp, mp); break; case HCI_EVENT_HARDWARE_ERROR: hci_event_hardware_error(sp, mp); break; case HCI_EVENT_FLUSH_OCCUR: hci_event_flush_occur(sp, mp); break; case HCI_EVENT_ROLE_CHANGE: hci_event_role_change(sp, mp); break; case HCI_EVENT_NUM_COMPL_PKTS: hci_event_num_completed_packets(sp, mp); break; case HCI_EVENT_MODE_CHANGE: hci_event_mode_change(sp, mp); break; case HCI_EVENT_RETURN_LINK_KEYS: hci_event_return_link_keys(sp, mp); break; case HCI_EVENT_PIN_CODE_REQ: hci_event_pin_code_request(sp, mp); break; case HCI_EVENT_LINK_KEY_REQ: hci_event_link_key_request(sp, mp); break; case HCI_EVENT_LINK_KEY_NOTIFICATION: hci_event_link_key_notification(sp, mp); break; case HCI_EVENT_LOOPBACK_COMMAND: hci_event_loopback_command(sp, mp); break; case HCI_EVENT_DATA_BUFFER_OVERFLOW: hci_event_data_buf_overflow(sp, mp); break; case HCI_EVENT_MAX_SLOT_CHANGE: hci_event_max_slot_change(sp, mp); break; case HCI_EVENT_READ_CLOCK_OFFSET_COMPL: hci_event_read_clock_offset_complete(sp, mp); break; case HCI_EVENT_CON_PKT_TYPE_CHANGED: hci_event_connection_pkt_type_changed(sp, mp); break; case HCI_EVENT_QOS_VIOLATION: hci_event_qos_violation(sp, mp); break; case HCI_EVENT_PAGE_SCAN_MODE_CHANGE: hci_event_page_scan_mode_change(sp, mp); break; case HCI_EVENT_PAGE_SCAN_REP_MODE_CHANGE: hci_event_page_scan_rep_mode_change(sp, mp); break; case HCI_EVENT_FLOW_SPECIFICATION_COMPL: hci_event_flow_spec_complete(sp, mp); break; case HCI_EVENT_RSSI_RESULT: hci_event_rssi_result(sp, mp); break; case HCI_EVENT_READ_REMOTE_EXTENDED_FEATURES: hci_event_read_remote_ext_features_complete(sp, mp); case HCI_EVENT_SCO_CON_COMPL: hci_event_sco_connection_complete(sp, mp); break; case HCI_EVENT_SCO_CON_CHANGED: hci_event_sco_connection_changed(sp, mp); break; case HCI_EVENT_BT_LOGO: case HCI_EVENT_VENDOR: break; default: cmn_err(CE_WARN, "Unknown event (0x%02x) from HCI", eh->event); } }