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
2df06ce5
Commit
2df06ce5
authored
Apr 22, 2003
by
Marcel Holtmann
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://linux.bkbits.net/linux-2.5
into hostme.bitkeeper.com:/ua/repos/l/linux-bt/bt-2.5
parents
f52d1d03
dbb5f15d
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
693 additions
and
444 deletions
+693
-444
drivers/bluetooth/Kconfig
drivers/bluetooth/Kconfig
+8
-1
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bluecard_cs.c
+14
-21
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/bt3c_cs.c
+14
-21
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/btuart_cs.c
+14
-21
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/dtl1_cs.c
+14
-21
drivers/bluetooth/hci_usb.c
drivers/bluetooth/hci_usb.c
+486
-334
drivers/bluetooth/hci_usb.h
drivers/bluetooth/hci_usb.h
+78
-21
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_core.h
+7
-3
include/net/bluetooth/rfcomm.h
include/net/bluetooth/rfcomm.h
+5
-0
net/bluetooth/hci_conn.c
net/bluetooth/hci_conn.c
+1
-0
net/bluetooth/l2cap.c
net/bluetooth/l2cap.c
+1
-1
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/core.c
+51
-0
No files found.
drivers/bluetooth/Kconfig
View file @
2df06ce5
...
...
@@ -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/bluecard_cs.c
View file @
2df06ce5
...
...
@@ -1075,36 +1075,29 @@ int bluecard_event(event_t event, int priority, event_callback_args_t *args)
return
0
;
}
/* ======================== Module initialization ======================== */
int
__init
init_bluecard_cs
(
void
)
static
struct
pcmcia_driver
bluecard_driver
=
{
.
owner
=
THIS_MODULE
,
.
drv
=
{
.
name
=
"bluecard_cs"
,
},
.
attach
=
bluecard_attach
,
.
detach
=
bluecard_detach
,
};
static
int
__init
init_bluecard_cs
(
void
)
{
servinfo_t
serv
;
int
err
;
CardServices
(
GetCardServicesInfo
,
&
serv
);
if
(
serv
.
Revision
!=
CS_RELEASE_CODE
)
{
printk
(
KERN_NOTICE
"bluecard_cs: Card Services release does not match!
\n
"
);
return
-
1
;
}
err
=
register_pccard_driver
(
&
dev_info
,
&
bluecard_attach
,
&
bluecard_detach
);
return
err
;
return
pcmcia_register_driver
(
&
bluecard_driver
);
}
void
__exit
exit_bluecard_cs
(
void
)
static
void
__exit
exit_bluecard_cs
(
void
)
{
unregister_pccard_driver
(
&
dev_info
);
pcmcia_unregister_driver
(
&
bluecard_driver
);
/* XXX: this really needs to move into generic code.. */
while
(
dev_list
!=
NULL
)
bluecard_detach
(
dev_list
);
}
module_init
(
init_bluecard_cs
);
module_exit
(
exit_bluecard_cs
);
drivers/bluetooth/bt3c_cs.c
View file @
2df06ce5
...
...
@@ -861,36 +861,29 @@ int bt3c_event(event_t event, int priority, event_callback_args_t *args)
return
0
;
}
/* ======================== Module initialization ======================== */
int
__init
init_bt3c_cs
(
void
)
static
struct
pcmcia_driver
bt3c_driver
=
{
.
owner
=
THIS_MODULE
,
.
drv
=
{
.
name
=
"bt3c_cs"
,
},
.
attach
=
bt3c_attach
,
.
detach
=
bt3c_detach
,
};
static
int
__init
init_bt3c_cs
(
void
)
{
servinfo_t
serv
;
int
err
;
CardServices
(
GetCardServicesInfo
,
&
serv
);
if
(
serv
.
Revision
!=
CS_RELEASE_CODE
)
{
printk
(
KERN_NOTICE
"bt3c_cs: Card Services release does not match!
\n
"
);
return
-
1
;
}
err
=
register_pccard_driver
(
&
dev_info
,
&
bt3c_attach
,
&
bt3c_detach
);
return
err
;
return
pcmcia_register_driver
(
&
bt3c_driver
);
}
void
__exit
exit_bt3c_cs
(
void
)
static
void
__exit
exit_bt3c_cs
(
void
)
{
unregister_pccard_driver
(
&
dev_info
);
pcmcia_unregister_driver
(
&
bt3c_driver
);
/* XXX: this really needs to move into generic code.. */
while
(
dev_list
!=
NULL
)
bt3c_detach
(
dev_list
);
}
module_init
(
init_bt3c_cs
);
module_exit
(
exit_bt3c_cs
);
drivers/bluetooth/btuart_cs.c
View file @
2df06ce5
...
...
@@ -868,36 +868,29 @@ int btuart_event(event_t event, int priority, event_callback_args_t *args)
return
0
;
}
/* ======================== Module initialization ======================== */
int
__init
init_btuart_cs
(
void
)
static
struct
pcmcia_driver
btuart_driver
=
{
.
owner
=
THIS_MODULE
,
.
drv
=
{
.
name
=
"btuart_cs"
,
},
.
attach
=
btuart_attach
,
.
detach
=
btuart_detach
,
};
static
int
__init
init_btuart_cs
(
void
)
{
servinfo_t
serv
;
int
err
;
CardServices
(
GetCardServicesInfo
,
&
serv
);
if
(
serv
.
Revision
!=
CS_RELEASE_CODE
)
{
printk
(
KERN_NOTICE
"btuart_cs: Card Services release does not match!
\n
"
);
return
-
1
;
}
err
=
register_pccard_driver
(
&
dev_info
,
&
btuart_attach
,
&
btuart_detach
);
return
err
;
return
pcmcia_register_driver
(
&
btuart_driver
);
}
void
__exit
exit_btuart_cs
(
void
)
static
void
__exit
exit_btuart_cs
(
void
)
{
unregister_pccard_driver
(
&
dev_info
);
pcmcia_unregister_driver
(
&
btuart_driver
);
/* XXX: this really needs to move into generic code.. */
while
(
dev_list
!=
NULL
)
btuart_detach
(
dev_list
);
}
module_init
(
init_btuart_cs
);
module_exit
(
exit_btuart_cs
);
drivers/bluetooth/dtl1_cs.c
View file @
2df06ce5
...
...
@@ -820,36 +820,29 @@ int dtl1_event(event_t event, int priority, event_callback_args_t *args)
return
0
;
}
/* ======================== Module initialization ======================== */
int
__init
init_dtl1_cs
(
void
)
static
struct
pcmcia_driver
dtl1_driver
=
{
.
owner
=
THIS_MODULE
,
.
drv
=
{
.
name
=
"dtl1_cs"
,
},
.
attach
=
dtl1_attach
,
.
detach
=
dtl1_detach
,
};
static
int
__init
init_dtl1_cs
(
void
)
{
servinfo_t
serv
;
int
err
;
CardServices
(
GetCardServicesInfo
,
&
serv
);
if
(
serv
.
Revision
!=
CS_RELEASE_CODE
)
{
printk
(
KERN_NOTICE
"dtl1_cs: Card Services release does not match!
\n
"
);
return
-
1
;
}
err
=
register_pccard_driver
(
&
dev_info
,
&
dtl1_attach
,
&
dtl1_detach
);
return
err
;
return
pcmcia_register_driver
(
&
dtl1_driver
);
}
void
__exit
exit_dtl1_cs
(
void
)
static
void
__exit
exit_dtl1_cs
(
void
)
{
unregister_pccard_driver
(
&
dev_info
);
pcmcia_unregister_driver
(
&
dtl1_driver
);
/* XXX: this really needs to move into generic code.. */
while
(
dev_list
!=
NULL
)
dtl1_detach
(
dev_list
);
}
module_init
(
init_dtl1_cs
);
module_exit
(
exit_dtl1_cs
);
drivers/bluetooth/hci_usb.c
View file @
2df06ce5
/*
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
;
}
_urb
->
type
=
HCI_SCODATA_PKT
;
_urb_queue_tail
(
__pending_q
(
husb
,
_urb
->
type
),
_urb
);
BT_DBG
(
"%s urb %p"
,
husb
->
hdev
.
name
,
urb
)
;
urb
=
&
_urb
->
urb
;
skb
->
dev
=
(
void
*
)
&
husb
->
hdev
;
skb
->
pkt_type
=
HCI_ACLDATA_PKT
;
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
;
scb
=
(
struct
hci_usb_scb
*
)
skb
->
cb
;
scb
->
urb
=
urb
;
urb
->
transfer_buffer_length
=
size
;
urb
->
transfer_buffer
=
buf
;
urb
->
transfer_flags
=
URB_ISO_ASAP
;
pipe
=
usb_rcvbulkpipe
(
husb
->
udev
,
husb
->
bulk_in_ep
);
__fill_isoc_desc
(
urb
,
size
,
mtu
);
usb_fill_bulk_urb
(
urb
,
husb
->
udev
,
pipe
,
skb
->
data
,
size
,
hci_usb_rx_complete
,
sk
b
);
BT_DBG
(
"%s urb %p"
,
husb
->
hdev
.
name
,
ur
b
);
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
clear_bit
(
HCI_RUNNING
,
&
hdev
->
flags
);
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
;
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
);
kfree_skb
(
skb
);
_urb_queue_tail
(
__completed_q
(
husb
,
_urb
->
type
),
_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
);
}
while
((
urb
=
hci_usb_get_completed
(
husb
)))
usb_free_urb
(
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,79 +384,123 @@ static int hci_usb_close(struct hci_dev *hdev)
return
0
;
}
static
int
__tx_submit
(
struct
hci_usb
*
husb
,
struct
_urb
*
_urb
)
{
struct
urb
*
urb
=
&
_urb
->
urb
;
int
err
;
BT_DBG
(
"%s urb %p type %d"
,
husb
->
hdev
.
name
,
urb
,
_urb
->
type
);
_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
));
return
err
;
}
static
inline
int
hci_usb_send_ctrl
(
struct
hci_usb
*
husb
,
struct
sk_buff
*
skb
)
{
struct
hci_usb_scb
*
scb
=
(
void
*
)
skb
->
cb
;
struct
urb
*
urb
=
hci_usb_get_completed
(
husb
);
struct
usb_ctrlrequest
*
cr
;
int
pipe
,
err
;
struct
_urb
*
_urb
=
__get_completed
(
husb
,
skb
->
pkt_type
);
struct
usb_ctrlrequest
*
dr
;
struct
urb
*
urb
;
if
(
!
urb
&&
!
(
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
)))
if
(
!
_urb
)
{
_urb
=
_urb_alloc
(
0
,
GFP_ATOMIC
);
if
(
!
_urb
)
return
-
ENOMEM
;
_urb
->
type
=
skb
->
pkt_type
;
if
(
!
(
cr
=
kmalloc
(
sizeof
(
*
cr
),
GFP_ATOMIC
)))
{
usb_free_urb
(
urb
);
dr
=
kmalloc
(
sizeof
(
*
dr
),
GFP_ATOMIC
);
if
(
!
dr
)
{
_urb_free
(
_urb
);
return
-
ENOMEM
;
}
}
else
dr
=
(
void
*
)
_urb
->
urb
.
setup_packet
;
pipe
=
usb_sndctrlpipe
(
husb
->
udev
,
0
);
dr
->
bRequestType
=
HCI_CTRL_REQ
;
dr
->
bRequest
=
0
;
dr
->
wIndex
=
0
;
dr
->
wValue
=
0
;
dr
->
wLength
=
__cpu_to_le16
(
skb
->
len
);
cr
->
bRequestType
=
HCI_CTRL_REQ
;
cr
->
bRequest
=
0
;
cr
->
wIndex
=
0
;
cr
->
wValue
=
0
;
cr
->
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
);
usb_fill_control_urb
(
urb
,
husb
->
udev
,
pipe
,
(
void
*
)
cr
,
skb
->
data
,
skb
->
len
,
hci_usb_tx_complete
,
skb
);
BT_DBG
(
"%s skb %p len %d"
,
husb
->
hdev
.
name
,
skb
,
skb
->
len
);
BT_DBG
(
"%s urb %p len %d"
,
husb
->
hdev
.
name
,
urb
,
skb
->
len
);
_urb
->
priv
=
skb
;
return
__tx_submit
(
husb
,
_urb
);
}
scb
->
urb
=
urb
;
static
inline
int
hci_usb_send_bulk
(
struct
hci_usb
*
husb
,
struct
sk_buff
*
skb
)
{
struct
_urb
*
_urb
=
__get_completed
(
husb
,
skb
->
pkt_type
);
struct
urb
*
urb
;
int
pipe
;
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
);
if
(
!
_urb
)
{
_urb
=
_urb_alloc
(
0
,
GFP_ATOMIC
);
if
(
!
_urb
)
return
-
ENOMEM
;
_urb
->
type
=
skb
->
pkt_type
;
}
return
err
;
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
,
husb
);
urb
->
transfer_flags
=
USB_ZERO_PACKET
;
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
)
#ifdef CONFIG_BT_USB_SCO
static
inline
int
hci_usb_send_isoc
(
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
;
if
(
!
urb
&&
!
(
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
)))
if
(
!
_urb
)
{
_urb
=
_urb_alloc
(
HCI_MAX_ISOC_FRAMES
,
GFP_ATOMIC
);
if
(
!
_urb
)
return
-
ENOMEM
;
_urb
->
type
=
skb
->
pkt_type
;
}
pipe
=
usb_sndbulkpipe
(
husb
->
udev
,
husb
->
bulk_out_ep
);
BT_DBG
(
"%s skb %p len %d"
,
husb
->
hdev
.
name
,
skb
,
skb
->
len
);
usb_fill_bulk_urb
(
urb
,
husb
->
udev
,
pipe
,
skb
->
data
,
skb
->
len
,
hci_usb_tx_complete
,
skb
);
urb
->
transfer_flags
=
URB_ZERO_PACKET
;
urb
=
&
_urb
->
urb
;
BT_DBG
(
"%s urb %p len %d"
,
husb
->
hdev
.
name
,
urb
,
skb
->
len
);
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
;
scb
->
urb
=
urb
;
urb
->
transfer_buffer
=
skb
->
data
;
urb
->
transfer_buffer_length
=
skb
->
len
;
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
);
}
return
err
;
__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
);
...
...
@@ -351,22 +508,31 @@ static void hci_usb_tx_process(struct hci_usb *husb)
do
{
clear_bit
(
HCI_USB_TX_WAKEUP
,
&
husb
->
state
);
/* Process
ACL
queue */
while
(
skb_queue_len
(
&
husb
->
pending_q
)
<
HCI_MAX_PENDING
&&
(
skb
=
skb_dequeue
(
&
husb
->
acl_q
)))
{
if
(
hci_usb_send_bulk
(
husb
,
skb
)
<
0
)
{
skb_queue_head
(
&
husb
->
acl_q
,
skb
);
break
;
/* 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
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
)
;
/* Process
ACL
queue */
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
(
q
,
skb
);
break
;
}
}
}
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,228 +562,206 @@ 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 urb %p count %d"
,
husb
->
hdev
.
name
,
urb
,
count
);
if
(
!
test_bit
(
HCI_RUNNING
,
&
husb
->
hdev
.
flags
))
return
;
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
;
}
if
(
!
count
)
{
BT_DBG
(
"%s intr status %d, count %d"
,
husb
->
hdev
.
name
,
urb
->
status
,
count
);
goto
exit
;
}
read_lock
(
&
husb
->
completion_lock
);
BT_DBG
(
"%s type %d data %p count %d"
,
husb
->
hdev
.
name
,
type
,
data
,
count
);
husb
->
hdev
.
stat
.
byte_rx
+=
count
;
if
(
!
(
skb
=
husb
->
intr_skb
))
{
while
(
count
)
{
struct
sk_buff
*
skb
=
__reassembly
(
husb
,
type
);
struct
{
int
expect
;
}
*
scb
;
int
len
=
0
;
if
(
!
skb
)
{
/* Start of the frame */
if
(
count
<
HCI_EVENT_HDR_SIZE
)
goto
bad_len
;
eh
=
(
struct
hci_event_hdr
*
)
data
;
len
=
eh
->
plen
+
HCI_EVENT_HDR_SIZE
;
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
;
if
(
count
>
len
)
goto
bad_len
;
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 event
packet"
,
husb
->
hdev
.
name
);
goto
done
;
BT_ERR
(
"%s no memory for the
packet"
,
husb
->
hdev
.
name
);
return
-
ENOMEM
;
}
scb
=
(
void
*
)
skb
->
cb
;
skb
->
dev
=
(
void
*
)
&
husb
->
hdev
;
skb
->
pkt_type
=
HCI_EVENT_PKT
;
skb
->
pkt_type
=
type
;
__reassembly
(
husb
,
type
)
=
skb
;
husb
->
intr_skb
=
sk
b
;
scb
->
intr_len
=
len
;
scb
=
(
void
*
)
skb
->
c
b
;
scb
->
expect
=
len
;
}
else
{
/* Continuation */
scb
=
(
void
*
)
skb
->
cb
;
len
=
scb
->
intr_len
;
if
(
count
>
len
)
{
husb
->
intr_skb
=
NULL
;
kfree_skb
(
skb
);
goto
bad_len
;
}
len
=
scb
->
expect
;
}
memcpy
(
skb_put
(
skb
,
count
),
data
,
count
);
scb
->
intr_len
-=
count
;
len
=
min
(
len
,
count
);
memcpy
(
skb_put
(
skb
,
len
),
data
,
len
);
if
(
!
scb
->
intr_len
)
{
scb
->
expect
-=
len
;
if
(
!
scb
->
expect
)
{
/* Complete frame */
husb
->
intr_skb
=
NULL
;
__reassembly
(
husb
,
type
)
=
NULL
;
hci_recv_frame
(
skb
);
}
done:
read_unlock
(
&
husb
->
completion_lock
);
goto
exit
;
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
);
count
-=
len
;
data
+=
len
;
}
return
0
;
}
static
void
hci_usb_
t
x_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
static
void
hci_usb_
r
x_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
;
BT_DBG
(
"%s urb %p status %d flags %x"
,
husb
->
hdev
.
name
,
urb
,
urb
->
status
,
urb
->
transfer_flags
);
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
;
if
(
urb
->
pipe
==
usb_sndctrlpipe
(
husb
->
udev
,
0
))
{
kfree
(
urb
->
setup_packet
);
clear_bit
(
HCI_USB_CTRL_TX
,
&
husb
->
state
);
}
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
(
!
test_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
return
;
read_lock
(
&
husb
->
completion_lock
);
if
(
!
urb
->
status
)
husb
->
hdev
.
stat
.
byte_tx
+=
skb
->
len
;
else
husb
->
hdev
.
stat
.
err_tx
++
;
if
(
urb
->
status
||
!
count
)
goto
resubmit
;
skb_unlink
(
skb
);
skb_queue_tail
(
&
husb
->
completed_q
,
skb
);
hci_usb_tx_wakeup
(
husb
);
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
{
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
++
;
}
}
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
);
read_unlock
(
&
husb
->
completion_lock
);
return
;
}
static
void
hci_usb_
r
x_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
static
void
hci_usb_
t
x_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
);
struct
_urb
*
_urb
=
container_of
(
urb
,
struct
_urb
,
urb
);
struct
hci_usb
*
husb
=
(
void
*
)
urb
->
context
;
struct
hci_dev
*
hdev
=
&
husb
->
hdev
;
if
(
!
test_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
return
;
BT_DBG
(
"%s urb %p status %d flags %x"
,
hdev
->
name
,
urb
,
urb
->
status
,
urb
->
transfer_flags
)
;
read_lock
(
&
husb
->
completion_lock
);
atomic_dec
(
__pending_tx
(
husb
,
_urb
->
type
)
);
if
(
urb
->
status
||
!
count
)
goto
resubmit
;
urb
->
transfer_buffer
=
NULL
;
kfree_skb
((
struct
sk_buff
*
)
_urb
->
priv
)
;
husb
->
hdev
.
stat
.
byte_rx
+=
count
;
ah
=
(
struct
hci_acl_hdr
*
)
skb
->
data
;
dlen
=
__le16_to_cpu
(
ah
->
dlen
);
size
=
HCI_ACL_HDR_SIZE
+
dlen
;
if
(
!
test_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
return
;
/* 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
;
}
if
(
!
urb
->
status
)
hdev
->
stat
.
byte_tx
+=
urb
->
transfer_buffer_length
;
else
hdev
->
stat
.
err_tx
++
;
skb_unlink
(
skb
);
skb_put
(
skb
,
count
);
hci_recv_frame
(
skb
);
read_lock
(
&
husb
->
completion_lock
);
hci_usb_rx_submit
(
husb
,
urb
);
_urb_unlink
(
_urb
);
_urb_queue_tail
(
__completed_q
(
husb
,
_urb
->
type
),
_urb
);
read_unlock
(
&
husb
->
completion_lock
);
return
;
hci_usb_tx_wakeup
(
husb
);
resubmit:
urb
->
dev
=
husb
->
udev
;
status
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
BT_DBG
(
"%s URB resubmit status %d"
,
husb
->
hdev
.
name
,
status
);
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
);
}
...
...
@@ -629,14 +773,16 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
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_interface
*
uif
;
struct
usb_host_endpoint
*
ep
;
struct
usb_host_interface
*
uif
;
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,30 +866,31 @@ 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
];
}
#endif
husb
->
completion_lock
=
RW_LOCK_UNLOCKED
;
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
);
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
;
...
...
@@ -773,13 +924,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
);
...
...
@@ -795,14 +945,16 @@ static struct usb_driver hci_usb_driver = {
.
name
=
"hci_usb"
,
.
probe
=
hci_usb_probe
,
.
disconnect
=
hci_usb_disconnect
,
.
id_table
=
bluetooth_ids
.
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 +971,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 @
2df06ce5
/*
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__ */
include/net/bluetooth/hci_core.h
View file @
2df06ce5
...
...
@@ -262,7 +262,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
int
hci_conn_auth
(
struct
hci_conn
*
conn
);
int
hci_conn_encrypt
(
struct
hci_conn
*
conn
);
static
inline
void
hci_conn_set_timer
(
struct
hci_conn
*
conn
,
long
timeout
)
static
inline
void
hci_conn_set_timer
(
struct
hci_conn
*
conn
,
unsigned
long
timeout
)
{
mod_timer
(
&
conn
->
timer
,
jiffies
+
timeout
);
}
...
...
@@ -280,8 +280,12 @@ static inline void hci_conn_hold(struct hci_conn *conn)
static
inline
void
hci_conn_put
(
struct
hci_conn
*
conn
)
{
if
(
atomic_dec_and_test
(
&
conn
->
refcnt
)
&&
conn
->
out
)
if
(
atomic_dec_and_test
(
&
conn
->
refcnt
))
{
if
(
conn
->
type
==
SCO_LINK
)
hci_conn_set_timer
(
conn
,
HZ
/
100
);
else
if
(
conn
->
out
)
hci_conn_set_timer
(
conn
,
HCI_DISCONN_TIMEOUT
);
}
}
/* ----- HCI tasks ----- */
...
...
include/net/bluetooth/rfcomm.h
View file @
2df06ce5
...
...
@@ -146,6 +146,11 @@ struct rfcomm_rpn {
u16
param_mask
;
}
__attribute__
((
packed
));
struct
rfcomm_rls
{
u8
dlci
;
u8
status
;
}
__attribute__
((
packed
));
struct
rfcomm_msc
{
u8
dlci
;
u8
v24_sig
;
...
...
net/bluetooth/hci_conn.c
View file @
2df06ce5
...
...
@@ -71,6 +71,7 @@ void hci_acl_connect(struct hci_conn *conn)
memset
(
&
cp
,
0
,
sizeof
(
cp
));
bacpy
(
&
cp
.
bdaddr
,
&
conn
->
dst
);
cp
.
pscan_rep_mode
=
0x01
;
if
((
ie
=
inquiry_cache_lookup
(
hdev
,
&
conn
->
dst
))
&&
inquiry_entry_age
(
ie
)
<=
INQUIRY_ENTRY_AGE_MAX
)
{
...
...
net/bluetooth/l2cap.c
View file @
2df06ce5
...
...
@@ -1788,7 +1788,7 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
if
(
sk
->
state
!=
BT_LISTEN
)
continue
;
if
(
!
bacmp
(
&
bt_sk
(
sk
)
->
src
,
bdaddr
))
{
if
(
!
bacmp
(
&
bt_sk
(
sk
)
->
src
,
&
hdev
->
bdaddr
))
{
lm1
|=
(
HCI_LM_ACCEPT
|
l2cap_pi
(
sk
)
->
link_mode
);
exact
++
;
}
else
if
(
!
bacmp
(
&
bt_sk
(
sk
)
->
src
,
BDADDR_ANY
))
...
...
net/bluetooth/rfcomm/core.c
View file @
2df06ce5
...
...
@@ -798,6 +798,33 @@ static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
);
}
static
int
rfcomm_send_rls
(
struct
rfcomm_session
*
s
,
int
cr
,
u8
dlci
,
u8
status
)
{
struct
rfcomm_hdr
*
hdr
;
struct
rfcomm_mcc
*
mcc
;
struct
rfcomm_rls
*
rls
;
u8
buf
[
16
],
*
ptr
=
buf
;
BT_DBG
(
"%p cr %d status 0x%x"
,
s
,
cr
,
status
);
hdr
=
(
void
*
)
ptr
;
ptr
+=
sizeof
(
*
hdr
);
hdr
->
addr
=
__addr
(
s
->
initiator
,
0
);
hdr
->
ctrl
=
__ctrl
(
RFCOMM_UIH
,
0
);
hdr
->
len
=
__len8
(
sizeof
(
*
mcc
)
+
sizeof
(
*
rls
));
mcc
=
(
void
*
)
ptr
;
ptr
+=
sizeof
(
*
mcc
);
mcc
->
type
=
__mcc_type
(
cr
,
RFCOMM_RLS
);
mcc
->
len
=
__len8
(
sizeof
(
*
rls
));
rls
=
(
void
*
)
ptr
;
ptr
+=
sizeof
(
*
rls
);
rls
->
dlci
=
__addr
(
1
,
dlci
);
rls
->
status
=
status
;
*
ptr
=
__fcs
(
buf
);
ptr
++
;
return
rfcomm_send_frame
(
s
,
buf
,
ptr
-
buf
);
}
static
int
rfcomm_send_msc
(
struct
rfcomm_session
*
s
,
int
cr
,
u8
dlci
,
u8
v24_sig
)
{
struct
rfcomm_hdr
*
hdr
;
...
...
@@ -1229,6 +1256,26 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
return
0
;
}
static
int
rfcomm_recv_rls
(
struct
rfcomm_session
*
s
,
int
cr
,
struct
sk_buff
*
skb
)
{
struct
rfcomm_rls
*
rls
=
(
void
*
)
skb
->
data
;
u8
dlci
=
__get_dlci
(
rls
->
dlci
);
BT_DBG
(
"dlci %d cr %d status 0x%x"
,
dlci
,
cr
,
rls
->
status
);
if
(
!
cr
)
return
0
;
/* FIXME: We should probably do something with this
information here. But for now it's sufficient just
to reply -- Bluetooth 1.1 says it's mandatory to
recognise and respond to RLS */
rfcomm_send_rls
(
s
,
0
,
dlci
,
rls
->
status
);
return
0
;
}
static
int
rfcomm_recv_msc
(
struct
rfcomm_session
*
s
,
int
cr
,
struct
sk_buff
*
skb
)
{
struct
rfcomm_msc
*
msc
=
(
void
*
)
skb
->
data
;
...
...
@@ -1279,6 +1326,10 @@ static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
rfcomm_recv_rpn
(
s
,
cr
,
len
,
skb
);
break
;
case
RFCOMM_RLS
:
rfcomm_recv_rls
(
s
,
cr
,
skb
);
break
;
case
RFCOMM_MSC
:
rfcomm_recv_msc
(
s
,
cr
,
skb
);
break
;
...
...
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