Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
2dbbab6f
Commit
2dbbab6f
authored
Mar 23, 2003
by
Maksim Krasnyanskiy
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[Bluetooth] HCI USB driver update. Support for SCO over HCI USB.
URB and buffer managment rewrite.
parent
0d8865bd
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
572 additions
and
357 deletions
+572
-357
drivers/bluetooth/Kconfig
drivers/bluetooth/Kconfig
+8
-1
drivers/bluetooth/hci_usb.c
drivers/bluetooth/hci_usb.c
+486
-335
drivers/bluetooth/hci_usb.h
drivers/bluetooth/hci_usb.h
+78
-21
No files found.
drivers/bluetooth/Kconfig
View file @
2dbbab6f
...
...
@@ -13,11 +13,18 @@ config BT_HCIUSB
Say Y here to compile support for Bluetooth USB devices into the
kernel or say M to compile it as module (hci_usb).
config BT_USB_SCO
bool "SCO over HCI USB support"
depends on BT_HCIUSB
help
This option enables the SCO support in the HCI USB driver. You need this
to transmit voice data with your Bluetooth USB device.
Say Y here to compile support for SCO over HCI USB.
config BT_USB_ZERO_PACKET
bool "USB zero packet support"
depends on BT_HCIUSB
help
Support for USB zero packets.
This option is provided only as a work around for buggy Bluetooth USB
devices. Do _not_ enable it unless you know for sure that your device
requires zero packets.
...
...
drivers/bluetooth/hci_usb.c
View file @
2dbbab6f
/*
BlueZ - Bluetooth protocol stack for Linux
HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
Copyright (C) 2000-2001 Qualcomm Incorporated
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
...
...
@@ -23,20 +24,17 @@
*/
/*
* Bluetooth HCI USB driver.
* Based on original USB Bluetooth driver for Linux kernel
* Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu>
*
* $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $
*/
#define VERSION "2.
1
"
#define VERSION "2.
4
"
#include <linux/config.h>
#include <linux/module.h>
#define __KERNEL_SYSCALLS__
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/init.h>
...
...
@@ -49,17 +47,15 @@
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/kmod.h>
#include <linux/usb.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include "hci_usb.h"
#
define HCI_MAX_PENDING (HCI_MAX_BULK_RX + HCI_MAX_BULK_TX + 1)
#
include "hci_usb.h"
#ifndef
CONFIG_BT_HCI
USB_DEBUG
#ifndef
HCI_
USB_DEBUG
#undef BT_DBG
#define BT_DBG( A... )
#undef BT_DMP
...
...
@@ -67,8 +63,8 @@
#endif
#ifndef CONFIG_BT_USB_ZERO_PACKET
#undef U
R
B_ZERO_PACKET
#define U
R
B_ZERO_PACKET 0
#undef U
S
B_ZERO_PACKET
#define U
S
B_ZERO_PACKET 0
#endif
static
struct
usb_driver
hci_usb_driver
;
...
...
@@ -80,6 +76,9 @@ static struct usb_device_id bluetooth_ids[] = {
/* Ericsson with non-standard id */
{
USB_DEVICE
(
0x0bdb
,
0x1002
)
},
/* Bluetooth Ultraport Module from IBM */
{
USB_DEVICE
(
0x04bf
,
0x030a
)
},
{
}
/* Terminating entry */
};
...
...
@@ -92,108 +91,196 @@ static struct usb_device_id ignore_ids[] = {
{
}
/* Terminating entry */
};
static
void
hci_usb_interrupt
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
);
struct
_urb
*
_urb_alloc
(
int
isoc
,
int
gfp
)
{
struct
_urb
*
_urb
=
kmalloc
(
sizeof
(
struct
_urb
)
+
sizeof
(
struct
usb_iso_packet_descriptor
)
*
isoc
,
gfp
);
if
(
_urb
)
{
memset
(
_urb
,
0
,
sizeof
(
*
_urb
));
_urb
->
urb
.
count
=
(
atomic_t
)
ATOMIC_INIT
(
1
);
spin_lock_init
(
&
_urb
->
urb
.
lock
);
}
return
_urb
;
}
struct
_urb
*
_urb_dequeue
(
struct
_urb_queue
*
q
)
{
struct
_urb
*
_urb
=
NULL
;
unsigned
long
flags
;
spin_lock_irqsave
(
&
q
->
lock
,
flags
);
{
struct
list_head
*
head
=
&
q
->
head
;
struct
list_head
*
next
=
head
->
next
;
if
(
next
!=
head
)
{
_urb
=
list_entry
(
next
,
struct
_urb
,
list
);
list_del
(
next
);
_urb
->
queue
=
NULL
;
}
}
spin_unlock_irqrestore
(
&
q
->
lock
,
flags
);
return
_urb
;
}
static
void
hci_usb_rx_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
);
static
void
hci_usb_tx_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
);
static
struct
urb
*
hci_usb_get_completed
(
struct
hci_usb
*
husb
)
#define __pending_tx(husb, type) (&husb->pending_tx[type-1])
#define __pending_q(husb, type) (&husb->pending_q[type-1])
#define __completed_q(husb, type) (&husb->completed_q[type-1])
#define __transmit_q(husb, type) (&husb->transmit_q[type-1])
#define __reassembly(husb, type) (husb->reassembly[type-1])
static
inline
struct
_urb
*
__get_completed
(
struct
hci_usb
*
husb
,
int
type
)
{
struct
sk_buff
*
skb
;
struct
urb
*
urb
=
NULL
;
return
_urb_dequeue
(
__completed_q
(
husb
,
type
));
}
skb
=
skb_dequeue
(
&
husb
->
completed_q
);
if
(
skb
)
{
urb
=
((
struct
hci_usb_scb
*
)
skb
->
cb
)
->
urb
;
kfree_skb
(
skb
);
}
#ifdef CONFIG_BT_USB_SCO
static
void
__fill_isoc_desc
(
struct
urb
*
urb
,
int
len
,
int
mtu
)
{
int
offset
=
0
,
i
;
BT_DBG
(
"%s urb %p"
,
husb
->
hdev
.
name
,
urb
);
return
urb
;
BT_DBG
(
"len %d mtu %d"
,
len
,
mtu
);
for
(
i
=
0
;
i
<
HCI_MAX_ISOC_FRAMES
&&
len
>=
mtu
;
i
++
,
offset
+=
mtu
,
len
-=
mtu
)
{
urb
->
iso_frame_desc
[
i
].
offset
=
offset
;
urb
->
iso_frame_desc
[
i
].
length
=
mtu
;
BT_DBG
(
"desc %d offset %d len %d"
,
i
,
offset
,
mtu
);
}
if
(
len
&&
i
<
HCI_MAX_ISOC_FRAMES
)
{
urb
->
iso_frame_desc
[
i
].
offset
=
offset
;
urb
->
iso_frame_desc
[
i
].
length
=
len
;
BT_DBG
(
"desc %d offset %d len %d"
,
i
,
offset
,
len
);
i
++
;
}
urb
->
number_of_packets
=
i
;
}
#endif
static
int
hci_usb_
enable_intr
(
struct
hci_usb
*
husb
)
static
int
hci_usb_
intr_rx_submit
(
struct
hci_usb
*
husb
)
{
struct
_urb
*
_urb
;
struct
urb
*
urb
;
int
pipe
,
size
;
int
err
,
pipe
,
interval
,
size
;
void
*
buf
;
BT_DBG
(
"%s"
,
husb
->
hdev
.
name
);
if
(
!
(
urb
=
usb_alloc_urb
(
0
,
GFP_KERNEL
)))
size
=
husb
->
intr_in_ep
->
desc
.
wMaxPacketSize
;
buf
=
kmalloc
(
size
,
GFP_ATOMIC
);
if
(
!
buf
)
return
-
ENOMEM
;
if
(
!
(
buf
=
kmalloc
(
HCI_MAX_EVENT_SIZE
,
GFP_KERNEL
)))
{
usb_free_urb
(
urb
);
_urb
=
_urb_alloc
(
0
,
GFP_ATOMIC
);
if
(
!
_urb
)
{
kfree
(
buf
);
return
-
ENOMEM
;
}
_urb
->
type
=
HCI_EVENT_PKT
;
_urb_queue_tail
(
__pending_q
(
husb
,
_urb
->
type
),
_urb
);
husb
->
intr_urb
=
urb
;
pipe
=
usb_rcvintpipe
(
husb
->
udev
,
husb
->
intr_ep
);
size
=
usb_maxpacket
(
husb
->
udev
,
pipe
,
usb_pipeout
(
pipe
));
usb_fill_int_urb
(
urb
,
husb
->
udev
,
pipe
,
buf
,
size
,
hci_usb_interrupt
,
husb
,
husb
->
intr_interval
);
urb
=
&
_urb
->
urb
;
pipe
=
usb_rcvintpipe
(
husb
->
udev
,
husb
->
intr_in_ep
->
desc
.
bEndpointAddress
);
interval
=
husb
->
intr_in_ep
->
desc
.
bInterval
;
usb_fill_int_urb
(
urb
,
husb
->
udev
,
pipe
,
buf
,
size
,
hci_usb_rx_complete
,
husb
,
interval
);
return
usb_submit_urb
(
urb
,
GFP_KERNEL
);
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
err
)
{
BT_ERR
(
"%s intr rx submit failed urb %p err %d"
,
husb
->
hdev
.
name
,
urb
,
err
);
_urb_unlink
(
_urb
);
_urb_free
(
_urb
);
kfree
(
buf
);
}
return
err
;
}
static
int
hci_usb_
disable_intr
(
struct
hci_usb
*
husb
)
static
int
hci_usb_
bulk_rx_submit
(
struct
hci_usb
*
husb
)
{
struct
urb
*
urb
=
husb
->
intr
_urb
;
struct
sk_buff
*
sk
b
;
BT_DBG
(
"%s"
,
husb
->
hdev
.
name
)
;
struct
_urb
*
_urb
;
struct
urb
*
ur
b
;
int
err
,
pipe
,
size
=
HCI_MAX_FRAME_SIZE
;
void
*
buf
;
usb_unlink_urb
(
urb
);
usb_free_urb
(
urb
);
husb
->
intr_urb
=
NULL
;
buf
=
kmalloc
(
size
,
GFP_ATOMIC
);
if
(
!
buf
)
return
-
ENOMEM
;
skb
=
husb
->
intr_skb
;
if
(
sk
b
)
{
husb
->
intr_skb
=
NULL
;
kfree_skb
(
skb
)
;
_urb
=
_urb_alloc
(
0
,
GFP_ATOMIC
)
;
if
(
!
_ur
b
)
{
kfree
(
buf
)
;
return
-
ENOMEM
;
}
_urb
->
type
=
HCI_ACLDATA_PKT
;
_urb_queue_tail
(
__pending_q
(
husb
,
_urb
->
type
),
_urb
);
return
0
;
urb
=
&
_urb
->
urb
;
pipe
=
usb_rcvbulkpipe
(
husb
->
udev
,
husb
->
bulk_in_ep
->
desc
.
bEndpointAddress
);
usb_fill_bulk_urb
(
urb
,
husb
->
udev
,
pipe
,
buf
,
size
,
hci_usb_rx_complete
,
husb
);
urb
->
transfer_flags
=
0
;
BT_DBG
(
"%s urb %p"
,
husb
->
hdev
.
name
,
urb
);
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
err
)
{
BT_ERR
(
"%s bulk rx submit failed urb %p err %d"
,
husb
->
hdev
.
name
,
urb
,
err
);
_urb_unlink
(
_urb
);
_urb_free
(
_urb
);
kfree
(
buf
);
}
return
err
;
}
static
int
hci_usb_rx_submit
(
struct
hci_usb
*
husb
,
struct
urb
*
urb
)
#ifdef CONFIG_BT_USB_SCO
static
int
hci_usb_isoc_rx_submit
(
struct
hci_usb
*
husb
)
{
struct
hci_usb_scb
*
scb
;
struct
sk_buff
*
skb
;
int
pipe
,
size
,
err
;
struct
_urb
*
_urb
;
struct
urb
*
urb
;
int
err
,
mtu
,
size
;
void
*
buf
;
if
(
!
urb
&&
!
(
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
)))
return
-
ENOMEM
;
mtu
=
husb
->
isoc_in_ep
->
desc
.
wMaxPacketSize
;
size
=
mtu
*
HCI_MAX_ISOC_FRAMES
;
size
=
HCI_MAX_FRAME_SIZE
;
buf
=
kmalloc
(
size
,
GFP_ATOMIC
);
if
(
!
buf
)
return
-
ENOMEM
;
if
(
!
(
skb
=
bt_skb_alloc
(
size
,
GFP_ATOMIC
)))
{
usb_free_urb
(
urb
);
_urb
=
_urb_alloc
(
HCI_MAX_ISOC_FRAMES
,
GFP_ATOMIC
);
if
(
!
_urb
)
{
kfree
(
buf
);
return
-
ENOMEM
;
}
BT_DBG
(
"%s urb %p"
,
husb
->
hdev
.
name
,
urb
);
_urb
->
type
=
HCI_SCODATA_PKT
;
_urb_queue_tail
(
__pending_q
(
husb
,
_urb
->
type
),
_
urb
);
skb
->
dev
=
(
void
*
)
&
husb
->
hdev
;
skb
->
pkt_type
=
HCI_ACLDATA_PKT
;
urb
=
&
_urb
->
urb
;
scb
=
(
struct
hci_usb_scb
*
)
skb
->
cb
;
scb
->
urb
=
urb
;
urb
->
context
=
husb
;
urb
->
dev
=
husb
->
udev
;
urb
->
pipe
=
usb_rcvisocpipe
(
husb
->
udev
,
husb
->
isoc_in_ep
->
desc
.
bEndpointAddress
);
urb
->
complete
=
hci_usb_rx_complete
;
pipe
=
usb_rcvbulkpipe
(
husb
->
udev
,
husb
->
bulk_in_ep
);
urb
->
transfer_buffer_length
=
size
;
urb
->
transfer_buffer
=
buf
;
urb
->
transfer_flags
=
URB_ISO_ASAP
;
usb_fill_bulk_urb
(
urb
,
husb
->
udev
,
pipe
,
skb
->
data
,
size
,
hci_usb_rx_complete
,
skb
);
__fill_isoc_desc
(
urb
,
size
,
mtu
);
BT_DBG
(
"%s urb %p"
,
husb
->
hdev
.
name
,
urb
);
skb_queue_tail
(
&
husb
->
pending_q
,
skb
);
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
err
)
{
BT_ERR
(
"%s
bulk
rx submit failed urb %p err %d"
,
BT_ERR
(
"%s
isoc
rx submit failed urb %p err %d"
,
husb
->
hdev
.
name
,
urb
,
err
);
skb_unlink
(
skb
);
usb_free_urb
(
urb
);
_urb_unlink
(
_urb
);
_urb_free
(
_urb
);
kfree
(
buf
);
}
return
err
;
}
#endif
/* Initialize device */
static
int
hci_usb_open
(
struct
hci_dev
*
hdev
)
...
...
@@ -209,13 +296,17 @@ static int hci_usb_open(struct hci_dev *hdev)
write_lock_irqsave
(
&
husb
->
completion_lock
,
flags
);
err
=
hci_usb_
enable_intr
(
husb
);
err
=
hci_usb_
intr_rx_submit
(
husb
);
if
(
!
err
)
{
for
(
i
=
0
;
i
<
HCI_MAX_BULK_RX
;
i
++
)
hci_usb_rx_submit
(
husb
,
NULL
);
}
else
hci_usb_bulk_rx_submit
(
husb
);
#ifdef CONFIG_BT_USB_SCO
hci_usb_isoc_rx_submit
(
husb
);
#endif
}
else
{
clear_bit
(
HCI_RUNNING
,
&
hdev
->
flags
);
}
write_unlock_irqrestore
(
&
husb
->
completion_lock
,
flags
);
return
err
;
...
...
@@ -225,29 +316,52 @@ static int hci_usb_open(struct hci_dev *hdev)
static
int
hci_usb_flush
(
struct
hci_dev
*
hdev
)
{
struct
hci_usb
*
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
int
i
;
BT_DBG
(
"%s"
,
hdev
->
name
);
skb_queue_purge
(
&
husb
->
cmd_q
);
skb_queue_purge
(
&
husb
->
acl_q
);
for
(
i
=
0
;
i
<
4
;
i
++
)
skb_queue_purge
(
&
husb
->
transmit_q
[
i
]
);
return
0
;
}
static
inline
void
hci_usb_unlink_urbs
(
struct
hci_usb
*
husb
)
static
void
hci_usb_unlink_urbs
(
struct
hci_usb
*
husb
)
{
struct
sk_buff
*
skb
;
struct
urb
*
urb
;
int
i
;
BT_DBG
(
"%s"
,
husb
->
hdev
.
name
);
while
((
skb
=
skb_dequeue
(
&
husb
->
pending_q
)))
{
urb
=
((
struct
hci_usb_scb
*
)
skb
->
cb
)
->
urb
;
usb_unlink_urb
(
urb
);
kfree_skb
(
skb
);
}
for
(
i
=
0
;
i
<
4
;
i
++
)
{
struct
_urb
*
_urb
;
struct
urb
*
urb
;
/* Kill pending requests */
while
((
_urb
=
_urb_dequeue
(
&
husb
->
pending_q
[
i
])))
{
urb
=
&
_urb
->
urb
;
BT_DBG
(
"%s unlinking _urb %p type %d urb %p"
,
husb
->
hdev
.
name
,
_urb
,
_urb
->
type
,
urb
);
usb_unlink_urb
(
urb
);
_urb_queue_tail
(
__completed_q
(
husb
,
_urb
->
type
),
_urb
);
}
while
((
urb
=
hci_usb_get_completed
(
husb
)))
usb_free_urb
(
urb
);
/* Release completed requests */
while
((
_urb
=
_urb_dequeue
(
&
husb
->
completed_q
[
i
])))
{
urb
=
&
_urb
->
urb
;
BT_DBG
(
"%s freeing _urb %p type %d urb %p"
,
husb
->
hdev
.
name
,
_urb
,
_urb
->
type
,
urb
);
if
(
urb
->
setup_packet
)
kfree
(
urb
->
setup_packet
);
if
(
urb
->
transfer_buffer
)
kfree
(
urb
->
transfer_buffer
);
_urb_free
(
_urb
);
}
/* Release reassembly buffers */
if
(
husb
->
reassembly
[
i
])
{
kfree_skb
(
husb
->
reassembly
[
i
]);
husb
->
reassembly
[
i
]
=
NULL
;
}
}
}
/* Close device */
...
...
@@ -263,7 +377,6 @@ static int hci_usb_close(struct hci_dev *hdev)
write_lock_irqsave
(
&
husb
->
completion_lock
,
flags
);
hci_usb_disable_intr
(
husb
);
hci_usb_unlink_urbs
(
husb
);
hci_usb_flush
(
hdev
);
...
...
@@ -271,104 +384,157 @@ static int hci_usb_close(struct hci_dev *hdev)
return
0
;
}
static
in
line
int
hci_usb_send_ctrl
(
struct
hci_usb
*
husb
,
struct
sk_buff
*
sk
b
)
static
in
t
__tx_submit
(
struct
hci_usb
*
husb
,
struct
_urb
*
_ur
b
)
{
struct
hci_usb_scb
*
scb
=
(
void
*
)
skb
->
cb
;
struct
urb
*
urb
=
hci_usb_get_completed
(
husb
);
struct
usb_ctrlrequest
*
cr
;
int
pipe
,
err
;
if
(
!
urb
&&
!
(
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
)))
return
-
ENOMEM
;
struct
urb
*
urb
=
&
_urb
->
urb
;
int
err
;
if
(
!
(
cr
=
kmalloc
(
sizeof
(
*
cr
),
GFP_ATOMIC
)))
{
usb_free_urb
(
urb
);
return
-
ENOMEM
;
}
BT_DBG
(
"%s urb %p type %d"
,
husb
->
hdev
.
name
,
urb
,
_urb
->
type
);
pipe
=
usb_sndctrlpipe
(
husb
->
udev
,
0
);
_urb_queue_tail
(
__pending_q
(
husb
,
_urb
->
type
),
_urb
);
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
err
)
{
BT_ERR
(
"%s tx submit failed urb %p type %d err %d"
,
husb
->
hdev
.
name
,
urb
,
_urb
->
type
,
err
);
_urb_unlink
(
_urb
);
_urb_queue_tail
(
__completed_q
(
husb
,
_urb
->
type
),
_urb
);
}
else
atomic_inc
(
__pending_tx
(
husb
,
_urb
->
type
));
cr
->
bRequestType
=
HCI_CTRL_REQ
;
cr
->
bRequest
=
0
;
cr
->
wIndex
=
0
;
cr
->
wValue
=
0
;
cr
->
wLength
=
__cpu_to_le16
(
skb
->
len
);
return
err
;
}
usb_fill_control_urb
(
urb
,
husb
->
udev
,
pipe
,
(
void
*
)
cr
,
skb
->
data
,
skb
->
len
,
hci_usb_tx_complete
,
skb
);
static
inline
int
hci_usb_send_ctrl
(
struct
hci_usb
*
husb
,
struct
sk_buff
*
skb
)
{
struct
_urb
*
_urb
=
__get_completed
(
husb
,
skb
->
pkt_type
);
struct
usb_ctrlrequest
*
dr
;
struct
urb
*
urb
;
BT_DBG
(
"%s urb %p len %d"
,
husb
->
hdev
.
name
,
urb
,
skb
->
len
);
if
(
!
_urb
)
{
_urb
=
_urb_alloc
(
0
,
GFP_ATOMIC
);
if
(
!
_urb
)
return
-
ENOMEM
;
_urb
->
type
=
skb
->
pkt_type
;
scb
->
urb
=
urb
;
dr
=
kmalloc
(
sizeof
(
*
dr
),
GFP_ATOMIC
);
if
(
!
dr
)
{
_urb_free
(
_urb
);
return
-
ENOMEM
;
}
}
else
dr
=
(
void
*
)
_urb
->
urb
.
setup_packet
;
skb_queue_tail
(
&
husb
->
pending_q
,
skb
);
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
err
)
{
BT_ERR
(
"%s ctrl tx submit failed urb %p err %d"
,
husb
->
hdev
.
name
,
urb
,
err
);
skb_unlink
(
skb
);
usb_free_urb
(
urb
);
kfree
(
cr
);
}
return
err
;
dr
->
bRequestType
=
HCI_CTRL_REQ
;
dr
->
bRequest
=
0
;
dr
->
wIndex
=
0
;
dr
->
wValue
=
0
;
dr
->
wLength
=
__cpu_to_le16
(
skb
->
len
);
urb
=
&
_urb
->
urb
;
usb_fill_control_urb
(
urb
,
husb
->
udev
,
usb_sndctrlpipe
(
husb
->
udev
,
0
),
(
void
*
)
dr
,
skb
->
data
,
skb
->
len
,
hci_usb_tx_complete
,
husb
);
BT_DBG
(
"%s skb %p len %d"
,
husb
->
hdev
.
name
,
skb
,
skb
->
len
);
_urb
->
priv
=
skb
;
return
__tx_submit
(
husb
,
_urb
);
}
static
inline
int
hci_usb_send_bulk
(
struct
hci_usb
*
husb
,
struct
sk_buff
*
skb
)
{
struct
hci_usb_scb
*
scb
=
(
void
*
)
skb
->
cb
;
struct
urb
*
urb
=
hci_usb_get_completed
(
husb
)
;
int
pipe
,
err
;
struct
_urb
*
_urb
=
__get_completed
(
husb
,
skb
->
pkt_type
)
;
struct
urb
*
urb
;
int
pipe
;
if
(
!
urb
&&
!
(
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
)))
return
-
ENOMEM
;
if
(
!
_urb
)
{
_urb
=
_urb_alloc
(
0
,
GFP_ATOMIC
);
if
(
!
_urb
)
return
-
ENOMEM
;
_urb
->
type
=
skb
->
pkt_type
;
}
pipe
=
usb_sndbulkpipe
(
husb
->
udev
,
husb
->
bulk_out_ep
)
;
usb_fill_bulk_urb
(
urb
,
husb
->
udev
,
pipe
,
skb
->
data
,
skb
->
len
,
hci_usb_tx_complete
,
sk
b
);
urb
->
transfer_flags
=
U
R
B_ZERO_PACKET
;
urb
=
&
_urb
->
urb
;
pipe
=
usb_sndbulkpipe
(
husb
->
udev
,
husb
->
bulk_out_ep
->
desc
.
bEndpointAddress
);
usb_fill_bulk_urb
(
urb
,
husb
->
udev
,
pipe
,
skb
->
data
,
skb
->
len
,
hci_usb_tx_complete
,
hus
b
);
urb
->
transfer_flags
=
U
S
B_ZERO_PACKET
;
BT_DBG
(
"%s
urb %p len %d"
,
husb
->
hdev
.
name
,
ur
b
,
skb
->
len
);
BT_DBG
(
"%s
skb %p len %d"
,
husb
->
hdev
.
name
,
sk
b
,
skb
->
len
);
scb
->
urb
=
urb
;
_urb
->
priv
=
skb
;
return
__tx_submit
(
husb
,
_urb
);
}
skb_queue_tail
(
&
husb
->
pending_q
,
skb
);
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
err
)
{
BT_ERR
(
"%s bulk tx submit failed urb %p err %d"
,
husb
->
hdev
.
name
,
urb
,
err
);
skb_unlink
(
skb
);
usb_free_urb
(
urb
);
#ifdef CONFIG_BT_USB_SCO
static
inline
int
hci_usb_send_isoc
(
struct
hci_usb
*
husb
,
struct
sk_buff
*
skb
)
{
struct
_urb
*
_urb
=
__get_completed
(
husb
,
skb
->
pkt_type
);
struct
urb
*
urb
;
if
(
!
_urb
)
{
_urb
=
_urb_alloc
(
HCI_MAX_ISOC_FRAMES
,
GFP_ATOMIC
);
if
(
!
_urb
)
return
-
ENOMEM
;
_urb
->
type
=
skb
->
pkt_type
;
}
return
err
;
BT_DBG
(
"%s skb %p len %d"
,
husb
->
hdev
.
name
,
skb
,
skb
->
len
);
urb
=
&
_urb
->
urb
;
urb
->
context
=
husb
;
urb
->
dev
=
husb
->
udev
;
urb
->
pipe
=
usb_sndisocpipe
(
husb
->
udev
,
husb
->
isoc_out_ep
->
desc
.
bEndpointAddress
);
urb
->
complete
=
hci_usb_tx_complete
;
urb
->
transfer_flags
=
URB_ISO_ASAP
;
urb
->
transfer_buffer
=
skb
->
data
;
urb
->
transfer_buffer_length
=
skb
->
len
;
__fill_isoc_desc
(
urb
,
skb
->
len
,
husb
->
isoc_out_ep
->
desc
.
wMaxPacketSize
);
_urb
->
priv
=
skb
;
return
__tx_submit
(
husb
,
_urb
);
}
#endif
static
void
hci_usb_tx_process
(
struct
hci_usb
*
husb
)
{
struct
sk_buff_head
*
q
;
struct
sk_buff
*
skb
;
BT_DBG
(
"%s"
,
husb
->
hdev
.
name
);
do
{
clear_bit
(
HCI_USB_TX_WAKEUP
,
&
husb
->
state
);
/* Process command queue */
q
=
__transmit_q
(
husb
,
HCI_COMMAND_PKT
);
if
(
!
atomic_read
(
__pending_tx
(
husb
,
HCI_COMMAND_PKT
))
&&
(
skb
=
skb_dequeue
(
q
)))
{
if
(
hci_usb_send_ctrl
(
husb
,
skb
)
<
0
)
skb_queue_head
(
q
,
skb
);
}
#ifdef CONFIG_BT_USB_SCO
/* Process SCO queue */
q
=
__transmit_q
(
husb
,
HCI_SCODATA_PKT
);
if
(
!
atomic_read
(
__pending_tx
(
husb
,
HCI_SCODATA_PKT
))
&&
(
skb
=
skb_dequeue
(
q
)))
{
if
(
hci_usb_send_isoc
(
husb
,
skb
)
<
0
)
skb_queue_head
(
q
,
skb
);
}
#endif
/* Process ACL queue */
while
(
skb_queue_len
(
&
husb
->
pending_q
)
<
HCI_MAX_PENDING
&&
(
skb
=
skb_dequeue
(
&
husb
->
acl_q
)))
{
q
=
__transmit_q
(
husb
,
HCI_ACLDATA_PKT
);
while
(
atomic_read
(
__pending_tx
(
husb
,
HCI_ACLDATA_PKT
))
<
HCI_MAX_BULK_TX
&&
(
skb
=
skb_dequeue
(
q
)))
{
if
(
hci_usb_send_bulk
(
husb
,
skb
)
<
0
)
{
skb_queue_head
(
&
husb
->
acl_
q
,
skb
);
skb_queue_head
(
q
,
skb
);
break
;
}
}
/* Process command queue */
if
(
!
test_bit
(
HCI_USB_CTRL_TX
,
&
husb
->
state
)
&&
(
skb
=
skb_dequeue
(
&
husb
->
cmd_q
))
!=
NULL
)
{
set_bit
(
HCI_USB_CTRL_TX
,
&
husb
->
state
);
if
(
hci_usb_send_ctrl
(
husb
,
skb
)
<
0
)
{
skb_queue_head
(
&
husb
->
cmd_q
,
skb
);
clear_bit
(
HCI_USB_CTRL_TX
,
&
husb
->
state
);
}
}
}
while
(
test_bit
(
HCI_USB_TX_WAKEUP
,
&
husb
->
state
));
}
...
...
@@ -383,7 +549,7 @@ static inline void hci_usb_tx_wakeup(struct hci_usb *husb)
}
/* Send frames from HCI layer */
int
hci_usb_send_frame
(
struct
sk_buff
*
skb
)
static
int
hci_usb_send_frame
(
struct
sk_buff
*
skb
)
{
struct
hci_dev
*
hdev
=
(
struct
hci_dev
*
)
skb
->
dev
;
struct
hci_usb
*
husb
;
...
...
@@ -396,247 +562,227 @@ int hci_usb_send_frame(struct sk_buff *skb)
if
(
!
test_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
return
-
EBUSY
;
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
BT_DBG
(
"%s type %d len %d"
,
hdev
->
name
,
skb
->
pkt_type
,
skb
->
len
);
read_lock
(
&
husb
->
completion_lock
)
;
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
switch
(
skb
->
pkt_type
)
{
case
HCI_COMMAND_PKT
:
skb_queue_tail
(
&
husb
->
cmd_q
,
skb
);
hdev
->
stat
.
cmd_tx
++
;
break
;
case
HCI_ACLDATA_PKT
:
skb_queue_tail
(
&
husb
->
acl_q
,
skb
);
hdev
->
stat
.
acl_tx
++
;
break
;
#ifdef CONFIG_BT_USB_SCO
case
HCI_SCODATA_PKT
:
hdev
->
stat
.
sco_tx
++
;
break
;
#endif
default:
kfree_skb
(
skb
);
break
;
return
0
;
}
read_lock
(
&
husb
->
completion_lock
);
skb_queue_tail
(
__transmit_q
(
husb
,
skb
->
pkt_type
),
skb
);
hci_usb_tx_wakeup
(
husb
);
read_unlock
(
&
husb
->
completion_lock
);
return
0
;
}
static
void
hci_usb_interrupt
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
static
inline
int
__recv_frame
(
struct
hci_usb
*
husb
,
int
type
,
void
*
data
,
int
count
)
{
struct
hci_usb
*
husb
=
(
void
*
)
urb
->
context
;
struct
hci_usb_scb
*
scb
;
struct
sk_buff
*
skb
;
struct
hci_event_hdr
*
eh
;
__u8
*
data
=
urb
->
transfer_buffer
;
int
count
=
urb
->
actual_length
;
int
len
=
HCI_EVENT_HDR_SIZE
;
int
status
;
BT_DBG
(
"%s type %d data %p count %d"
,
husb
->
hdev
.
name
,
type
,
data
,
count
);
BT_DBG
(
"%s urb %p count %d"
,
husb
->
hdev
.
name
,
urb
,
count
)
;
husb
->
hdev
.
stat
.
byte_rx
+=
count
;
if
(
!
test_bit
(
HCI_RUNNING
,
&
husb
->
hdev
.
flags
))
return
;
while
(
count
)
{
struct
sk_buff
*
skb
=
__reassembly
(
husb
,
type
);
struct
{
int
expect
;
}
*
scb
;
int
len
=
0
;
if
(
!
skb
)
{
/* Start of the frame */
switch
(
type
)
{
case
HCI_EVENT_PKT
:
if
(
count
>=
HCI_EVENT_HDR_SIZE
)
{
struct
hci_event_hdr
*
h
=
data
;
len
=
HCI_EVENT_HDR_SIZE
+
h
->
plen
;
}
else
return
-
EILSEQ
;
break
;
switch
(
urb
->
status
)
{
case
0
:
/* success */
break
;
case
-
ECONNRESET
:
case
-
ENOENT
:
case
-
ESHUTDOWN
:
/* this urb is terminated, clean up */
BT_DBG
(
"%s urb shutting down with status: %d"
,
husb
->
hdev
.
name
,
urb
->
status
);
return
;
default:
BT_ERR
(
"%s nonzero urb status received: %d"
,
husb
->
hdev
.
name
,
urb
->
status
);
goto
exit
;
}
case
HCI_ACLDATA_PKT
:
if
(
count
>=
HCI_ACL_HDR_SIZE
)
{
struct
hci_acl_hdr
*
h
=
data
;
len
=
HCI_ACL_HDR_SIZE
+
__le16_to_cpu
(
h
->
dlen
);
}
else
return
-
EILSEQ
;
break
;
#ifdef CONFIG_BT_USB_SCO
case
HCI_SCODATA_PKT
:
if
(
count
>=
HCI_SCO_HDR_SIZE
)
{
struct
hci_sco_hdr
*
h
=
data
;
len
=
HCI_SCO_HDR_SIZE
+
h
->
dlen
;
}
else
return
-
EILSEQ
;
break
;
#endif
}
BT_DBG
(
"new packet len %d"
,
len
);
skb
=
bt_skb_alloc
(
len
,
GFP_ATOMIC
);
if
(
!
skb
)
{
BT_ERR
(
"%s no memory for the packet"
,
husb
->
hdev
.
name
);
return
-
ENOMEM
;
}
skb
->
dev
=
(
void
*
)
&
husb
->
hdev
;
skb
->
pkt_type
=
type
;
__reassembly
(
husb
,
type
)
=
skb
;
scb
=
(
void
*
)
skb
->
cb
;
scb
->
expect
=
len
;
}
else
{
/* Continuation */
scb
=
(
void
*
)
skb
->
cb
;
len
=
scb
->
expect
;
}
if
(
!
count
)
{
BT_DBG
(
"%s intr status %d, count %d"
,
husb
->
hdev
.
name
,
urb
->
status
,
count
);
goto
exit
;
}
len
=
min
(
len
,
count
);
memcpy
(
skb_put
(
skb
,
len
),
data
,
len
);
read_lock
(
&
husb
->
completion_lock
);
husb
->
hdev
.
stat
.
byte_rx
+=
count
;
scb
->
expect
-=
len
;
if
(
!
scb
->
expect
)
{
/* Complete frame */
__reassembly
(
husb
,
type
)
=
NULL
;
hci_recv_frame
(
skb
);
}
count
-=
len
;
data
+=
len
;
}
return
0
;
}
if
(
!
(
skb
=
husb
->
intr_skb
))
{
/* Start of the frame */
if
(
count
<
HCI_EVENT_HDR_SIZE
)
goto
bad_len
;
static
void
hci_usb_rx_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
{
struct
_urb
*
_urb
=
container_of
(
urb
,
struct
_urb
,
urb
);
struct
hci_usb
*
husb
=
(
void
*
)
urb
->
context
;
struct
hci_dev
*
hdev
=
&
husb
->
hdev
;
int
err
,
count
=
urb
->
actual_length
;
eh
=
(
struct
hci_event_hdr
*
)
data
;
len
=
eh
->
plen
+
HCI_EVENT_HDR_SIZE
;
BT_DBG
(
"%s urb %p type %d status %d count %d flags %x"
,
hdev
->
name
,
urb
,
_urb
->
type
,
urb
->
status
,
count
,
urb
->
transfer_flags
)
;
if
(
count
>
len
)
goto
bad_le
n
;
if
(
!
test_bit
(
HCI_RUNNING
,
&
hdev
->
flags
)
)
retur
n
;
skb
=
bt_skb_alloc
(
len
,
GFP_ATOMIC
);
if
(
!
skb
)
{
BT_ERR
(
"%s no memory for event packet"
,
husb
->
hdev
.
name
);
goto
done
;
}
scb
=
(
void
*
)
skb
->
cb
;
read_lock
(
&
husb
->
completion_lock
);
skb
->
dev
=
(
void
*
)
&
husb
->
hdev
;
skb
->
pkt_type
=
HCI_EVENT_PKT
;
if
(
urb
->
status
||
!
count
)
goto
resubmit
;
husb
->
intr_skb
=
skb
;
scb
->
intr_len
=
len
;
if
(
_urb
->
type
==
HCI_SCODATA_PKT
)
{
#ifdef CONFIG_BT_USB_SCO
int
i
;
for
(
i
=
0
;
i
<
urb
->
number_of_packets
;
i
++
)
{
BT_DBG
(
"desc %d status %d offset %d len %d"
,
i
,
urb
->
iso_frame_desc
[
i
].
status
,
urb
->
iso_frame_desc
[
i
].
offset
,
urb
->
iso_frame_desc
[
i
].
actual_length
);
if
(
!
urb
->
iso_frame_desc
[
i
].
status
)
__recv_frame
(
husb
,
_urb
->
type
,
urb
->
transfer_buffer
+
urb
->
iso_frame_desc
[
i
].
offset
,
urb
->
iso_frame_desc
[
i
].
actual_length
);
}
#else
;
#endif
}
else
{
/* Continuation */
scb
=
(
void
*
)
skb
->
cb
;
len
=
scb
->
intr_len
;
if
(
count
>
len
)
{
husb
->
intr_skb
=
NULL
;
kfree_skb
(
skb
);
goto
bad_len
;
err
=
__recv_frame
(
husb
,
_urb
->
type
,
urb
->
transfer_buffer
,
count
);
if
(
err
<
0
)
{
BT_ERR
(
"%s corrupted packet: type %d count %d"
,
husb
->
hdev
.
name
,
_urb
->
type
,
count
);
hdev
->
stat
.
err_rx
++
;
}
}
memcpy
(
skb_put
(
skb
,
count
),
data
,
count
);
scb
->
intr_len
-=
count
;
if
(
!
scb
->
intr_len
)
{
/* Complete frame */
husb
->
intr_skb
=
NULL
;
hci_recv_frame
(
skb
);
}
done:
read_unlock
(
&
husb
->
completion_lock
);
goto
exit
;
resubmit:
urb
->
dev
=
husb
->
udev
;
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
BT_DBG
(
"%s urb %p type %d resubmit status %d"
,
hdev
->
name
,
urb
,
_urb
->
type
,
err
);
bad_len:
BT_ERR
(
"%s bad frame len %d expected %d"
,
husb
->
hdev
.
name
,
count
,
len
);
husb
->
hdev
.
stat
.
err_rx
++
;
read_unlock
(
&
husb
->
completion_lock
);
exit:
status
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
status
)
BT_ERR
(
"%s usb_submit_urb failed with result %d"
,
husb
->
hdev
.
name
,
status
);
}
static
void
hci_usb_tx_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
{
struct
sk_buff
*
skb
=
(
struct
sk_buff
*
)
urb
->
context
;
struct
hci_
dev
*
hdev
=
(
struct
hci_dev
*
)
skb
->
dev
;
struct
hci_
usb
*
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
struct
_urb
*
_urb
=
container_of
(
urb
,
struct
_urb
,
urb
)
;
struct
hci_
usb
*
husb
=
(
void
*
)
urb
->
context
;
struct
hci_
dev
*
hdev
=
&
husb
->
hdev
;
BT_DBG
(
"%s urb %p status %d flags %x"
,
h
usb
->
hdev
.
name
,
urb
,
BT_DBG
(
"%s urb %p status %d flags %x"
,
h
dev
->
name
,
urb
,
urb
->
status
,
urb
->
transfer_flags
);
if
(
urb
->
pipe
==
usb_sndctrlpipe
(
husb
->
udev
,
0
))
{
kfree
(
urb
->
setup_packet
);
clear_bit
(
HCI_USB_CTRL_TX
,
&
husb
->
state
)
;
}
atomic_dec
(
__pending_tx
(
husb
,
_urb
->
type
));
urb
->
transfer_buffer
=
NULL
;
kfree_skb
((
struct
sk_buff
*
)
_urb
->
priv
);
if
(
!
test_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
return
;
read_lock
(
&
husb
->
completion_lock
);
if
(
!
urb
->
status
)
h
usb
->
hdev
.
stat
.
byte_tx
+=
skb
->
len
;
h
dev
->
stat
.
byte_tx
+=
urb
->
transfer_buffer_length
;
else
husb
->
hdev
.
stat
.
err_tx
++
;
skb_unlink
(
skb
);
skb_queue_tail
(
&
husb
->
completed_q
,
skb
);
hci_usb_tx_wakeup
(
husb
);
read_unlock
(
&
husb
->
completion_lock
);
return
;
}
static
void
hci_usb_rx_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
{
struct
sk_buff
*
skb
=
(
struct
sk_buff
*
)
urb
->
context
;
struct
hci_dev
*
hdev
=
(
struct
hci_dev
*
)
skb
->
dev
;
struct
hci_usb
*
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
int
status
,
count
=
urb
->
actual_length
;
struct
hci_acl_hdr
*
ah
;
int
dlen
,
size
;
BT_DBG
(
"%s urb %p status %d count %d flags %x"
,
husb
->
hdev
.
name
,
urb
,
urb
->
status
,
count
,
urb
->
transfer_flags
);
if
(
!
test_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
return
;
hdev
->
stat
.
err_tx
++
;
read_lock
(
&
husb
->
completion_lock
);
if
(
urb
->
status
||
!
count
)
goto
resubmit
;
husb
->
hdev
.
stat
.
byte_rx
+=
count
;
_urb_unlink
(
_urb
);
_urb_queue_tail
(
__completed_q
(
husb
,
_urb
->
type
),
_urb
);
ah
=
(
struct
hci_acl_hdr
*
)
skb
->
data
;
dlen
=
__le16_to_cpu
(
ah
->
dlen
);
size
=
HCI_ACL_HDR_SIZE
+
dlen
;
/* Verify frame len and completeness */
if
(
count
!=
size
)
{
BT_ERR
(
"%s corrupted ACL packet: count %d, dlen %d"
,
husb
->
hdev
.
name
,
count
,
dlen
);
bt_dump
(
"hci_usb"
,
skb
->
data
,
count
);
husb
->
hdev
.
stat
.
err_rx
++
;
goto
resubmit
;
}
skb_unlink
(
skb
);
skb_put
(
skb
,
count
);
hci_recv_frame
(
skb
);
hci_usb_rx_submit
(
husb
,
urb
);
read_unlock
(
&
husb
->
completion_lock
);
return
;
resubmit:
urb
->
dev
=
husb
->
udev
;
status
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
BT_DBG
(
"%s URB resubmit status %d"
,
husb
->
hdev
.
name
,
status
);
hci_usb_tx_wakeup
(
husb
);
read_unlock
(
&
husb
->
completion_lock
);
}
static
void
hci_usb_destruct
(
struct
hci_dev
*
hdev
)
{
struct
hci_usb
*
husb
;
if
(
!
hdev
)
return
;
struct
hci_usb
*
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
BT_DBG
(
"%s"
,
hdev
->
name
);
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
kfree
(
husb
);
}
int
hci_usb_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
udev
=
interface_to_usbdev
(
intf
);
struct
usb_device
*
udev
=
interface_to_usbdev
(
intf
);
struct
usb_host_endpoint
*
bulk_out_ep
[
HCI_MAX_IFACE_NUM
];
struct
usb_host_endpoint
*
isoc_out_ep
[
HCI_MAX_IFACE_NUM
];
struct
usb_host_endpoint
*
bulk_in_ep
[
HCI_MAX_IFACE_NUM
];
struct
usb_host_endpoint
*
isoc_in_ep
[
HCI_MAX_IFACE_NUM
];
struct
usb_host_endpoint
*
intr_in_ep
[
HCI_MAX_IFACE_NUM
];
struct
usb_host_endpoint
*
ep
;
struct
usb_host_interface
*
uif
;
struct
usb_host_endpoint
*
ep
;
struct
usb_interface
*
iface
,
*
isoc_iface
;
struct
hci_usb
*
husb
;
struct
hci_dev
*
hdev
;
int
i
,
a
,
e
,
size
,
ifn
,
isoc_ifnum
,
isoc_alts
;
BT_DBG
(
"intf %p"
,
intf
);
BT_DBG
(
"udev %p ifnum %d"
,
udev
,
ifnum
);
iface
=
&
udev
->
actconfig
->
interface
[
0
];
/* Check our black list */
if
(
usb_match_id
(
intf
,
ignore_ids
))
...
...
@@ -679,6 +825,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
bulk_out_ep
[
i
]
=
ep
;
break
;
#ifdef CONFIG_BT_USB_SCO
case
USB_ENDPOINT_XFER_ISOC
:
if
(
ep
->
desc
.
wMaxPacketSize
<
size
)
break
;
...
...
@@ -693,6 +840,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
else
isoc_out_ep
[
i
]
=
ep
;
break
;
#endif
}
}
}
...
...
@@ -703,10 +851,12 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
goto
done
;
}
#ifdef CONFIG_BT_USB_SCO
if
(
!
isoc_in_ep
[
1
]
||
!
isoc_out_ep
[
1
])
{
BT_DBG
(
"Isoc endpoints not found"
);
isoc_iface
=
NULL
;
}
#endif
if
(
!
(
husb
=
kmalloc
(
sizeof
(
struct
hci_usb
),
GFP_KERNEL
)))
{
BT_ERR
(
"Can't allocate: control structure"
);
...
...
@@ -716,35 +866,36 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
memset
(
husb
,
0
,
sizeof
(
struct
hci_usb
));
husb
->
udev
=
udev
;
husb
->
bulk_out_ep
=
bulk_out_ep
[
0
]
->
desc
.
bEndpointAddress
;
husb
->
bulk_in_ep
=
bulk_in_ep
[
0
]
->
desc
.
bEndpointAddress
;
husb
->
intr_ep
=
intr_in_ep
[
0
]
->
desc
.
bEndpointAddress
;
husb
->
intr_interval
=
intr_in_ep
[
0
]
->
desc
.
bInterval
;
husb
->
bulk_out_ep
=
bulk_out_ep
[
0
];
husb
->
bulk_in_ep
=
bulk_in_ep
[
0
];
husb
->
intr_in_ep
=
intr_in_ep
[
0
];
#ifdef CONFIG_BT_USB_SCO
if
(
isoc_iface
)
{
BT_DBG
(
"isoc ifnum %d alts %d"
,
isoc_ifnum
,
isoc_alts
);
if
(
usb_set_interface
(
udev
,
isoc_ifnum
,
isoc_alts
))
{
BT_ERR
(
"Can't set isoc interface settings"
);
isoc_iface
=
NULL
;
}
usb_driver_claim_interface
(
&
hci_usb_driver
,
isoc_iface
,
husb
);
husb
->
isoc_iface
=
isoc_iface
;
husb
->
isoc_in_ep
=
isoc_in_ep
[
1
]
->
desc
.
bEndpointAddress
;
husb
->
isoc_out_ep
=
isoc_in_ep
[
1
]
->
desc
.
bEndpointAddress
;
husb
->
isoc_in_ep
=
isoc_in_ep
[
isoc_ifnum
];
husb
->
isoc_out_ep
=
isoc_out_ep
[
isoc_ifnum
];
}
husb
->
completion_lock
=
RW_LOCK_UNLOCKED
;
#endif
skb_queue_head_init
(
&
husb
->
acl_q
);
skb_queue_head_init
(
&
husb
->
cmd_q
);
skb_queue_head_init
(
&
husb
->
pending_q
);
skb_queue_head_init
(
&
husb
->
completed_q
);
husb
->
completion_lock
=
RW_LOCK_UNLOCKED
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
skb_queue_head_init
(
&
husb
->
transmit_q
[
i
]);
_urb_queue_init
(
&
husb
->
pending_q
[
i
]);
_urb_queue_init
(
&
husb
->
completed_q
[
i
]);
}
/* Initialize and register HCI device */
hdev
=
&
husb
->
hdev
;
hdev
->
type
=
HCI_USB
;
hdev
->
type
=
HCI_USB
;
hdev
->
driver_data
=
husb
;
hdev
->
open
=
hci_usb_open
;
...
...
@@ -753,8 +904,6 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
hdev
->
send
=
hci_usb_send_frame
;
hdev
->
destruct
=
hci_usb_destruct
;
hdev
->
owner
=
THIS_MODULE
;
if
(
hci_register_dev
(
hdev
)
<
0
)
{
BT_ERR
(
"Can't register HCI device"
);
goto
probe_error
;
...
...
@@ -773,13 +922,12 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
static
void
hci_usb_disconnect
(
struct
usb_interface
*
intf
)
{
struct
hci_usb
*
husb
=
usb_get_intfdata
(
intf
);
struct
hci_dev
*
hdev
;
struct
hci_dev
*
hdev
=
&
husb
->
hdev
;
if
(
!
husb
)
return
;
usb_set_intfdata
(
intf
,
NULL
);
hdev
=
&
husb
->
hdev
;
BT_DBG
(
"%s"
,
hdev
->
name
);
hci_usb_close
(
hdev
);
...
...
@@ -792,17 +940,20 @@ static void hci_usb_disconnect(struct usb_interface *intf)
}
static
struct
usb_driver
hci_usb_driver
=
{
.
name
=
"hci_usb"
,
.
probe
=
hci_usb_probe
,
.
disconnect
=
hci_usb_disconnect
,
.
id_table
=
bluetooth_ids
.
owner
=
THIS_MODULE
,
.
name
=
"hci_usb"
,
.
probe
=
hci_usb_probe
,
.
disconnect
=
hci_usb_disconnect
,
.
id_table
=
bluetooth_ids
,
};
int
hci_usb_init
(
void
)
{
int
err
;
BT_INFO
(
"HCI USB driver ver %s"
,
VERSION
);
BT_INFO
(
"BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc"
,
VERSION
);
BT_INFO
(
"Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>"
);
if
((
err
=
usb_register
(
&
hci_usb_driver
))
<
0
)
BT_ERR
(
"Failed to register HCI USB driver"
);
...
...
@@ -819,5 +970,5 @@ module_init(hci_usb_init);
module_exit
(
hci_usb_cleanup
);
MODULE_AUTHOR
(
"Maxim Krasnyansky <maxk@qualcomm.com>"
);
MODULE_DESCRIPTION
(
"Blue
tooth
HCI USB driver ver "
VERSION
);
MODULE_DESCRIPTION
(
"Blue
Z
HCI USB driver ver "
VERSION
);
MODULE_LICENSE
(
"GPL"
);
drivers/bluetooth/hci_usb.h
View file @
2dbbab6f
/*
BlueZ - Bluetooth protocol stack for Linux
HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
Copyright (C) 2000-2001 Qualcomm Incorporated
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
Copyright (C) 2003 Maxim Krasnyansky <maxk@qualcomm.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
...
...
@@ -40,40 +41,96 @@
#define HCI_MAX_BULK_TX 4
#define HCI_MAX_BULK_RX 1
#define HCI_MAX_ISOC_FRAMES 10
struct
_urb_queue
{
struct
list_head
head
;
spinlock_t
lock
;
};
struct
_urb
{
struct
list_head
list
;
struct
_urb_queue
*
queue
;
int
type
;
void
*
priv
;
struct
urb
urb
;
};
struct
_urb
*
_urb_alloc
(
int
isoc
,
int
gfp
);
static
inline
void
_urb_free
(
struct
_urb
*
_urb
)
{
kfree
(
_urb
);
}
static
inline
void
_urb_queue_init
(
struct
_urb_queue
*
q
)
{
INIT_LIST_HEAD
(
&
q
->
head
);
spin_lock_init
(
&
q
->
lock
);
}
static
inline
void
_urb_queue_head
(
struct
_urb_queue
*
q
,
struct
_urb
*
_urb
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
q
->
lock
,
flags
);
list_add
(
&
_urb
->
list
,
&
q
->
head
);
_urb
->
queue
=
q
;
spin_unlock_irqrestore
(
&
q
->
lock
,
flags
);
}
static
inline
void
_urb_queue_tail
(
struct
_urb_queue
*
q
,
struct
_urb
*
_urb
)
{
unsigned
long
flags
;
spin_lock_irqsave
(
&
q
->
lock
,
flags
);
list_add_tail
(
&
_urb
->
list
,
&
q
->
head
);
_urb
->
queue
=
q
;
spin_unlock_irqrestore
(
&
q
->
lock
,
flags
);
}
static
inline
void
_urb_unlink
(
struct
_urb
*
_urb
)
{
struct
_urb_queue
*
q
=
_urb
->
queue
;
unsigned
long
flags
;
if
(
q
)
{
spin_lock_irqsave
(
&
q
->
lock
,
flags
);
list_del
(
&
_urb
->
list
);
_urb
->
queue
=
NULL
;
spin_unlock_irqrestore
(
&
q
->
lock
,
flags
);
}
}
struct
_urb
*
_urb_dequeue
(
struct
_urb_queue
*
q
);
#ifndef container_of
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#endif
struct
hci_usb
{
struct
hci_dev
hdev
;
unsigned
long
state
;
struct
usb_device
*
udev
;
struct
usb_interface
*
isoc_iface
;
__u8
bulk_out_ep
;
__u8
bulk_in_ep
;
__u8
isoc_out_ep
;
__u8
isoc_in_ep
;
struct
usb_host_endpoint
*
bulk_in_ep
;
struct
usb_host_endpoint
*
bulk_out_ep
;
struct
usb_host_endpoint
*
intr_in_ep
;
struct
usb_interface
*
isoc_iface
;
struct
usb_host_endpoint
*
isoc_out_ep
;
struct
usb_host_endpoint
*
isoc_in_ep
;
__u8
intr_ep
;
__u8
intr_interval
;
struct
urb
*
intr_urb
;
struct
sk_buff
*
intr_skb
;
struct
sk_buff_head
transmit_q
[
4
];
struct
sk_buff
*
reassembly
[
4
];
// Reassembly buffers
rwlock_t
completion_lock
;
struct
sk_buff_head
cmd_q
;
// TX Commands
struct
sk_buff_head
acl_q
;
// TX ACLs
struct
sk_buff_head
pending_q
;
// Pending requests
struct
sk_buff_head
completed_q
;
// Completed requests
};
struct
hci_usb_scb
{
struct
urb
*
urb
;
int
intr_len
;
atomic_t
pending_tx
[
4
];
// Number of pending requests
struct
_urb_queue
pending_q
[
4
];
// Pending requests
struct
_urb_queue
completed_q
[
4
];
// Completed requests
};
/* States */
#define HCI_USB_TX_PROCESS 1
#define HCI_USB_TX_WAKEUP 2
#define HCI_USB_CTRL_TX 3
#endif
/* __KERNEL__ */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment