2005-04-17 02:20:36 +04:00
/*
*
2005-10-28 21:20:45 +04:00
* Bluetooth HCI UART driver
*
* Copyright ( C ) 2000 - 2001 Qualcomm Incorporated
* Copyright ( C ) 2002 - 2003 Maxim Krasnyansky < maxk @ qualcomm . com >
* Copyright ( C ) 2004 - 2005 Marcel Holtmann < marcel @ holtmann . org >
*
*
* 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
*
2005-04-17 02:20:36 +04:00
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/types.h>
# include <linux/fcntl.h>
# include <linux/interrupt.h>
# include <linux/ptrace.h>
# include <linux/poll.h>
# include <linux/slab.h>
# include <linux/tty.h>
# include <linux/errno.h>
# include <linux/string.h>
# include <linux/signal.h>
# include <linux/ioctl.h>
# include <linux/skbuff.h>
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
2005-10-28 21:20:45 +04:00
2005-04-17 02:20:36 +04:00
# include "hci_uart.h"
2005-10-28 21:20:45 +04:00
# define VERSION "1.2"
struct h4_struct {
unsigned long rx_state ;
unsigned long rx_count ;
struct sk_buff * rx_skb ;
struct sk_buff_head txq ;
} ;
/* H4 receiver States */
# define H4_W4_PACKET_TYPE 0
# define H4_W4_EVENT_HDR 1
# define H4_W4_ACL_HDR 2
# define H4_W4_SCO_HDR 3
# define H4_W4_DATA 4
2005-04-17 02:20:36 +04:00
/* Initialize protocol */
static int h4_open ( struct hci_uart * hu )
{
struct h4_struct * h4 ;
2005-10-28 21:20:45 +04:00
2005-04-17 02:20:36 +04:00
BT_DBG ( " hu %p " , hu ) ;
2005-10-28 21:20:45 +04:00
2005-11-07 12:01:26 +03:00
h4 = kzalloc ( sizeof ( * h4 ) , GFP_ATOMIC ) ;
2005-04-17 02:20:36 +04:00
if ( ! h4 )
return - ENOMEM ;
2005-10-28 21:20:45 +04:00
2005-04-17 02:20:36 +04:00
skb_queue_head_init ( & h4 - > txq ) ;
hu - > priv = h4 ;
return 0 ;
}
/* Flush protocol data */
static int h4_flush ( struct hci_uart * hu )
{
struct h4_struct * h4 = hu - > priv ;
BT_DBG ( " hu %p " , hu ) ;
2005-10-28 21:20:45 +04:00
2005-04-17 02:20:36 +04:00
skb_queue_purge ( & h4 - > txq ) ;
2005-10-28 21:20:45 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* Close protocol */
static int h4_close ( struct hci_uart * hu )
{
struct h4_struct * h4 = hu - > priv ;
2005-10-28 21:20:45 +04:00
2005-04-17 02:20:36 +04:00
hu - > priv = NULL ;
BT_DBG ( " hu %p " , hu ) ;
skb_queue_purge ( & h4 - > txq ) ;
2005-10-28 21:20:45 +04:00
2009-02-25 13:09:33 +03:00
kfree_skb ( h4 - > rx_skb ) ;
2005-04-17 02:20:36 +04:00
hu - > priv = NULL ;
kfree ( h4 ) ;
2005-10-28 21:20:45 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* Enqueue frame for transmittion (padding, crc, etc) */
static int h4_enqueue ( struct hci_uart * hu , struct sk_buff * skb )
{
struct h4_struct * h4 = hu - > priv ;
BT_DBG ( " hu %p skb %p " , hu , skb ) ;
/* Prepend skb with frame type */
2005-08-10 07:30:28 +04:00
memcpy ( skb_push ( skb , 1 ) , & bt_cb ( skb ) - > pkt_type , 1 ) ;
2005-04-17 02:20:36 +04:00
skb_queue_tail ( & h4 - > txq , skb ) ;
2005-10-28 21:20:45 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
static inline int h4_check_data_len ( struct h4_struct * h4 , int len )
{
register int room = skb_tailroom ( h4 - > rx_skb ) ;
BT_DBG ( " len %d room %d " , len , room ) ;
2005-10-28 21:20:45 +04:00
2005-04-17 02:20:36 +04:00
if ( ! len ) {
hci_recv_frame ( h4 - > rx_skb ) ;
} else if ( len > room ) {
BT_ERR ( " Data length is too large " ) ;
kfree_skb ( h4 - > rx_skb ) ;
} else {
h4 - > rx_state = H4_W4_DATA ;
h4 - > rx_count = len ;
return len ;
}
h4 - > rx_state = H4_W4_PACKET_TYPE ;
h4 - > rx_skb = NULL ;
h4 - > rx_count = 0 ;
2005-10-28 21:20:45 +04:00
2005-04-17 02:20:36 +04:00
return 0 ;
}
/* Recv data */
static int h4_recv ( struct hci_uart * hu , void * data , int count )
{
2011-04-08 01:53:45 +04:00
int ret ;
ret = hci_recv_stream_fragment ( hu - > hdev , data , count ) ;
if ( ret < 0 ) {
2010-07-24 08:46:57 +04:00
BT_ERR ( " Frame Reassembly Failed " ) ;
2011-04-08 01:53:45 +04:00
return ret ;
}
2005-10-28 21:20:45 +04:00
2005-04-17 02:20:36 +04:00
return count ;
}
static struct sk_buff * h4_dequeue ( struct hci_uart * hu )
{
struct h4_struct * h4 = hu - > priv ;
return skb_dequeue ( & h4 - > txq ) ;
}
static struct hci_uart_proto h4p = {
2005-10-28 21:20:45 +04:00
. id = HCI_UART_H4 ,
. open = h4_open ,
. close = h4_close ,
. recv = h4_recv ,
. enqueue = h4_enqueue ,
. dequeue = h4_dequeue ,
. flush = h4_flush ,
2005-04-17 02:20:36 +04:00
} ;
2005-10-28 21:20:45 +04:00
2010-07-24 09:04:44 +04:00
int __init h4_init ( void )
2005-04-17 02:20:36 +04:00
{
int err = hci_uart_register_proto ( & h4p ) ;
2005-10-28 21:20:45 +04:00
2005-04-17 02:20:36 +04:00
if ( ! err )
BT_INFO ( " HCI H4 protocol initialized " ) ;
else
BT_ERR ( " HCI H4 protocol registration failed " ) ;
2005-10-28 21:20:45 +04:00
2005-04-17 02:20:36 +04:00
return err ;
}
2010-07-24 09:04:44 +04:00
int __exit h4_deinit ( void )
2005-04-17 02:20:36 +04:00
{
return hci_uart_unregister_proto ( & h4p ) ;
}