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

Commit dc0d633e authored by John W. Linville's avatar John W. Linville
Browse files
parents aef6c928 4ae1652e
Loading
Loading
Loading
Loading
+3 −7
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ static struct usb_device_id btusb_table[] = {
	{ USB_DEVICE(0x0c10, 0x0000) },

	/* Broadcom BCM20702A0 */
	{ USB_DEVICE(0x0a5c, 0x21e3) },
	{ USB_DEVICE(0x413c, 0x8197) },

	{ }	/* Terminating entry */
@@ -508,15 +509,10 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)

	pipe = usb_rcvisocpipe(data->udev, data->isoc_rx_ep->bEndpointAddress);

	urb->dev      = data->udev;
	urb->pipe     = pipe;
	urb->context  = hdev;
	urb->complete = btusb_isoc_complete;
	urb->interval = data->isoc_rx_ep->bInterval;
	usb_fill_int_urb(urb, data->udev, pipe, buf, size, btusb_isoc_complete,
				hdev, data->isoc_rx_ep->bInterval);

	urb->transfer_flags  = URB_FREE_BUFFER | URB_ISO_ASAP;
	urb->transfer_buffer = buf;
	urb->transfer_buffer_length = size;

	__fill_isoc_descriptor(urb, size,
			le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize));
+0 −22
Original line number Diff line number Diff line
@@ -250,32 +250,10 @@ extern void bt_sysfs_cleanup(void);

extern struct dentry *bt_debugfs;

#ifdef CONFIG_BT_L2CAP
int l2cap_init(void);
void l2cap_exit(void);
#else
static inline int l2cap_init(void)
{
	return 0;
}

static inline void l2cap_exit(void)
{
}
#endif

#ifdef CONFIG_BT_SCO
int sco_init(void);
void sco_exit(void);
#else
static inline int sco_init(void)
{
	return 0;
}

static inline void sco_exit(void)
{
}
#endif

#endif /* __BLUETOOTH_H */
+13 −1
Original line number Diff line number Diff line
@@ -280,6 +280,10 @@ enum {
#define HCI_ERROR_LOCAL_HOST_TERM	0x16
#define HCI_ERROR_PAIRING_NOT_ALLOWED	0x18

/* Flow control modes */
#define HCI_FLOW_CTL_MODE_PACKET_BASED	0x00
#define HCI_FLOW_CTL_MODE_BLOCK_BASED	0x01

/* -----  HCI Commands ---- */
#define HCI_OP_NOP			0x0000

@@ -800,6 +804,9 @@ struct hci_cp_le_set_scan_param {
	__u8    filter_policy;
} __packed;

#define LE_SCANNING_DISABLED		0x00
#define LE_SCANNING_ENABLED		0x01

#define HCI_OP_LE_SET_SCAN_ENABLE	0x200c
struct hci_cp_le_set_scan_enable {
	__u8     enable;
@@ -975,9 +982,14 @@ struct hci_ev_role_change {
} __packed;

#define HCI_EV_NUM_COMP_PKTS		0x13
struct hci_comp_pkts_info {
	__le16   handle;
	__le16   count;
} __packed;

struct hci_ev_num_comp_pkts {
	__u8     num_hndl;
	/* variable length part */
	struct hci_comp_pkts_info handles[0];
} __packed;

#define HCI_EV_MODE_CHANGE		0x14
+68 −94
Original line number Diff line number Diff line
@@ -28,10 +28,6 @@
#include <linux/interrupt.h>
#include <net/bluetooth/hci.h>

/* HCI upper protocols */
#define HCI_PROTO_L2CAP	0
#define HCI_PROTO_SCO	1

/* HCI priority */
#define HCI_PRIO_MAX	7

@@ -54,7 +50,6 @@ struct inquiry_entry {
};

struct inquiry_cache {
	spinlock_t		lock;
	__u32			timestamp;
	struct inquiry_entry	*list;
};
@@ -314,6 +309,7 @@ struct hci_conn {
	struct hci_dev	*hdev;
	void		*l2cap_data;
	void		*sco_data;
	void		*smp_conn;

	struct hci_conn	*link;

@@ -330,25 +326,31 @@ struct hci_chan {
	unsigned int	sent;
};

extern struct hci_proto *hci_proto[];
extern struct list_head hci_dev_list;
extern struct list_head hci_cb_list;
extern rwlock_t hci_dev_list_lock;
extern rwlock_t hci_cb_list_lock;

/* ----- HCI interface to upper protocols ----- */
extern int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
extern int l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
extern int l2cap_disconn_ind(struct hci_conn *hcon);
extern int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt);
extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags);

extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
extern int sco_connect_cfm(struct hci_conn *hcon, __u8 status);
extern int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason);
extern int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb);

/* ----- Inquiry cache ----- */
#define INQUIRY_CACHE_AGE_MAX   (HZ*30)   /* 30 seconds */
#define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   /* 60 seconds */

#define inquiry_cache_lock(c)		spin_lock(&c->lock)
#define inquiry_cache_unlock(c)		spin_unlock(&c->lock)
#define inquiry_cache_lock_bh(c)	spin_lock_bh(&c->lock)
#define inquiry_cache_unlock_bh(c)	spin_unlock_bh(&c->lock)

static inline void inquiry_cache_init(struct hci_dev *hdev)
{
	struct inquiry_cache *c = &hdev->inq_cache;
	spin_lock_init(&c->lock);
	c->list = NULL;
}

@@ -677,53 +679,40 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_host_le_capable(dev)   ((dev)->extfeatures[0] & LMP_HOST_LE)

/* ----- HCI protocols ----- */
struct hci_proto {
	char		*name;
	unsigned int	id;
	unsigned long	flags;

	void		*priv;

	int (*connect_ind)	(struct hci_dev *hdev, bdaddr_t *bdaddr,
								__u8 type);
	int (*connect_cfm)	(struct hci_conn *conn, __u8 status);
	int (*disconn_ind)	(struct hci_conn *conn);
	int (*disconn_cfm)	(struct hci_conn *conn, __u8 reason);
	int (*recv_acldata)	(struct hci_conn *conn, struct sk_buff *skb,
								__u16 flags);
	int (*recv_scodata)	(struct hci_conn *conn, struct sk_buff *skb);
	int (*security_cfm)	(struct hci_conn *conn, __u8 status,
								__u8 encrypt);
};

static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
								__u8 type)
{
	register struct hci_proto *hp;
	int mask = 0;

	hp = hci_proto[HCI_PROTO_L2CAP];
	if (hp && hp->connect_ind)
		mask |= hp->connect_ind(hdev, bdaddr, type);
	switch (type) {
	case ACL_LINK:
		return l2cap_connect_ind(hdev, bdaddr);

	hp = hci_proto[HCI_PROTO_SCO];
	if (hp && hp->connect_ind)
		mask |= hp->connect_ind(hdev, bdaddr, type);
	case SCO_LINK:
	case ESCO_LINK:
		return sco_connect_ind(hdev, bdaddr);

	return mask;
	default:
		BT_ERR("unknown link type %d", type);
		return -EINVAL;
	}
}

static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
{
	register struct hci_proto *hp;
	switch (conn->type) {
	case ACL_LINK:
	case LE_LINK:
		l2cap_connect_cfm(conn, status);
		break;

	hp = hci_proto[HCI_PROTO_L2CAP];
	if (hp && hp->connect_cfm)
		hp->connect_cfm(conn, status);
	case SCO_LINK:
	case ESCO_LINK:
		sco_connect_cfm(conn, status);
		break;

	hp = hci_proto[HCI_PROTO_SCO];
	if (hp && hp->connect_cfm)
		hp->connect_cfm(conn, status);
	default:
		BT_ERR("unknown link type %d", conn->type);
		break;
	}

	if (conn->connect_cfm_cb)
		conn->connect_cfm_cb(conn, status);
@@ -731,31 +720,29 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)

static inline int hci_proto_disconn_ind(struct hci_conn *conn)
{
	register struct hci_proto *hp;
	int reason = HCI_ERROR_REMOTE_USER_TERM;

	hp = hci_proto[HCI_PROTO_L2CAP];
	if (hp && hp->disconn_ind)
		reason = hp->disconn_ind(conn);

	hp = hci_proto[HCI_PROTO_SCO];
	if (hp && hp->disconn_ind)
		reason = hp->disconn_ind(conn);
	if (conn->type != ACL_LINK && conn->type != LE_LINK)
		return HCI_ERROR_REMOTE_USER_TERM;

	return reason;
	return l2cap_disconn_ind(conn);
}

static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
{
	register struct hci_proto *hp;
	switch (conn->type) {
	case ACL_LINK:
	case LE_LINK:
		l2cap_disconn_cfm(conn, reason);
		break;

	hp = hci_proto[HCI_PROTO_L2CAP];
	if (hp && hp->disconn_cfm)
		hp->disconn_cfm(conn, reason);
	case SCO_LINK:
	case ESCO_LINK:
		sco_disconn_cfm(conn, reason);
		break;

	hp = hci_proto[HCI_PROTO_SCO];
	if (hp && hp->disconn_cfm)
		hp->disconn_cfm(conn, reason);
	default:
		BT_ERR("unknown link type %d", conn->type);
		break;
	}

	if (conn->disconn_cfm_cb)
		conn->disconn_cfm_cb(conn, reason);
@@ -763,21 +750,16 @@ static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)

static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
{
	register struct hci_proto *hp;
	__u8 encrypt;

	if (conn->type != ACL_LINK && conn->type != LE_LINK)
		return;

	if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
		return;

	encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;

	hp = hci_proto[HCI_PROTO_L2CAP];
	if (hp && hp->security_cfm)
		hp->security_cfm(conn, status, encrypt);

	hp = hci_proto[HCI_PROTO_SCO];
	if (hp && hp->security_cfm)
		hp->security_cfm(conn, status, encrypt);
	l2cap_security_cfm(conn, status, encrypt);

	if (conn->security_cfm_cb)
		conn->security_cfm_cb(conn, status);
@@ -786,23 +768,15 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status,
								__u8 encrypt)
{
	register struct hci_proto *hp;

	hp = hci_proto[HCI_PROTO_L2CAP];
	if (hp && hp->security_cfm)
		hp->security_cfm(conn, status, encrypt);
	if (conn->type != ACL_LINK && conn->type != LE_LINK)
		return;

	hp = hci_proto[HCI_PROTO_SCO];
	if (hp && hp->security_cfm)
		hp->security_cfm(conn, status, encrypt);
	l2cap_security_cfm(conn, status, encrypt);

	if (conn->security_cfm_cb)
		conn->security_cfm_cb(conn, status);
}

int hci_register_proto(struct hci_proto *hproto);
int hci_unregister_proto(struct hci_proto *hproto);

/* ----- HCI callbacks ----- */
struct hci_cb {
	struct list_head list;
@@ -827,13 +801,13 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)

	encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;

	read_lock_bh(&hci_cb_list_lock);
	read_lock(&hci_cb_list_lock);
	list_for_each(p, &hci_cb_list) {
		struct hci_cb *cb = list_entry(p, struct hci_cb, list);
		if (cb->security_cfm)
			cb->security_cfm(conn, status, encrypt);
	}
	read_unlock_bh(&hci_cb_list_lock);
	read_unlock(&hci_cb_list_lock);
}

static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
@@ -849,26 +823,26 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,

	hci_proto_encrypt_cfm(conn, status, encrypt);

	read_lock_bh(&hci_cb_list_lock);
	read_lock(&hci_cb_list_lock);
	list_for_each(p, &hci_cb_list) {
		struct hci_cb *cb = list_entry(p, struct hci_cb, list);
		if (cb->security_cfm)
			cb->security_cfm(conn, status, encrypt);
	}
	read_unlock_bh(&hci_cb_list_lock);
	read_unlock(&hci_cb_list_lock);
}

static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)
{
	struct list_head *p;

	read_lock_bh(&hci_cb_list_lock);
	read_lock(&hci_cb_list_lock);
	list_for_each(p, &hci_cb_list) {
		struct hci_cb *cb = list_entry(p, struct hci_cb, list);
		if (cb->key_change_cfm)
			cb->key_change_cfm(conn, status);
	}
	read_unlock_bh(&hci_cb_list_lock);
	read_unlock(&hci_cb_list_lock);
}

static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
@@ -876,13 +850,13 @@ static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
{
	struct list_head *p;

	read_lock_bh(&hci_cb_list_lock);
	read_lock(&hci_cb_list_lock);
	list_for_each(p, &hci_cb_list) {
		struct hci_cb *cb = list_entry(p, struct hci_cb, list);
		if (cb->role_switch_cfm)
			cb->role_switch_cfm(conn, status, role);
	}
	read_unlock_bh(&hci_cb_list_lock);
	read_unlock(&hci_cb_list_lock);
}

int hci_register_cb(struct hci_cb *hcb);
+34 −6
Original line number Diff line number Diff line
@@ -522,7 +522,7 @@ struct l2cap_conn {
	__u8		info_state;
	__u8		info_ident;

	struct delayed_work info_work;
	struct delayed_work info_timer;

	spinlock_t	lock;

@@ -532,7 +532,7 @@ struct l2cap_conn {

	__u8		disc_reason;

	struct timer_list security_timer;
	struct delayed_work  security_timer;
	struct smp_chan *smp_chan;

	struct list_head chan_l;
@@ -595,17 +595,45 @@ enum {
	FLAG_EFS_ENABLE,
};

static inline void l2cap_chan_hold(struct l2cap_chan *c)
{
	atomic_inc(&c->refcnt);
}

static inline void l2cap_chan_put(struct l2cap_chan *c)
{
	if (atomic_dec_and_test(&c->refcnt))
		kfree(c);
}

static inline void l2cap_set_timer(struct l2cap_chan *chan,
					struct delayed_work *work, long timeout)
{
	BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);

	if (!__cancel_delayed_work(work))
		l2cap_chan_hold(chan);
	schedule_delayed_work(work, timeout);
}

static inline void l2cap_clear_timer(struct l2cap_chan *chan,
					struct delayed_work *work)
{
	if (__cancel_delayed_work(work))
		l2cap_chan_put(chan);
}

#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
#define __clear_chan_timer(c) l2cap_clear_timer(&c->chan_timer)
#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
		L2CAP_DEFAULT_RETRANS_TO);
#define __clear_retrans_timer(c) l2cap_clear_timer(&c->retrans_timer)
#define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer)
#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
		L2CAP_DEFAULT_MONITOR_TO);
#define __clear_monitor_timer(c) l2cap_clear_timer(&c->monitor_timer)
#define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer)
#define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
		L2CAP_DEFAULT_ACK_TO);
#define __clear_ack_timer(c) l2cap_clear_timer(&c->ack_timer)
#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)

static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2)
{
Loading