Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb400801 authored by David S. Miller's avatar David S. Miller
Browse files
parents 130aa61a 611b30f7
Loading
Loading
Loading
Loading
+19 −71
Original line number Diff line number Diff line
@@ -40,7 +40,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>

#define VERSION "1.2"
#define VERSION "1.3"

static int minor = MISC_DYNAMIC_MINOR;

@@ -51,14 +51,8 @@ struct vhci_data {

	wait_queue_head_t read_wait;
	struct sk_buff_head readq;

	struct fasync_struct *fasync;
};

#define VHCI_FASYNC	0x0010

static struct miscdevice vhci_miscdev;

static int vhci_open_dev(struct hci_dev *hdev)
{
	set_bit(HCI_RUNNING, &hdev->flags);
@@ -105,9 +99,6 @@ static int vhci_send_frame(struct sk_buff *skb)
	memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
	skb_queue_tail(&data->readq, skb);

	if (data->flags & VHCI_FASYNC)
		kill_fasync(&data->fasync, SIGIO, POLL_IN);

	wake_up_interruptible(&data->read_wait);

	return 0;
@@ -179,41 +170,31 @@ static inline ssize_t vhci_put_user(struct vhci_data *data,
static ssize_t vhci_read(struct file *file,
				char __user *buf, size_t count, loff_t *pos)
{
	DECLARE_WAITQUEUE(wait, current);
	struct vhci_data *data = file->private_data;
	struct sk_buff *skb;
	ssize_t ret = 0;

	add_wait_queue(&data->read_wait, &wait);
	while (count) {
		set_current_state(TASK_INTERRUPTIBLE);

		skb = skb_dequeue(&data->readq);
		if (!skb) {
			if (file->f_flags & O_NONBLOCK) {
				ret = -EAGAIN;
		if (skb) {
			ret = vhci_put_user(data, skb, buf, count);
			if (ret < 0)
				skb_queue_head(&data->readq, skb);
			else
				kfree_skb(skb);
			break;
		}

			if (signal_pending(current)) {
				ret = -ERESTARTSYS;
		if (file->f_flags & O_NONBLOCK) {
			ret = -EAGAIN;
			break;
		}

			schedule();
			continue;
		}

		if (access_ok(VERIFY_WRITE, buf, count))
			ret = vhci_put_user(data, skb, buf, count);
		else
			ret = -EFAULT;

		kfree_skb(skb);
		ret = wait_event_interruptible(data->read_wait,
					!skb_queue_empty(&data->readq));
		if (ret < 0)
			break;
	}
	set_current_state(TASK_RUNNING);
	remove_wait_queue(&data->read_wait, &wait);

	return ret;
}
@@ -223,9 +204,6 @@ static ssize_t vhci_write(struct file *file,
{
	struct vhci_data *data = file->private_data;

	if (!access_ok(VERIFY_READ, buf, count))
		return -EFAULT;

	return vhci_get_user(data, buf, count);
}

@@ -259,11 +237,9 @@ static int vhci_open(struct inode *inode, struct file *file)
	skb_queue_head_init(&data->readq);
	init_waitqueue_head(&data->read_wait);

	lock_kernel();
	hdev = hci_alloc_dev();
	if (!hdev) {
		kfree(data);
		unlock_kernel();
		return -ENOMEM;
	}

@@ -284,12 +260,10 @@ static int vhci_open(struct inode *inode, struct file *file)
		BT_ERR("Can't register HCI device");
		kfree(data);
		hci_free_dev(hdev);
		unlock_kernel();
		return -EBUSY;
	}

	file->private_data = data;
	unlock_kernel();

	return nonseekable_open(inode, file);
}
@@ -310,48 +284,25 @@ static int vhci_release(struct inode *inode, struct file *file)
	return 0;
}

static int vhci_fasync(int fd, struct file *file, int on)
{
	struct vhci_data *data = file->private_data;
	int err = 0;

	lock_kernel();
	err = fasync_helper(fd, file, on, &data->fasync);
	if (err < 0)
		goto out;

	if (on)
		data->flags |= VHCI_FASYNC;
	else
		data->flags &= ~VHCI_FASYNC;

out:
	unlock_kernel();
	return err;
}

static const struct file_operations vhci_fops = {
	.owner		= THIS_MODULE,
	.read		= vhci_read,
	.write		= vhci_write,
	.poll		= vhci_poll,
	.ioctl		= vhci_ioctl,
	.open		= vhci_open,
	.release	= vhci_release,
	.fasync		= vhci_fasync,
};

static struct miscdevice vhci_miscdev= {
	.name	= "vhci",
	.fops	= &vhci_fops,
	.minor	= MISC_DYNAMIC_MINOR,
};

static int __init vhci_init(void)
{
	BT_INFO("Virtual HCI driver ver %s", VERSION);

	vhci_miscdev.minor = minor;

	if (misc_register(&vhci_miscdev) < 0) {
		BT_ERR("Can't register misc device with minor %d", minor);
		return -EIO;
@@ -369,9 +320,6 @@ static void __exit vhci_exit(void)
module_init(vhci_init);
module_exit(vhci_exit);

module_param(minor, int, 0444);
MODULE_PARM_DESC(minor, "Miscellaneous minor device number");

MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
MODULE_DESCRIPTION("Bluetooth virtual HCI driver ver " VERSION);
MODULE_VERSION(VERSION);
+0 −6
Original line number Diff line number Diff line
@@ -81,12 +81,6 @@ enum {
	BT_CLOSED
};

/* Endianness conversions */
#define htobs(a)	__cpu_to_le16(a)
#define htobl(a)	__cpu_to_le32(a)
#define btohs(a)	__le16_to_cpu(a)
#define btohl(a)	__le32_to_cpu(a)

/* BD Address */
typedef struct {
	__u8 b[6];
+2 −0
Original line number Diff line number Diff line
@@ -137,6 +137,8 @@ struct hci_dev {
	struct device		*parent;
	struct device		dev;

	struct rfkill		*rfkill;

	struct module 		*owner;

	int (*open)(struct hci_dev *hdev);
+50 −21
Original line number Diff line number Diff line
@@ -27,7 +27,12 @@

/* L2CAP defaults */
#define L2CAP_DEFAULT_MTU		672
#define L2CAP_DEFAULT_FLUSH_TO	0xFFFF
#define L2CAP_DEFAULT_FLUSH_TO		0xffff
#define L2CAP_DEFAULT_RX_WINDOW		1
#define L2CAP_DEFAULT_MAX_RECEIVE	1
#define L2CAP_DEFAULT_RETRANS_TO	300    /* 300 milliseconds */
#define L2CAP_DEFAULT_MONITOR_TO	1000   /* 1 second */
#define L2CAP_DEFAULT_MAX_RX_APDU	0xfff7

#define L2CAP_CONN_TIMEOUT	(40000) /* 40 seconds */
#define L2CAP_INFO_TIMEOUT	(4000)  /*  4 seconds */
@@ -76,6 +81,18 @@ struct l2cap_conninfo {
#define L2CAP_INFO_REQ		0x0a
#define L2CAP_INFO_RSP		0x0b

/* L2CAP feature mask */
#define L2CAP_FEAT_FLOWCTL	0x00000001
#define L2CAP_FEAT_RETRANS	0x00000002
#define L2CAP_FEAT_ERTM		0x00000008
#define L2CAP_FEAT_STREAMING	0x00000010
#define L2CAP_FEAT_FCS		0x00000020
#define L2CAP_FEAT_FIXED_CHAN	0x00000080

/* L2CAP checksum option */
#define L2CAP_FCS_NONE		0x00
#define L2CAP_FCS_CRC16		0x01

/* L2CAP structures */
struct l2cap_hdr {
	__le16     len;
@@ -106,6 +123,12 @@ struct l2cap_conn_rsp {
	__le16     status;
} __attribute__ ((packed));

/* channel indentifier */
#define L2CAP_CID_SIGNALING	0x0001
#define L2CAP_CID_CONN_LESS	0x0002
#define L2CAP_CID_DYN_START	0x0040
#define L2CAP_CID_DYN_END	0xffff

/* connect result */
#define L2CAP_CR_SUCCESS	0x0000
#define L2CAP_CR_PEND		0x0001
@@ -143,10 +166,14 @@ struct l2cap_conf_opt {
} __attribute__ ((packed));
#define L2CAP_CONF_OPT_SIZE	2

#define L2CAP_CONF_HINT		0x80
#define L2CAP_CONF_MASK		0x7f

#define L2CAP_CONF_MTU		0x01
#define L2CAP_CONF_FLUSH_TO	0x02
#define L2CAP_CONF_QOS		0x03
#define L2CAP_CONF_RFC		0x04
#define L2CAP_CONF_FCS		0x05

#define L2CAP_CONF_MAX_SIZE	22

@@ -162,6 +189,8 @@ struct l2cap_conf_rfc {
#define L2CAP_MODE_BASIC	0x00
#define L2CAP_MODE_RETRANS	0x01
#define L2CAP_MODE_FLOWCTL	0x02
#define L2CAP_MODE_ERTM		0x03
#define L2CAP_MODE_STREAM	0x04

struct l2cap_disconn_req {
	__le16     dcid;
+40 −1
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@
#include <linux/skbuff.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <linux/rfkill.h>
#include <net/sock.h>

#include <asm/system.h>
@@ -476,6 +477,11 @@ int hci_dev_open(__u16 dev)

	hci_req_lock(hdev);

	if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) {
		ret = -ERFKILL;
		goto done;
	}

	if (test_bit(HCI_UP, &hdev->flags)) {
		ret = -EALREADY;
		goto done;
@@ -813,6 +819,24 @@ int hci_get_dev_info(void __user *arg)

/* ---- Interface to HCI drivers ---- */

static int hci_rfkill_set_block(void *data, bool blocked)
{
	struct hci_dev *hdev = data;

	BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);

	if (!blocked)
		return 0;

	hci_dev_do_close(hdev);

	return 0;
}

static const struct rfkill_ops hci_rfkill_ops = {
	.set_block = hci_rfkill_set_block,
};

/* Alloc HCI device */
struct hci_dev *hci_alloc_dev(void)
{
@@ -844,7 +868,8 @@ int hci_register_dev(struct hci_dev *hdev)
	struct list_head *head = &hci_dev_list, *p;
	int i, id = 0;

	BT_DBG("%p name %s type %d owner %p", hdev, hdev->name, hdev->type, hdev->owner);
	BT_DBG("%p name %s type %d owner %p", hdev, hdev->name,
						hdev->type, hdev->owner);

	if (!hdev->open || !hdev->close || !hdev->destruct)
		return -EINVAL;
@@ -900,6 +925,15 @@ int hci_register_dev(struct hci_dev *hdev)

	hci_register_sysfs(hdev);

	hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
				RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
	if (hdev->rfkill) {
		if (rfkill_register(hdev->rfkill) < 0) {
			rfkill_destroy(hdev->rfkill);
			hdev->rfkill = NULL;
		}
	}

	hci_notify(hdev, HCI_DEV_REG);

	return id;
@@ -924,6 +958,11 @@ int hci_unregister_dev(struct hci_dev *hdev)

	hci_notify(hdev, HCI_DEV_UNREG);

	if (hdev->rfkill) {
		rfkill_unregister(hdev->rfkill);
		rfkill_destroy(hdev->rfkill);
	}

	hci_unregister_sysfs(hdev);

	__hci_dev_put(hdev);
Loading