📄 bluetooth.c
字号:
#ifdef BT_USELINEBUF /* WINDOZE FIX */ BT_DATA(__FUNCTION__ ": (%d) line %d not active yet..., buffer it !\n", len, line); /* FIXME -- only buffer first packet ? */ bt_linebuf_add(line, data, len);#else BT_DATA(__FUNCTION__ ": (%d) line %d not active yet... silent discard!\n", len, line);#endif return 0; } bt_stat.bytes_received += len; upper_tty = GET_UPPERTTY(line); if (upper_tty) { upper_tty->ldisc.receive_buf(upper_tty, data, NULL, len); } else {// D_ERR(__FUNCTION__ ": No upper tty registered !!!\n"); return -1; } return 0;}//#define IMPROVE_RFCOMM_FLOWvoid bt_feedstack(void){ struct tty_struct *upper_tty = NULL; s32 check_line; s32 nbr_checked = 0; if (NBR_ACTIVE == 0) { return; } /* If buffer usage is less than BTMEM_UNTHROTTLE_SIZE check if we should wake up ldisc */ if (buf_byte_count(-1) >= BTMEM_UNTHROTTLE_SIZE) { return; } /* Choose next line to check */ if (NBR_ACTIVE == 1) { /* check same as last time */ check_line = bt_ctrl.tty_last_unthrottled; } else if (bt_ctrl.tty_last_unthrottled == BT_NBR_DATAPORTS-1) { /* wrap */ check_line = 0; } else { check_line = bt_ctrl.tty_last_unthrottled+1; } // BT_DATA(__FUNCTION__ ": Start on line %d\n", check_line); /* skip non-active and control port (last) */ while ((SESSIONSTATE(check_line) != BT_ACTIVE) && (nbr_checked <= BT_NBR_DATAPORTS)) { check_line++; nbr_checked++; if (check_line == BT_NBR_DATAPORTS) /* wrap */ check_line = 0; } /* check if we really found an active */ if (nbr_checked > BT_NBR_DATAPORTS) return;// BT_DATA(__FUNCTION__ ": Wakeup line %d !\n", check_line); upper_tty = GET_UPPERTTY(check_line); bt_ctrl.tty_last_unthrottled = check_line; if (!upper_tty) {// BT_DATA("No active line to feed from!\n"); return; }#ifdef IMPROVE_RFCOMM_FLOW /* FIXME: How should we know what serverchannel we are using ? */ if (rfcomm_flow_stop(check_line, 2)) { BT_DATA(__FUNCTION__ ": Flow stopped in RFCOMM\n"); return; }#endif if ((upper_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && upper_tty->ldisc.write_wakeup) {// BT_DATA(" |X|<<*** [%d]\n", check_line); /* TTY_DO_WRITE_WAKEUP bit is cleared in upper_tty->flags which means user mode process will be able to write more data */ (upper_tty->ldisc.write_wakeup)(upper_tty); } else if (!upper_tty->ldisc.write_wakeup) { /* if no wake_up function is defined (N_TTY ldisc) wake up wait queue */// BT_DATA(" |X|<<*** [%d] (n_tty)\n", check_line); wake_up_interruptible(&upper_tty->write_wait); }}/* Used to wait for dma to finish transmission */void bt_wait_tx(s32 trim_delay){ while (sertty->driver.chars_in_buffer(sertty) > 0) udelay(100); udelay(trim_delay);}#ifdef CONFIG_BLUETOOTH_USE_INBUFFERstatic void bt_handle_indata(const __u8 *data, s32 count){ s32 free; /* Check if there is data that hasn't been passed up to hci yet. In that case there is a task scheduled for this and we shouldn't add another one. */ if (hci_data.put == hci_data.get) { bt_receive_task.routine = (void*)hci_receive_data_task; bt_receive_task.data = NULL;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) queue_task(&bt_receive_task, &tq_scheduler);#else queue_task(&bt_receive_task, &tq_immediate); mark_bh(IMMEDIATE_BH);#endif } if (hci_data.put >= hci_data.get) { /* check for overruns... */ if (hci_data.put + count - BT_INBUFFER_SIZE >= hci_data.get) { D_ERR(__FUNCTION__ ": Buffer overrun!\n"); } else { /* Calculate how much space there is left at the end of the buffer */ free = hci_data.tail - hci_data.put + 1; /* normal case, data fits in buffer */ if (count < free) { memcpy(hci_data.put, (u8*)data, count); } else { /* wrap buffer */ memcpy(hci_data.put, (u8*)data, free); memcpy(hci_data.head, (u8*)(data + free), count - free); } } } else { /* hci_data.put < hci_data.get */ /* check for overruns ... */ if (hci_data.put + count >= hci_data.get) { D_ERR(__FUNCTION__ ": Buffer overrun!\n"); } else { /* Copy the data to the buffer */ memcpy(hci_data.put, (u8*)data, count); } } hci_data.put += count; if (hci_data.put > hci_data.tail) hci_data.put -= BT_INBUFFER_SIZE; }static voidhci_receive_data_task(void){ s32 size_end; s32 size_start; u8* getTemp; cli(); if (hci_data.get == hci_data.put) { sti(); return; } else if (hci_data.get > hci_data.put) { /* buffer is wrapped */ size_end = hci_data.tail - hci_data.get + 1; size_start = hci_data.put - hci_data.head; getTemp = hci_data.get; /* Indicate that all data has been fetched (or soon will be) by setting get == put. */ hci_data.get = hci_data.put; sti(); bt_receive_data(getTemp, size_end); bt_receive_data(hci_data.head, size_start); } else { /* no wrapped buffer */ size_end = hci_data.put - hci_data.get; getTemp = hci_data.get; /* Indicate that all data has been fetched (or soon will be) by setting get == put. */ hci_data.get = hci_data.put; sti(); bt_receive_data(getTemp, size_end); }}#endif /* CONFIG_BLUETOOTH_USE_INBUFFER *//* * Searches data buffer for number of completed packets (NCP) * If only NCP data was found tell serial driver not to * schedule a flip of DMA inbuffer. */int bt_catch_ncp(u8* data, u32 count){ int index = 0; /* fixme -- do this for BCSP as well */#ifdef CONFIG_BLUETOOTH_SUPPORT_BCSP if (bt_use_bcsp(-1)) return 0;#endif /* || uart hdr | event code | par_len | nbr_handles | [data...] || */ while (index+2 < count && data[index] == EVENT_PKT && data[index+1] == NBR_OF_COMPLETED_PACKETS) { /* we found a NCP */ index += (3 + data[index + 2]); /* event hdr + par len */ } if (index == count) { /* Contains _only_ NCP data, parse it ! */ /* The easy way would be to call bt_receive_data(data, count), but since it calls hci_receive_data() which is a state machine, we might mess up its state... */ index = 0; while (index+2 < count) { update_ncp(data[index+3], data+index+4); index += (3 + data[index + 2]); } return 1; } /* Contains more than NCP data, tell serial driver to queue it up as usual */ return 0;}static voidbt_receive_data(u8* data, u32 count){#ifdef CONFIG_BLUETOOTH_SUPPORT_BCSP if (bt_use_bcsp(-1)) bcsp_receive_lower(data, count); else#endif hci_receive_data(data, count);}/* Opens a connection to the selected PSM, layer specific is the same as the * lowest part on the connection ID, in RFCOMM this is line | dlci, each one * is 8-bits */s32bt_connect(u8 *bd_addr, u32 con_id){ u8 line = GET_LINE(con_id); s32 retval = 0; /* Check if we already got a connection on the line */ if ((SESSIONSTATE(line) == BT_LOWERCONNECTED)|| (SESSIONSTATE(line) == BT_ACTIVE)) { D_WARN(__FUNCTION__ ": Already got connection on line %d\n", line); return -MSGCODE(MSG_BT_INTERFACE, BT_LINE_BUSY); } switch (GET_PSM(con_id)) { case RFCOMM_LAYER: { u8 srv_ch; s32 retval = 0; CHECK_RFCOMM(con_id); srv_ch = GET_RFCOMMSRVCH(con_id); bt_ctrl.session[line].connect_status = -1; BT_DRIVER(__FUNCTION__ ": Connecting srv ch %d on line %d\n", srv_ch, line); BT_DATADUMP("Remote BD: ", bd_addr, 6); if ((retval = rfcomm_connect_req(bd_addr, srv_ch, line)) < 0) { BT_DRIVER(__FUNCTION__ ": Failed\n"); return retval; } /* sleep if not yet connected */ if (bt_ctrl.session[line].connect_status == -1) { start_wq_timer(&bt_timer, BT_CON_TIMEOUT, &bt_ctrl.connect_wq[line]); interruptible_sleep_on(&bt_ctrl.connect_wq[line]); } return bt_ctrl.session[line].connect_status; } break; case SDP_LAYER: { int sdp_connection_id = -1; int return_value; /* Initiate the connection */ BT_DRIVER(__FUNCTION__ ": Connecting SDP on line %d\n", line); BT_DATADUMP("Remote BD: ", bd_addr, 6); if ((sdp_connection_id = sdp_connect_req(bd_addr, line)) >= 0) { /* * If here, we have successfully created an SDP * connection entry and are starting the sequence of * opening an l2cap connection. Allow the bottom * half to process the request and get back to us. */ /* I seem to be having a lot of trouble with the L2CAP traffic just not appearing on this side of the link while I'm waiting for the SDP conneciton to finish up. So let's start a timer to wake us up if things don't appear to be working out. --gmcnutt */ /* fixme -- we probably need a lock on this timer since multiple processes could be trying to use it at the same time... or maybe use one timer per session. */ start_wq_timer(&bt_timer, BT_CON_TIMEOUT, &bt_ctrl.connect_wq[line]); /* The timeout routine doesn't have a hendle to our session status, so set things up to reflect a timeout error by default. If we really do get a connection then this value _should_ be changed by the time we wake up to reflect a good connection. --gmcnutt */ bt_ctrl.session[line].connect_status = -ETIMEDOUT; BT_DRIVER(__FUNCTION__ ": Sleep on line %d\n", line); interruptible_sleep_on(&bt_ctrl.connect_wq[line]); /* * If the connect_status is >= 0, then the lower * stack did not have a problem handling the request. * Therefore return the sdp_connection_id */ BT_DRIVER(__FUNCTION__ ": Wake up - line %d\n", line); if (bt_ctrl.session[line].connect_status >= 0) { return_value = sdp_connection_id; } else { return_value = bt_ctrl.session[line].connect_status; } } else { return_value = sdp_connection_id; } return return_value; } break; case L2CAP_TEST_LAYER: case L2CAP_TEST2_LAYER: case L2CAP_TEST3_LAYER: BT_DRIVER(__FUNCTION__ ": Connecting TEST_LAYER (psm %02X) on line %d\n", GET_PSM(con_id), line); if((retval = test_connect_psmreq(bd_addr, GET_PSM(con_id))) < 0) { BT_DRIVER(__FUNCTION__ ": Failed\n"); return retval; } return retval; case TCS_LAYER: return tcs_connect_req(bd_addr); default: BT_DRIVER(__FUNCTION__ ": PSM %d not supported as client\n", GET_PSM(con_id)); break; } return -1;}static s32 bt_execute_sdp_request(bt_sdp_request *sdpRequest){ int line = GET_LINE(sdpRequest->conID); int sdpIndex = GET_SDPINDEX(sdpRequest->conID); if (SESSIONSTATE(line) != BT_ACTIVE) { /* SDP connection not active! Don't issue the request */ BT_DRIVER(__FUNCTION__ ": Line %d does not have an active connection!\n", line); return -ENOTCONN; } BT_DRIVER(__FUNCTION__ ": Line %d SDP index %d\n", line, sdpIndex); if (sdpStartRequest(sdpIndex, sdpRequest->sdpCommand, sdpRequest->pduPayload, sdpRequest->pduLength) < 0) return -1; /* fixme -- EPERM probably not appropriate */ /* Sleep on this line while the response is going through */ printk(__FUNCTION__ ": Sleep on line %d\n", line); interruptible_sleep_on(&bt_ctrl.connect_wq[line]); /* If we're back, there may be data to send back. Copy into sdpRequest and return */ if (bt_ctrl.session[line].sdpRequestResponseData) { BT_DRIVER(__FUNCTION__ ": sdpRequestResponseData 0x%x - copying\n", (int)bt_ctrl.session[line].sdpRequestResponseData); memcpy(sdpRequest->requestResponse, bt_ctrl.session[line].sdpRequestResponseData, bt_ctrl.session[line].sdpRequestResponseDataLength); sdpRequest->responseLength = bt_ctrl.session[line].sdpRequestResponseDataLength; } return 0;} voidbt_connect_ind(u32 con_id) { if (GET_PSM(con_id) == RFCOMM_LAYER) BT_DRIVER(__FUNCTION__ ": RFCOMM dlci : %d\n", GET_RFCOMMDLCI(con_id)); else BT_DRIVER(__FUNCTION__ ": PSM %d\n", GET_PSM(con_id));}voidbt_connect_cfm(u32 con_id, s32 status){ u16 psm; s32 line = GET_LINE(con_id); psm = GET_PSM(con_id); if ((line < 0) || (line > BT_NBR_DATAPORTS)) { D_ERR(__FUNCTION__ ": Invalid line (%d)\n", line); return; } switch (psm) { case RFCOMM_LAYER: CHECK_RFCOMM(con_id); bt_ctrl.session[line].connect_status = status; BT_DRIVER(__FUNCTION__ ": Line %d [%s]\n", line, psmname(psm)); release_wq_timer(&bt_timer); wake_up_interruptible(&bt_ctrl.connect_wq[line]); wake_up_interruptible(&bt_ctrl.any_wq); break; case SDP_LAYER: /* Record the connection status for bt_connect() to process. */ bt_ctrl.session[line].connect_status = status; BT_DRIVER(__FUNCTION__ ": Line %d [%s]\n", line, psmname(psm)); BT_DRIVER(__FUNCTION__ ": Wake up line %d\n", line); release_wq_timer(&bt_timer); wake_up_interruptible(&bt_ctrl.connect_wq[line]); wake_up_interruptible(&bt_ctrl.any_wq); break; case TCS_LAYER: BT_DRIVER(__FUNCTION__ ": [%s]\n", psmname(psm)); break; default: D_ERR(__FUNCTION__ ": Unknown layer %d\n", psm); break; }}void bt_send_sdp_data_received(u8 line, u8 *data, int len){ /* Check the line for validity */ if (line > BT_NBR_DATAPORTS) { D_ERR(__FUNCTION__ ": Invalid line (%d)\n", line); return; } /* When data received for this line, we simply attach the data (& length) and wake up */ BT_DRIVER(__FUNCTION__ ": data 0x%x len %d\n", (int)data, len); /* If previous data, deallocate it */ if (bt_ctrl.session[line].sdpRequestResponseData) { D_WARN(__FUNCTION__ ": sdpRequestResponseData set - deallocate\n"); kfree(bt_ctrl.session[line].sdpRequestResponseData); bt_ctrl.session[line].sdpRequestResponseData = NULL; bt_ctrl.session[line].sdpRequestResponseDataLength = 0; } bt_ctrl.session[line].sdpRequestResponseData = data; bt_ctrl.session[line].sdpRequestResponseDataLength = len; wake_up_interruptible(&bt_ctrl.connect_wq[line]); return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -