11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
30372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  Bluetooth HCI UART driver
40372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *
50372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  Copyright (C) 2000-2001  Qualcomm Incorporated
60372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
70372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  Copyright (C) 2004-2005  Marcel Holtmann <marcel@holtmann.org>
80372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *
90372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *
100372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  This program is free software; you can redistribute it and/or modify
110372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  it under the terms of the GNU General Public License as published by
120372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  the Free Software Foundation; either version 2 of the License, or
130372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  (at your option) any later version.
140372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *
150372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  This program is distributed in the hope that it will be useful,
160372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  but WITHOUT ANY WARRANTY; without even the implied warranty of
170372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
180372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  GNU General Public License for more details.
190372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *
200372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  You should have received a copy of the GNU General Public License
210372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  along with this program; if not, write to the Free Software
220372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
230372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h>
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/poll.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/signal.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioctl.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/bluetooth/bluetooth.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/bluetooth/hci_core.h>
460372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "hci_uart.h"
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
490372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann#define VERSION "1.2"
500372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
510372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmannstruct h4_struct {
520372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann	unsigned long rx_state;
530372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann	unsigned long rx_count;
540372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann	struct sk_buff *rx_skb;
550372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann	struct sk_buff_head txq;
560372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann};
570372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
580372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann/* H4 receiver States */
590372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann#define H4_W4_PACKET_TYPE	0
600372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann#define H4_W4_EVENT_HDR		1
610372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann#define H4_W4_ACL_HDR		2
620372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann#define H4_W4_SCO_HDR		3
630372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann#define H4_W4_DATA		4
640372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Initialize protocol */
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int h4_open(struct hci_uart *hu)
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct h4_struct *h4;
690372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("hu %p", hu);
710372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
72fdcd1661a6b22e3ac429759627d2b4d68f77d64aDavid Herrmann	h4 = kzalloc(sizeof(*h4), GFP_KERNEL);
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!h4)
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
750372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_head_init(&h4->txq);
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hu->priv = h4;
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Flush protocol data */
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int h4_flush(struct hci_uart *hu)
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct h4_struct *h4 = hu->priv;
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("hu %p", hu);
880372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_purge(&h4->txq);
900372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Close protocol */
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int h4_close(struct hci_uart *hu)
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct h4_struct *h4 = hu->priv;
980372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hu->priv = NULL;
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("hu %p", hu);
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_purge(&h4->txq);
1040372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
105b1fb06830dc870d862f7f80e276130c0ab84d59fWei Yongjun	kfree_skb(h4->rx_skb);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	hu->priv = NULL;
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(h4);
1090372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Enqueue frame for transmittion (padding, crc, etc) */
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct h4_struct *h4 = hu->priv;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("hu %p skb %p", hu, skb);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Prepend skb with frame type */
1210d48d93947dd9ea21c5cdc76a8581b06a4a39281Marcel Holtmann	memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_queue_tail(&h4->txq, skb);
1230372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int h4_check_data_len(struct h4_struct *h4, int len)
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register int room = skb_tailroom(h4->rx_skb);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	BT_DBG("len %d room %d", len, room);
1320372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!len) {
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		hci_recv_frame(h4->rx_skb);
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else if (len > room) {
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_ERR("Data length is too large");
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree_skb(h4->rx_skb);
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		h4->rx_state = H4_W4_DATA;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		h4->rx_count = len;
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return len;
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	h4->rx_state = H4_W4_PACKET_TYPE;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	h4->rx_skb   = NULL;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	h4->rx_count = 0;
1470372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Recv data */
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int h4_recv(struct hci_uart *hu, void *data, int count)
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
154b86ed368f1f0b19de1918c57e4b056e73d5613a0Gustavo F. Padovan	int ret;
155b86ed368f1f0b19de1918c57e4b056e73d5613a0Gustavo F. Padovan
156b86ed368f1f0b19de1918c57e4b056e73d5613a0Gustavo F. Padovan	ret = hci_recv_stream_fragment(hu->hdev, data, count);
157b86ed368f1f0b19de1918c57e4b056e73d5613a0Gustavo F. Padovan	if (ret < 0) {
158e9da101f6d0c9a8fda9f78a80365ba2a9f75603fGustavo F. Padovan		BT_ERR("Frame Reassembly Failed");
159b86ed368f1f0b19de1918c57e4b056e73d5613a0Gustavo F. Padovan		return ret;
160b86ed368f1f0b19de1918c57e4b056e73d5613a0Gustavo F. Padovan	}
1610372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return count;
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sk_buff *h4_dequeue(struct hci_uart *hu)
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct h4_struct *h4 = hu->priv;
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return skb_dequeue(&h4->txq);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct hci_uart_proto h4p = {
1720372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann	.id		= HCI_UART_H4,
1730372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann	.open		= h4_open,
1740372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann	.close		= h4_close,
1750372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann	.recv		= h4_recv,
1760372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann	.enqueue	= h4_enqueue,
1770372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann	.dequeue	= h4_dequeue,
1780372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann	.flush		= h4_flush,
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1800372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
181f2b94bb9e0b8bd048331a6e9d616e918f4bcbd97Gustavo F. Padovanint __init h4_init(void)
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = hci_uart_register_proto(&h4p);
1840372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!err)
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_INFO("HCI H4 protocol initialized");
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		BT_ERR("HCI H4 protocol registration failed");
1890372a6627f862f90a2c43772befeecef508cfd7bMarcel Holtmann
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return err;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
193f2b94bb9e0b8bd048331a6e9d616e918f4bcbd97Gustavo F. Padovanint __exit h4_deinit(void)
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return hci_uart_unregister_proto(&h4p);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
197