📄 btmem.c
字号:
/* * btmem.c -- Memory management in Bluetooth stack * * Copyright (C) 2000, 2001 Axis Communications AB * * Author: Mattias Agren <mattias.agren@axis.com> * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * Exceptionally, Axis Communications AB grants discretionary and * conditional permissions for additional use of the text contained * in the company's release of the AXIS OpenBT Stack under the * provisions set forth hereunder. * * Provided that, if you use the AXIS OpenBT Stack with other files, * that do not implement functionality as specified in the Bluetooth * System specification, to produce an executable, this does not by * itself cause the resulting executable to be covered by the GNU * General Public License. Your use of that executable is in no way * restricted on account of using the AXIS OpenBT Stack code with it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the provisions of the GNU * General Public License. * * $Id: btmem.c,v 1.43 2001/06/19 06:13:01 matsf Exp $ * *//****************** INCLUDE FILES SECTION ***********************************/#define __NO_VERSION__ /* don't define kernel_version in module.h */#ifdef __KERNEL__#include <linux/malloc.h>#include <linux/bluetooth/btmem.h>#else#include <stdlib.h>#include "include/btmem.h"#include "include/btcommon.h"#include <string.h> /* memset */#endif/****************** DEBUG CONSTANT AND MACRO SECTION ************************/#if BTMEM_DEBUG#define D_MEM(fmt...) printk(BTMEM_DBG_STR fmt)#define PRINTPKT(str, data, len) print_data(str, data, len)#else#define D_MEM(fmt...) #define PRINTPKT(str, data, len)#endif /* Execute test function in init */#define BTMEM_TEST 0 /* Displays buffer usage */#define BTMEM_SHOW_GRAPH 0/* Panic if something goes wrong */#define PANIC_AT_ERROR 0/* discard all marked buffers */#define BTMEM_FLUSH_ENABLED 1/****************** CONSTANT AND MACRO SECTION ******************************/#define BUFFER_USAGE_LEVEL(usage) ((usage*100)/(int)(BT_BUF_SIZE))/****************** TYPE DEFINITION SECTION *********************************/typedef struct bt_buf_main{ u8 *head; /* Start of data buffer */ u8 *tail; /* End of data buffer */ u8 *toss_tail; /* Toss tail when getting subscribed mem */ u8 *free; /* After this pointer new data can be subscribed */ u8 *send; /* This is where send function consumes data */ s32 size; /* Total size of buffer */ s32 count; /* Total number bytes subscribed */ s32 nbr_bufs;} bt_buf_main;/****************** LOCAL FUNCTION DECLARATION SECTION **********************//* Finds a free area and subscribes it *///static bt_tx_buf* subscribe(s32 head_free, s32 tail_free, s32 len, s32 wrap);/****************** GLOBAL VARIABLE DECLARATION SECTION *********************//****************** LOCAL VARIABLE DECLARATION SECTION **********************/static bt_buf_main bt_buf = {NULL, NULL, NULL, NULL, NULL, 0, 0, 0};/****************** FUNCTION DEFINITION SECTION *****************************/void btmem_init(void){ /* Allocate memory area */ DSYS("Initialising BTMEM [%d bytes]\n", BT_BUF_SIZE); bt_buf.head = (u8*) kmalloc(BT_BUF_SIZE,GFP_KERNEL); /* Initiate main buffer object */ bt_buf.tail = bt_buf.head + BT_BUF_SIZE; bt_buf.toss_tail = bt_buf.tail; /* Used when reading wrapped data */ bt_buf.free = bt_buf.head; bt_buf.send = bt_buf.head; bt_buf.size = BT_BUF_SIZE; bt_buf.count = 0; bt_buf.nbr_bufs = 0;#if BTMEM_TEST btmem_test();#endif} /* Returns success if deallocation was successful */void btmem_shutdown(void){ DSYS("Shutting down BTMEM\n"); /* FIXME - Check that the stack is not in use */ /* Deallocate memory area */ if (bt_buf.head) kfree(bt_buf.head); bt_buf.head = NULL;}/* Is run whenever buffer is empty */void btmem_reset(){ if (bt_buf.count) D_ERR("Resetting buffer and not empty !\n"); bt_buf.toss_tail = bt_buf.tail; /* Used when reading out wrapped data*/ bt_buf.free = bt_buf.head; bt_buf.send = bt_buf.head; bt_buf.count = 0; bt_buf.nbr_bufs = 0;}/* Sets the flush flag for all buffers waiting to be sent on handle hdl. Later when calling get_bt_buf(), if the buffer found has flushed flag set the function unsubscribes it and fetches the next unflushed instead. */void btmem_flushhandle(u16 hdl){ u8 *pos = bt_buf.head; bt_tx_buf *tx; u32 i=0; D_MEM("btmem_flushhandle\n"); cli(); /* non wrapped buffer */ if (bt_buf.free > bt_buf.send) { /* read from send -> free */ pos = bt_buf.send; while (pos < bt_buf.free) { tx = (bt_tx_buf *)(pos); if (tx->hci_hdl==hdl) { i++; tx->flushed=1; } pos += BT_TX_HDRSIZE + tx->subscr_len; } } else if (bt_buf.free!=bt_buf.send) { /* wrapped buffer */ /* send -> toss_tail, read from head -> free */ pos = bt_buf.send; while (pos < bt_buf.toss_tail) { tx = (bt_tx_buf *)(pos); if (tx->hci_hdl==hdl) { i++; tx->flushed=1; } pos += BT_TX_HDRSIZE + tx->subscr_len; } pos = bt_buf.head; while (pos < bt_buf.free) { tx = (bt_tx_buf*)(pos); if (tx->hci_hdl==hdl) { i++; tx->flushed=1; } pos += BT_TX_HDRSIZE + tx->subscr_len; } } else { /*empty buffer */ sti(); return; } D_MEM("btmem_flushhandle : flushed %d buffers\n", i); sti(); /* get_bt_buf removes flushed buffers if located in queue head */ get_bt_buf();}/* Subscribes one bt_tx_buf with send_len bytes in the data segment */bt_tx_buf* subscribe_bt_buf(s32 send_len){ bt_tx_buf *tx; s32 buf_len; /* Total size of bt_tx_object */ u32 head_free; u32 tail_free; /* Number bytes available */ cli(); buf_len = send_len + BT_TX_HDRSIZE; D_MEM(__FUNCTION__ ": buf_len %d\n", buf_len); /* 'Normal' case send free | | --------------------------------------------- | head_free |XXXXXXXXXXXX| tail_free | --------------------------------------------- head tail */ /* check for flushed buffers */ get_bt_buf(); if (bt_buf.free > bt_buf.send) { tail_free = (bt_buf.tail - bt_buf.free); head_free = (bt_buf.send - bt_buf.head); if (tail_free >= buf_len) { D_MEM(__FUNCTION__ ": subscribe in tail at pos %d\n", bt_buf.free - bt_buf.head); tx = (bt_tx_buf *)bt_buf.free; /* Don't touch send, only update free and count */ bt_buf.free += buf_len; bt_buf.count += buf_len; bt_buf.nbr_bufs++; } else if (head_free >= buf_len) { D_MEM("No room in tail, subscribe at head (WRAP!)\n"); tx = (bt_tx_buf *)bt_buf.head; /* Toss rest of tail to avoid fragmenting */ bt_buf.toss_tail = bt_buf.free; bt_buf.free = bt_buf.head+buf_len; /*Now send > free */ bt_buf.nbr_bufs++; bt_buf.count += buf_len; } else { D_ERR(__FUNCTION__ ": Cannot subscribe %d bytes !\n", send_len); D_ERR(__FUNCTION__ ": Only %d available (non - fragmented)\n", buf_write_room());#if PANIC_AT_ERROR btmem_get_status(NULL); panic("lets stop here...\n");#endif sti(); return NULL; } } else if (bt_buf.free <= bt_buf.send) { /* 'Wrap' case */ tail_free = (bt_buf.send - bt_buf.free); head_free = 0; /* head_free is not interesting since we cannot put data here even if it would fit since we already have put data in the start of the buffer! (Fragmentation) */ if (tail_free >= buf_len) { D_MEM("Wrapped buffer, subscribe at free (pos %d)\n", bt_buf.free - bt_buf.head); tx = (bt_tx_buf *)bt_buf.free; bt_buf.free += buf_len; bt_buf.count += buf_len; bt_buf.nbr_bufs++; } else if (!bt_buf.count) { /* If buffer empty, reset buffer */ btmem_reset(); if (buf_len > bt_buf.size) { D_ERR(__FUNCTION__ ": Cannot subscribe %d bytes !\n", send_len); D_ERR(__FUNCTION__ ": Only %d available (non - fragmented)\n", buf_write_room()); btmem_get_status(NULL); sti(); return NULL; } D_MEM("Buffer empty, reset buffer and subsc at %d\n ", bt_buf.free - bt_buf.head); tx = (bt_tx_buf *)bt_buf.free; bt_buf.free += buf_len; bt_buf.count += buf_len; bt_buf.nbr_bufs++; } else { D_ERR(__FUNCTION__ ": Cannot subscribe requested size (%d) !\n", send_len); D_ERR(__FUNCTION__ ": Only %d available (non - fragmented)\n", buf_write_room()); btmem_get_status(NULL);#if PANIC_AT_ERROR panic("lets stop here... (WRAP)\n");#endif sti(); return NULL; } } tx->magic = 0x4321; tx->subscr_len = send_len; tx->flushed = 0; tx->line = -1; sti();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -