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
nexedi
linux
Commits
76d53202
Commit
76d53202
authored
Apr 21, 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
1bb563db
b9568005
Changes
11
Show whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
692 additions
and
443 deletions
+692
-443
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/rfcomm/core.c
net/bluetooth/rfcomm/core.c
+51
-0
No files found.
drivers/bluetooth/Kconfig
View file @
76d53202
...
@@ -13,11 +13,18 @@ config BT_HCIUSB
...
@@ -13,11 +13,18 @@ config BT_HCIUSB
Say Y here to compile support for Bluetooth USB devices into the
Say Y here to compile support for Bluetooth USB devices into the
kernel or say M to compile it as module (hci_usb).
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
config BT_USB_ZERO_PACKET
bool "USB zero packet support"
bool "USB zero packet support"
depends on BT_HCIUSB
depends on BT_HCIUSB
help
help
Support for USB zero packets.
This option is provided only as a work around for buggy Bluetooth USB
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
devices. Do _not_ enable it unless you know for sure that your device
requires zero packets.
requires zero packets.
...
...
drivers/bluetooth/bluecard_cs.c
View file @
76d53202
...
@@ -1075,36 +1075,29 @@ int bluecard_event(event_t event, int priority, event_callback_args_t *args)
...
@@ -1075,36 +1075,29 @@ int bluecard_event(event_t event, int priority, event_callback_args_t *args)
return
0
;
return
0
;
}
}
static
struct
pcmcia_driver
bluecard_driver
=
{
.
owner
=
THIS_MODULE
,
/* ======================== Module initialization ======================== */
.
drv
=
{
.
name
=
"bluecard_cs"
,
},
int
__init
init_bluecard_cs
(
void
)
.
attach
=
bluecard_attach
,
.
detach
=
bluecard_detach
,
};
static
int
__init
init_bluecard_cs
(
void
)
{
{
servinfo_t
serv
;
return
pcmcia_register_driver
(
&
bluecard_driver
);
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
;
}
}
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
)
while
(
dev_list
!=
NULL
)
bluecard_detach
(
dev_list
);
bluecard_detach
(
dev_list
);
}
}
module_init
(
init_bluecard_cs
);
module_init
(
init_bluecard_cs
);
module_exit
(
exit_bluecard_cs
);
module_exit
(
exit_bluecard_cs
);
drivers/bluetooth/bt3c_cs.c
View file @
76d53202
...
@@ -861,36 +861,29 @@ int bt3c_event(event_t event, int priority, event_callback_args_t *args)
...
@@ -861,36 +861,29 @@ int bt3c_event(event_t event, int priority, event_callback_args_t *args)
return
0
;
return
0
;
}
}
static
struct
pcmcia_driver
bt3c_driver
=
{
.
owner
=
THIS_MODULE
,
/* ======================== Module initialization ======================== */
.
drv
=
{
.
name
=
"bt3c_cs"
,
},
int
__init
init_bt3c_cs
(
void
)
.
attach
=
bt3c_attach
,
.
detach
=
bt3c_detach
,
};
static
int
__init
init_bt3c_cs
(
void
)
{
{
servinfo_t
serv
;
return
pcmcia_register_driver
(
&
bt3c_driver
);
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
;
}
}
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
)
while
(
dev_list
!=
NULL
)
bt3c_detach
(
dev_list
);
bt3c_detach
(
dev_list
);
}
}
module_init
(
init_bt3c_cs
);
module_init
(
init_bt3c_cs
);
module_exit
(
exit_bt3c_cs
);
module_exit
(
exit_bt3c_cs
);
drivers/bluetooth/btuart_cs.c
View file @
76d53202
...
@@ -868,36 +868,29 @@ int btuart_event(event_t event, int priority, event_callback_args_t *args)
...
@@ -868,36 +868,29 @@ int btuart_event(event_t event, int priority, event_callback_args_t *args)
return
0
;
return
0
;
}
}
static
struct
pcmcia_driver
btuart_driver
=
{
.
owner
=
THIS_MODULE
,
/* ======================== Module initialization ======================== */
.
drv
=
{
.
name
=
"btuart_cs"
,
},
int
__init
init_btuart_cs
(
void
)
.
attach
=
btuart_attach
,
.
detach
=
btuart_detach
,
};
static
int
__init
init_btuart_cs
(
void
)
{
{
servinfo_t
serv
;
return
pcmcia_register_driver
(
&
btuart_driver
);
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
;
}
}
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
)
while
(
dev_list
!=
NULL
)
btuart_detach
(
dev_list
);
btuart_detach
(
dev_list
);
}
}
module_init
(
init_btuart_cs
);
module_init
(
init_btuart_cs
);
module_exit
(
exit_btuart_cs
);
module_exit
(
exit_btuart_cs
);
drivers/bluetooth/dtl1_cs.c
View file @
76d53202
...
@@ -820,36 +820,29 @@ int dtl1_event(event_t event, int priority, event_callback_args_t *args)
...
@@ -820,36 +820,29 @@ int dtl1_event(event_t event, int priority, event_callback_args_t *args)
return
0
;
return
0
;
}
}
static
struct
pcmcia_driver
dtl1_driver
=
{
.
owner
=
THIS_MODULE
,
/* ======================== Module initialization ======================== */
.
drv
=
{
.
name
=
"dtl1_cs"
,
},
int
__init
init_dtl1_cs
(
void
)
.
attach
=
dtl1_attach
,
.
detach
=
dtl1_detach
,
};
static
int
__init
init_dtl1_cs
(
void
)
{
{
servinfo_t
serv
;
return
pcmcia_register_driver
(
&
dtl1_driver
);
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
;
}
}
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
)
while
(
dev_list
!=
NULL
)
dtl1_detach
(
dev_list
);
dtl1_detach
(
dev_list
);
}
}
module_init
(
init_dtl1_cs
);
module_init
(
init_dtl1_cs
);
module_exit
(
exit_dtl1_cs
);
module_exit
(
exit_dtl1_cs
);
drivers/bluetooth/hci_usb.c
View file @
76d53202
/*
/*
BlueZ - Bluetooth protocol stack for Linux
HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
Copyright (C) 2000-2001 Qualcomm Incorporated
Copyright (C) 2000-2001 Qualcomm Incorporated
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
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
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
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
published by the Free Software Foundation;
...
@@ -23,20 +24,17 @@
...
@@ -23,20 +24,17 @@
*/
*/
/*
/*
* Bluetooth HCI USB driver.
* Based on original USB Bluetooth driver for Linux kernel
* Based on original USB Bluetooth driver for Linux kernel
* Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu>
* Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu>
*
*
* $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $
* $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/config.h>
#include <linux/module.h>
#include <linux/module.h>
#define __KERNEL_SYSCALLS__
#include <linux/version.h>
#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/init.h>
...
@@ -49,17 +47,15 @@
...
@@ -49,17 +47,15 @@
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/skbuff.h>
#include <linux/kmod.h>
#include <linux/usb.h>
#include <linux/usb.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.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
#undef BT_DBG
#define BT_DBG( A... )
#define BT_DBG( A... )
#undef BT_DMP
#undef BT_DMP
...
@@ -67,8 +63,8 @@
...
@@ -67,8 +63,8 @@
#endif
#endif
#ifndef CONFIG_BT_USB_ZERO_PACKET
#ifndef CONFIG_BT_USB_ZERO_PACKET
#undef U
R
B_ZERO_PACKET
#undef U
S
B_ZERO_PACKET
#define U
R
B_ZERO_PACKET 0
#define U
S
B_ZERO_PACKET 0
#endif
#endif
static
struct
usb_driver
hci_usb_driver
;
static
struct
usb_driver
hci_usb_driver
;
...
@@ -80,6 +76,9 @@ static struct usb_device_id bluetooth_ids[] = {
...
@@ -80,6 +76,9 @@ static struct usb_device_id bluetooth_ids[] = {
/* Ericsson with non-standard id */
/* Ericsson with non-standard id */
{
USB_DEVICE
(
0x0bdb
,
0x1002
)
},
{
USB_DEVICE
(
0x0bdb
,
0x1002
)
},
/* Bluetooth Ultraport Module from IBM */
{
USB_DEVICE
(
0x04bf
,
0x030a
)
},
{
}
/* Terminating entry */
{
}
/* Terminating entry */
};
};
...
@@ -92,108 +91,196 @@ static struct usb_device_id ignore_ids[] = {
...
@@ -92,108 +91,196 @@ static struct usb_device_id ignore_ids[] = {
{
}
/* Terminating entry */
{
}
/* 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_rx_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
);
static
void
hci_usb_tx_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
;
return
_urb_dequeue
(
__completed_q
(
husb
,
type
));
struct
urb
*
urb
=
NULL
;
}
skb
=
skb_dequeue
(
&
husb
->
completed_q
);
#ifdef CONFIG_BT_USB_SCO
if
(
skb
)
{
static
void
__fill_isoc_desc
(
struct
urb
*
urb
,
int
len
,
int
mtu
)
urb
=
((
struct
hci_usb_scb
*
)
skb
->
cb
)
->
urb
;
{
kfree_skb
(
skb
);
int
offset
=
0
,
i
;
}
BT_DBG
(
"%s urb %p"
,
husb
->
hdev
.
name
,
urb
);
BT_DBG
(
"len %d mtu %d"
,
len
,
mtu
);
return
urb
;
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
;
struct
urb
*
urb
;
int
pipe
,
size
;
int
err
,
pipe
,
interval
,
size
;
void
*
buf
;
void
*
buf
;
BT_DBG
(
"%s"
,
husb
->
hdev
.
name
);
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
;
return
-
ENOMEM
;
if
(
!
(
buf
=
kmalloc
(
HCI_MAX_EVENT_SIZE
,
GFP_KERNEL
)))
{
_urb
=
_urb_alloc
(
0
,
GFP_ATOMIC
);
usb_free_urb
(
urb
);
if
(
!
_urb
)
{
kfree
(
buf
);
return
-
ENOMEM
;
return
-
ENOMEM
;
}
}
_urb
->
type
=
HCI_EVENT_PKT
;
_urb_queue_tail
(
__pending_q
(
husb
,
_urb
->
type
),
_urb
);
husb
->
intr_urb
=
urb
;
urb
=
&
_urb
->
urb
;
pipe
=
usb_rcvintpipe
(
husb
->
udev
,
husb
->
intr_in_ep
->
desc
.
bEndpointAddress
);
pipe
=
usb_rcvintpipe
(
husb
->
udev
,
husb
->
intr_ep
);
interval
=
husb
->
intr_in_ep
->
desc
.
bInterval
;
size
=
usb_maxpacket
(
husb
->
udev
,
pipe
,
usb_pipeout
(
pipe
));
usb_fill_int_urb
(
urb
,
husb
->
udev
,
pipe
,
buf
,
size
,
hci_usb_rx_complete
,
husb
,
interval
);
usb_fill_int_urb
(
urb
,
husb
->
udev
,
pipe
,
buf
,
size
,
hci_usb_interrupt
,
husb
,
husb
->
intr_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
_urb
*
_urb
;
struct
sk_buff
*
sk
b
;
struct
urb
*
ur
b
;
int
err
,
pipe
,
size
=
HCI_MAX_FRAME_SIZE
;
BT_DBG
(
"%s"
,
husb
->
hdev
.
name
)
;
void
*
buf
;
usb_unlink_urb
(
urb
);
usb_free_urb
(
urb
);
buf
=
kmalloc
(
size
,
GFP_ATOMIC
);
husb
->
intr_urb
=
NULL
;
if
(
!
buf
)
return
-
ENOMEM
;
skb
=
husb
->
intr_skb
;
_urb
=
_urb_alloc
(
0
,
GFP_ATOMIC
)
;
if
(
sk
b
)
{
if
(
!
_ur
b
)
{
husb
->
intr_skb
=
NULL
;
kfree
(
buf
)
;
kfree_skb
(
skb
)
;
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
_urb
*
_urb
;
struct
sk_buff
*
skb
;
struct
urb
*
urb
;
int
pipe
,
size
,
err
;
int
err
,
mtu
,
size
;
void
*
buf
;
if
(
!
urb
&&
!
(
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
)))
mtu
=
husb
->
isoc_in_ep
->
desc
.
wMaxPacketSize
;
return
-
ENOMEM
;
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
)))
{
_urb
=
_urb_alloc
(
HCI_MAX_ISOC_FRAMES
,
GFP_ATOMIC
);
usb_free_urb
(
urb
);
if
(
!
_urb
)
{
kfree
(
buf
);
return
-
ENOMEM
;
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
;
urb
->
context
=
husb
;
skb
->
pkt_type
=
HCI_ACLDATA_PKT
;
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
;
urb
->
transfer_buffer_length
=
size
;
scb
->
urb
=
urb
;
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
);
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
err
)
{
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
);
husb
->
hdev
.
name
,
urb
,
err
);
skb_unlink
(
skb
);
_urb_unlink
(
_urb
);
usb_free_urb
(
urb
);
_urb_free
(
_urb
);
kfree
(
buf
);
}
}
return
err
;
return
err
;
}
}
#endif
/* Initialize device */
/* Initialize device */
static
int
hci_usb_open
(
struct
hci_dev
*
hdev
)
static
int
hci_usb_open
(
struct
hci_dev
*
hdev
)
...
@@ -209,13 +296,17 @@ 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
);
write_lock_irqsave
(
&
husb
->
completion_lock
,
flags
);
err
=
hci_usb_
enable_intr
(
husb
);
err
=
hci_usb_
intr_rx_submit
(
husb
);
if
(
!
err
)
{
if
(
!
err
)
{
for
(
i
=
0
;
i
<
HCI_MAX_BULK_RX
;
i
++
)
for
(
i
=
0
;
i
<
HCI_MAX_BULK_RX
;
i
++
)
hci_usb_rx_submit
(
husb
,
NULL
);
hci_usb_bulk_rx_submit
(
husb
);
}
else
clear_bit
(
HCI_RUNNING
,
&
hdev
->
flags
);
#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
);
write_unlock_irqrestore
(
&
husb
->
completion_lock
,
flags
);
return
err
;
return
err
;
...
@@ -225,29 +316,52 @@ static int hci_usb_open(struct hci_dev *hdev)
...
@@ -225,29 +316,52 @@ static int hci_usb_open(struct hci_dev *hdev)
static
int
hci_usb_flush
(
struct
hci_dev
*
hdev
)
static
int
hci_usb_flush
(
struct
hci_dev
*
hdev
)
{
{
struct
hci_usb
*
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
struct
hci_usb
*
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
int
i
;
BT_DBG
(
"%s"
,
hdev
->
name
);
BT_DBG
(
"%s"
,
hdev
->
name
);
skb_queue_purge
(
&
husb
->
cmd_q
);
for
(
i
=
0
;
i
<
4
;
i
++
)
skb_queue_purge
(
&
husb
->
acl_q
);
skb_queue_purge
(
&
husb
->
transmit_q
[
i
]
);
return
0
;
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
;
int
i
;
struct
urb
*
urb
;
BT_DBG
(
"%s"
,
husb
->
hdev
.
name
);
BT_DBG
(
"%s"
,
husb
->
hdev
.
name
);
while
((
skb
=
skb_dequeue
(
&
husb
->
pending_q
)))
{
for
(
i
=
0
;
i
<
4
;
i
++
)
{
urb
=
((
struct
hci_usb_scb
*
)
skb
->
cb
)
->
urb
;
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
);
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
)))
/* Release reassembly buffers */
usb_free_urb
(
urb
);
if
(
husb
->
reassembly
[
i
])
{
kfree_skb
(
husb
->
reassembly
[
i
]);
husb
->
reassembly
[
i
]
=
NULL
;
}
}
}
}
/* Close device */
/* Close device */
...
@@ -263,7 +377,6 @@ static int hci_usb_close(struct hci_dev *hdev)
...
@@ -263,7 +377,6 @@ static int hci_usb_close(struct hci_dev *hdev)
write_lock_irqsave
(
&
husb
->
completion_lock
,
flags
);
write_lock_irqsave
(
&
husb
->
completion_lock
,
flags
);
hci_usb_disable_intr
(
husb
);
hci_usb_unlink_urbs
(
husb
);
hci_usb_unlink_urbs
(
husb
);
hci_usb_flush
(
hdev
);
hci_usb_flush
(
hdev
);
...
@@ -271,79 +384,123 @@ static int hci_usb_close(struct hci_dev *hdev)
...
@@ -271,79 +384,123 @@ static int hci_usb_close(struct hci_dev *hdev)
return
0
;
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
)
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
=
__get_completed
(
husb
,
skb
->
pkt_type
);
struct
urb
*
urb
=
hci_usb_get_completed
(
husb
);
struct
usb_ctrlrequest
*
dr
;
struct
usb_ctrlrequest
*
cr
;
struct
urb
*
urb
;
int
pipe
,
err
;
if
(
!
urb
&&
!
(
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
)))
if
(
!
_urb
)
{
_urb
=
_urb_alloc
(
0
,
GFP_ATOMIC
);
if
(
!
_urb
)
return
-
ENOMEM
;
return
-
ENOMEM
;
_urb
->
type
=
skb
->
pkt_type
;
if
(
!
(
cr
=
kmalloc
(
sizeof
(
*
cr
),
GFP_ATOMIC
)))
{
dr
=
kmalloc
(
sizeof
(
*
dr
),
GFP_ATOMIC
);
usb_free_urb
(
urb
);
if
(
!
dr
)
{
_urb_free
(
_urb
);
return
-
ENOMEM
;
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
;
urb
=
&
_urb
->
urb
;
cr
->
bRequest
=
0
;
usb_fill_control_urb
(
urb
,
husb
->
udev
,
usb_sndctrlpipe
(
husb
->
udev
,
0
),
cr
->
wIndex
=
0
;
(
void
*
)
dr
,
skb
->
data
,
skb
->
len
,
hci_usb_tx_complete
,
husb
);
cr
->
wValue
=
0
;
cr
->
wLength
=
__cpu_to_le16
(
skb
->
len
);
usb_fill_control_urb
(
urb
,
husb
->
udev
,
pipe
,
(
void
*
)
cr
,
BT_DBG
(
"%s skb %p len %d"
,
husb
->
hdev
.
name
,
skb
,
skb
->
len
);
skb
->
data
,
skb
->
len
,
hci_usb_tx_complete
,
skb
);
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
);
if
(
!
_urb
)
{
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
_urb
=
_urb_alloc
(
0
,
GFP_ATOMIC
);
if
(
err
)
{
if
(
!
_urb
)
BT_ERR
(
"%s ctrl tx submit failed urb %p err %d"
,
return
-
ENOMEM
;
husb
->
hdev
.
name
,
urb
,
err
);
_urb
->
type
=
skb
->
pkt_type
;
skb_unlink
(
skb
);
usb_free_urb
(
urb
);
kfree
(
cr
);
}
}
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
=
__get_completed
(
husb
,
skb
->
pkt_type
);
struct
urb
*
urb
=
hci_usb_get_completed
(
husb
);
struct
urb
*
urb
;
int
pipe
,
err
;
if
(
!
urb
&&
!
(
urb
=
usb_alloc_urb
(
0
,
GFP_ATOMIC
)))
if
(
!
_urb
)
{
_urb
=
_urb_alloc
(
HCI_MAX_ISOC_FRAMES
,
GFP_ATOMIC
);
if
(
!
_urb
)
return
-
ENOMEM
;
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
,
urb
=
&
_urb
->
urb
;
hci_usb_tx_complete
,
skb
);
urb
->
transfer_flags
=
URB_ZERO_PACKET
;
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
);
__fill_isoc_desc
(
urb
,
skb
->
len
,
husb
->
isoc_out_ep
->
desc
.
wMaxPacketSize
);
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
err
)
{
_urb
->
priv
=
skb
;
BT_ERR
(
"%s bulk tx submit failed urb %p err %d"
,
return
__tx_submit
(
husb
,
_urb
);
husb
->
hdev
.
name
,
urb
,
err
);
skb_unlink
(
skb
);
usb_free_urb
(
urb
);
}
return
err
;
}
}
#endif
static
void
hci_usb_tx_process
(
struct
hci_usb
*
husb
)
static
void
hci_usb_tx_process
(
struct
hci_usb
*
husb
)
{
{
struct
sk_buff_head
*
q
;
struct
sk_buff
*
skb
;
struct
sk_buff
*
skb
;
BT_DBG
(
"%s"
,
husb
->
hdev
.
name
);
BT_DBG
(
"%s"
,
husb
->
hdev
.
name
);
...
@@ -351,22 +508,31 @@ static void hci_usb_tx_process(struct hci_usb *husb)
...
@@ -351,22 +508,31 @@ static void hci_usb_tx_process(struct hci_usb *husb)
do
{
do
{
clear_bit
(
HCI_USB_TX_WAKEUP
,
&
husb
->
state
);
clear_bit
(
HCI_USB_TX_WAKEUP
,
&
husb
->
state
);
/* Process
ACL
queue */
/* Process
command
queue */
while
(
skb_queue_len
(
&
husb
->
pending_q
)
<
HCI_MAX_PENDING
&&
q
=
__transmit_q
(
husb
,
HCI_COMMAND_PKT
);
(
skb
=
skb_dequeue
(
&
husb
->
acl_q
)))
{
if
(
!
atomic_read
(
__pending_tx
(
husb
,
HCI_COMMAND_PKT
))
&&
if
(
hci_usb_send_bulk
(
husb
,
skb
)
<
0
)
{
(
skb
=
skb_dequeue
(
q
))
)
{
skb_queue_head
(
&
husb
->
acl_q
,
skb
);
if
(
hci_usb_send_ctrl
(
husb
,
skb
)
<
0
)
break
;
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 */
/* Process
ACL
queue */
if
(
!
test_bit
(
HCI_USB_CTRL_TX
,
&
husb
->
state
)
&&
q
=
__transmit_q
(
husb
,
HCI_ACLDATA_PKT
);
(
skb
=
skb_dequeue
(
&
husb
->
cmd_q
))
!=
NULL
)
{
while
(
atomic_read
(
__pending_tx
(
husb
,
HCI_ACLDATA_PKT
))
<
HCI_MAX_BULK_TX
&&
set_bit
(
HCI_USB_CTRL_TX
,
&
husb
->
state
);
(
skb
=
skb_dequeue
(
q
)))
{
if
(
hci_usb_send_
ctrl
(
husb
,
skb
)
<
0
)
{
if
(
hci_usb_send_
bulk
(
husb
,
skb
)
<
0
)
{
skb_queue_head
(
&
husb
->
cmd_
q
,
skb
);
skb_queue_head
(
q
,
skb
);
clear_bit
(
HCI_USB_CTRL_TX
,
&
husb
->
state
)
;
break
;
}
}
}
}
}
while
(
test_bit
(
HCI_USB_TX_WAKEUP
,
&
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)
...
@@ -383,7 +549,7 @@ static inline void hci_usb_tx_wakeup(struct hci_usb *husb)
}
}
/* Send frames from HCI layer */
/* 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_dev
*
hdev
=
(
struct
hci_dev
*
)
skb
->
dev
;
struct
hci_usb
*
husb
;
struct
hci_usb
*
husb
;
...
@@ -396,228 +562,206 @@ int hci_usb_send_frame(struct sk_buff *skb)
...
@@ -396,228 +562,206 @@ int hci_usb_send_frame(struct sk_buff *skb)
if
(
!
test_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
if
(
!
test_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
return
-
EBUSY
;
return
-
EBUSY
;
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
BT_DBG
(
"%s type %d len %d"
,
hdev
->
name
,
skb
->
pkt_type
,
skb
->
len
);
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
)
{
switch
(
skb
->
pkt_type
)
{
case
HCI_COMMAND_PKT
:
case
HCI_COMMAND_PKT
:
skb_queue_tail
(
&
husb
->
cmd_q
,
skb
);
hdev
->
stat
.
cmd_tx
++
;
hdev
->
stat
.
cmd_tx
++
;
break
;
break
;
case
HCI_ACLDATA_PKT
:
case
HCI_ACLDATA_PKT
:
skb_queue_tail
(
&
husb
->
acl_q
,
skb
);
hdev
->
stat
.
acl_tx
++
;
hdev
->
stat
.
acl_tx
++
;
break
;
break
;
#ifdef CONFIG_BT_USB_SCO
case
HCI_SCODATA_PKT
:
case
HCI_SCODATA_PKT
:
hdev
->
stat
.
sco_tx
++
;
break
;
#endif
default:
default:
kfree_skb
(
skb
);
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
);
hci_usb_tx_wakeup
(
husb
);
read_unlock
(
&
husb
->
completion_lock
);
read_unlock
(
&
husb
->
completion_lock
);
return
0
;
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
;
BT_DBG
(
"%s type %d data %p count %d"
,
husb
->
hdev
.
name
,
type
,
data
,
count
);
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
);
husb
->
hdev
.
stat
.
byte_rx
+=
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 */
/* Start of the frame */
if
(
count
<
HCI_EVENT_HDR_SIZE
)
goto
bad_len
;
eh
=
(
struct
hci_event_hdr
*
)
data
;
switch
(
type
)
{
len
=
eh
->
plen
+
HCI_EVENT_HDR_SIZE
;
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
)
case
HCI_ACLDATA_PKT
:
goto
bad_len
;
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
);
skb
=
bt_skb_alloc
(
len
,
GFP_ATOMIC
);
if
(
!
skb
)
{
if
(
!
skb
)
{
BT_ERR
(
"%s no memory for event
packet"
,
husb
->
hdev
.
name
);
BT_ERR
(
"%s no memory for the
packet"
,
husb
->
hdev
.
name
);
goto
done
;
return
-
ENOMEM
;
}
}
scb
=
(
void
*
)
skb
->
cb
;
skb
->
dev
=
(
void
*
)
&
husb
->
hdev
;
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
=
(
void
*
)
skb
->
c
b
;
scb
->
intr_len
=
len
;
scb
->
expect
=
len
;
}
else
{
}
else
{
/* Continuation */
/* Continuation */
scb
=
(
void
*
)
skb
->
cb
;
scb
=
(
void
*
)
skb
->
cb
;
len
=
scb
->
intr_len
;
len
=
scb
->
expect
;
if
(
count
>
len
)
{
husb
->
intr_skb
=
NULL
;
kfree_skb
(
skb
);
goto
bad_len
;
}
}
}
memcpy
(
skb_put
(
skb
,
count
),
data
,
count
);
len
=
min
(
len
,
count
);
scb
->
intr_len
-=
count
;
memcpy
(
skb_put
(
skb
,
len
),
data
,
len
);
if
(
!
scb
->
intr_len
)
{
scb
->
expect
-=
len
;
if
(
!
scb
->
expect
)
{
/* Complete frame */
/* Complete frame */
husb
->
intr_skb
=
NULL
;
__reassembly
(
husb
,
type
)
=
NULL
;
hci_recv_frame
(
skb
);
hci_recv_frame
(
skb
);
}
}
done:
count
-=
len
;
data
+=
len
;
read_unlock
(
&
husb
->
completion_lock
);
}
goto
exit
;
return
0
;
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_
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
_urb
*
_urb
=
container_of
(
urb
,
struct
_urb
,
urb
);
struct
hci_dev
*
hdev
=
(
struct
hci_dev
*
)
skb
->
dev
;
struct
hci_usb
*
husb
=
(
void
*
)
urb
->
context
;
struct
hci_usb
*
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
struct
hci_dev
*
hdev
=
&
husb
->
hdev
;
int
err
,
count
=
urb
->
actual_length
;
BT_DBG
(
"%s urb %p status %d flags %x"
,
husb
->
hdev
.
name
,
urb
,
urb
->
status
,
urb
->
transfer_flags
);
if
(
urb
->
pipe
==
usb_sndctrlpipe
(
husb
->
udev
,
0
))
{
BT_DBG
(
"%s urb %p type %d status %d count %d flags %x"
,
hdev
->
name
,
urb
,
kfree
(
urb
->
setup_packet
);
_urb
->
type
,
urb
->
status
,
count
,
urb
->
transfer_flags
);
clear_bit
(
HCI_USB_CTRL_TX
,
&
husb
->
state
);
}
if
(
!
test_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
if
(
!
test_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
return
;
return
;
read_lock
(
&
husb
->
completion_lock
);
read_lock
(
&
husb
->
completion_lock
);
if
(
!
urb
->
status
)
if
(
urb
->
status
||
!
count
)
husb
->
hdev
.
stat
.
byte_tx
+=
skb
->
len
;
goto
resubmit
;
else
husb
->
hdev
.
stat
.
err_tx
++
;
skb_unlink
(
skb
);
if
(
_urb
->
type
==
HCI_SCODATA_PKT
)
{
skb_queue_tail
(
&
husb
->
completed_q
,
skb
);
#ifdef CONFIG_BT_USB_SCO
hci_usb_tx_wakeup
(
husb
);
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
);
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
_urb
*
_urb
=
container_of
(
urb
,
struct
_urb
,
urb
);
struct
hci_dev
*
hdev
=
(
struct
hci_dev
*
)
skb
->
dev
;
struct
hci_usb
*
husb
=
(
void
*
)
urb
->
context
;
struct
hci_usb
*
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
struct
hci_dev
*
hdev
=
&
husb
->
hdev
;
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
))
BT_DBG
(
"%s urb %p status %d flags %x"
,
hdev
->
name
,
urb
,
return
;
urb
->
status
,
urb
->
transfer_flags
)
;
read_lock
(
&
husb
->
completion_lock
);
atomic_dec
(
__pending_tx
(
husb
,
_urb
->
type
)
);
if
(
urb
->
status
||
!
count
)
urb
->
transfer_buffer
=
NULL
;
goto
resubmit
;
kfree_skb
((
struct
sk_buff
*
)
_urb
->
priv
)
;
husb
->
hdev
.
stat
.
byte_rx
+=
count
;
if
(
!
test_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
return
;
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
(
!
urb
->
status
)
if
(
count
!=
size
)
{
hdev
->
stat
.
byte_tx
+=
urb
->
transfer_buffer_length
;
BT_ERR
(
"%s corrupted ACL packet: count %d, dlen %d"
,
else
husb
->
hdev
.
name
,
count
,
dlen
);
hdev
->
stat
.
err_tx
++
;
bt_dump
(
"hci_usb"
,
skb
->
data
,
count
);
husb
->
hdev
.
stat
.
err_rx
++
;
goto
resubmit
;
}
skb_unlink
(
skb
);
read_lock
(
&
husb
->
completion_lock
);
skb_put
(
skb
,
count
);
hci_recv_frame
(
skb
);
hci_usb_rx_submit
(
husb
,
urb
);
_urb_unlink
(
_urb
);
_urb_queue_tail
(
__completed_q
(
husb
,
_urb
->
type
),
_urb
);
read_unlock
(
&
husb
->
completion_lock
);
hci_usb_tx_wakeup
(
husb
);
return
;
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
);
read_unlock
(
&
husb
->
completion_lock
);
}
}
static
void
hci_usb_destruct
(
struct
hci_dev
*
hdev
)
static
void
hci_usb_destruct
(
struct
hci_dev
*
hdev
)
{
{
struct
hci_usb
*
husb
;
struct
hci_usb
*
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
if
(
!
hdev
)
return
;
BT_DBG
(
"%s"
,
hdev
->
name
);
BT_DBG
(
"%s"
,
hdev
->
name
);
husb
=
(
struct
hci_usb
*
)
hdev
->
driver_data
;
kfree
(
husb
);
kfree
(
husb
);
}
}
...
@@ -629,14 +773,16 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
...
@@ -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
*
bulk_in_ep
[
HCI_MAX_IFACE_NUM
];
struct
usb_host_endpoint
*
isoc_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
*
intr_in_ep
[
HCI_MAX_IFACE_NUM
];
struct
usb_host_interface
*
uif
;
struct
usb_host_endpoint
*
ep
;
struct
usb_host_endpoint
*
ep
;
struct
usb_host_interface
*
uif
;
struct
usb_interface
*
iface
,
*
isoc_iface
;
struct
usb_interface
*
iface
,
*
isoc_iface
;
struct
hci_usb
*
husb
;
struct
hci_usb
*
husb
;
struct
hci_dev
*
hdev
;
struct
hci_dev
*
hdev
;
int
i
,
a
,
e
,
size
,
ifn
,
isoc_ifnum
,
isoc_alts
;
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 */
/* Check our black list */
if
(
usb_match_id
(
intf
,
ignore_ids
))
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)
...
@@ -679,6 +825,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
bulk_out_ep
[
i
]
=
ep
;
bulk_out_ep
[
i
]
=
ep
;
break
;
break
;
#ifdef CONFIG_BT_USB_SCO
case
USB_ENDPOINT_XFER_ISOC
:
case
USB_ENDPOINT_XFER_ISOC
:
if
(
ep
->
desc
.
wMaxPacketSize
<
size
)
if
(
ep
->
desc
.
wMaxPacketSize
<
size
)
break
;
break
;
...
@@ -693,6 +840,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
...
@@ -693,6 +840,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
else
else
isoc_out_ep
[
i
]
=
ep
;
isoc_out_ep
[
i
]
=
ep
;
break
;
break
;
#endif
}
}
}
}
}
}
...
@@ -703,10 +851,12 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
...
@@ -703,10 +851,12 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
goto
done
;
goto
done
;
}
}
#ifdef CONFIG_BT_USB_SCO
if
(
!
isoc_in_ep
[
1
]
||
!
isoc_out_ep
[
1
])
{
if
(
!
isoc_in_ep
[
1
]
||
!
isoc_out_ep
[
1
])
{
BT_DBG
(
"Isoc endpoints not found"
);
BT_DBG
(
"Isoc endpoints not found"
);
isoc_iface
=
NULL
;
isoc_iface
=
NULL
;
}
}
#endif
if
(
!
(
husb
=
kmalloc
(
sizeof
(
struct
hci_usb
),
GFP_KERNEL
)))
{
if
(
!
(
husb
=
kmalloc
(
sizeof
(
struct
hci_usb
),
GFP_KERNEL
)))
{
BT_ERR
(
"Can't allocate: control structure"
);
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)
...
@@ -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
));
memset
(
husb
,
0
,
sizeof
(
struct
hci_usb
));
husb
->
udev
=
udev
;
husb
->
udev
=
udev
;
husb
->
bulk_out_ep
=
bulk_out_ep
[
0
]
->
desc
.
bEndpointAddress
;
husb
->
bulk_out_ep
=
bulk_out_ep
[
0
];
husb
->
bulk_in_ep
=
bulk_in_ep
[
0
]
->
desc
.
bEndpointAddress
;
husb
->
bulk_in_ep
=
bulk_in_ep
[
0
];
husb
->
intr_in_ep
=
intr_in_ep
[
0
];
husb
->
intr_ep
=
intr_in_ep
[
0
]
->
desc
.
bEndpointAddress
;
husb
->
intr_interval
=
intr_in_ep
[
0
]
->
desc
.
bInterval
;
#ifdef CONFIG_BT_USB_SCO
if
(
isoc_iface
)
{
if
(
isoc_iface
)
{
BT_DBG
(
"isoc ifnum %d alts %d"
,
isoc_ifnum
,
isoc_alts
);
if
(
usb_set_interface
(
udev
,
isoc_ifnum
,
isoc_alts
))
{
if
(
usb_set_interface
(
udev
,
isoc_ifnum
,
isoc_alts
))
{
BT_ERR
(
"Can't set isoc interface settings"
);
BT_ERR
(
"Can't set isoc interface settings"
);
isoc_iface
=
NULL
;
isoc_iface
=
NULL
;
}
}
usb_driver_claim_interface
(
&
hci_usb_driver
,
isoc_iface
,
husb
);
usb_driver_claim_interface
(
&
hci_usb_driver
,
isoc_iface
,
husb
);
husb
->
isoc_iface
=
isoc_iface
;
husb
->
isoc_iface
=
isoc_iface
;
husb
->
isoc_in_ep
=
isoc_in_ep
[
isoc_ifnum
];
husb
->
isoc_in_ep
=
isoc_in_ep
[
1
]
->
desc
.
bEndpointAddress
;
husb
->
isoc_out_ep
=
isoc_out_ep
[
isoc_ifnum
];
husb
->
isoc_out_ep
=
isoc_in_ep
[
1
]
->
desc
.
bEndpointAddress
;
}
}
#endif
husb
->
completion_lock
=
RW_LOCK_UNLOCKED
;
husb
->
completion_lock
=
RW_LOCK_UNLOCKED
;
skb_queue_head_init
(
&
husb
->
acl_q
);
for
(
i
=
0
;
i
<
4
;
i
++
)
{
skb_queue_head_init
(
&
husb
->
cmd_q
);
skb_queue_head_init
(
&
husb
->
transmit_q
[
i
]);
skb_queue_head_init
(
&
husb
->
pending_q
);
_urb_queue_init
(
&
husb
->
pending_q
[
i
]);
skb_queue_head_init
(
&
husb
->
completed_q
);
_urb_queue_init
(
&
husb
->
completed_q
[
i
]);
}
/* Initialize and register HCI device */
/* Initialize and register HCI device */
hdev
=
&
husb
->
hdev
;
hdev
=
&
husb
->
hdev
;
...
@@ -773,13 +924,12 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
...
@@ -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
)
static
void
hci_usb_disconnect
(
struct
usb_interface
*
intf
)
{
{
struct
hci_usb
*
husb
=
usb_get_intfdata
(
intf
);
struct
hci_usb
*
husb
=
usb_get_intfdata
(
intf
);
struct
hci_dev
*
hdev
;
struct
hci_dev
*
hdev
=
&
husb
->
hdev
;
if
(
!
husb
)
if
(
!
husb
)
return
;
return
;
usb_set_intfdata
(
intf
,
NULL
);
usb_set_intfdata
(
intf
,
NULL
);
hdev
=
&
husb
->
hdev
;
BT_DBG
(
"%s"
,
hdev
->
name
);
BT_DBG
(
"%s"
,
hdev
->
name
);
hci_usb_close
(
hdev
);
hci_usb_close
(
hdev
);
...
@@ -795,14 +945,16 @@ static struct usb_driver hci_usb_driver = {
...
@@ -795,14 +945,16 @@ static struct usb_driver hci_usb_driver = {
.
name
=
"hci_usb"
,
.
name
=
"hci_usb"
,
.
probe
=
hci_usb_probe
,
.
probe
=
hci_usb_probe
,
.
disconnect
=
hci_usb_disconnect
,
.
disconnect
=
hci_usb_disconnect
,
.
id_table
=
bluetooth_ids
.
id_table
=
bluetooth_ids
,
};
};
int
hci_usb_init
(
void
)
int
hci_usb_init
(
void
)
{
{
int
err
;
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
)
if
((
err
=
usb_register
(
&
hci_usb_driver
))
<
0
)
BT_ERR
(
"Failed to register HCI USB driver"
);
BT_ERR
(
"Failed to register HCI USB driver"
);
...
@@ -819,5 +971,5 @@ module_init(hci_usb_init);
...
@@ -819,5 +971,5 @@ module_init(hci_usb_init);
module_exit
(
hci_usb_cleanup
);
module_exit
(
hci_usb_cleanup
);
MODULE_AUTHOR
(
"Maxim Krasnyansky <maxk@qualcomm.com>"
);
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"
);
MODULE_LICENSE
(
"GPL"
);
drivers/bluetooth/hci_usb.h
View file @
76d53202
/*
/*
BlueZ - Bluetooth protocol stack for Linux
HCI USB driver for Linux Bluetooth protocol stack (BlueZ)
Copyright (C) 2000-2001 Qualcomm Incorporated
Copyright (C) 2000-2001 Qualcomm Incorporated
Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
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
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
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation;
published by the Free Software Foundation;
...
@@ -40,40 +41,96 @@
...
@@ -40,40 +41,96 @@
#define HCI_MAX_BULK_TX 4
#define HCI_MAX_BULK_TX 4
#define HCI_MAX_BULK_RX 1
#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_usb
{
struct
hci_dev
hdev
;
struct
hci_dev
hdev
;
unsigned
long
state
;
unsigned
long
state
;
struct
usb_device
*
udev
;
struct
usb_device
*
udev
;
struct
usb_interface
*
isoc_iface
;
__u8
bulk_out_ep
;
struct
usb_host_endpoint
*
bulk_in_ep
;
__u8
bulk_in_ep
;
struct
usb_host_endpoint
*
bulk_out_ep
;
__u8
isoc_out_ep
;
struct
usb_host_endpoint
*
intr_in_ep
;
__u8
isoc_in_ep
;
struct
usb_interface
*
isoc_iface
;
struct
usb_host_endpoint
*
isoc_out_ep
;
struct
usb_host_endpoint
*
isoc_in_ep
;
__u8
intr_ep
;
struct
sk_buff_head
transmit_q
[
4
];
__u8
intr_interval
;
struct
sk_buff
*
reassembly
[
4
];
// Reassembly buffers
struct
urb
*
intr_urb
;
struct
sk_buff
*
intr_skb
;
rwlock_t
completion_lock
;
rwlock_t
completion_lock
;
struct
sk_buff_head
cmd_q
;
// TX Commands
atomic_t
pending_tx
[
4
];
// Number of pending requests
struct
sk_buff_head
acl_q
;
// TX ACLs
struct
_urb_queue
pending_q
[
4
];
// Pending requests
struct
sk_buff_head
pending_q
;
// Pending requests
struct
_urb_queue
completed_q
[
4
];
// Completed requests
struct
sk_buff_head
completed_q
;
// Completed requests
};
struct
hci_usb_scb
{
struct
urb
*
urb
;
int
intr_len
;
};
};
/* States */
/* States */
#define HCI_USB_TX_PROCESS 1
#define HCI_USB_TX_PROCESS 1
#define HCI_USB_TX_WAKEUP 2
#define HCI_USB_TX_WAKEUP 2
#define HCI_USB_CTRL_TX 3
#endif
/* __KERNEL__ */
#endif
/* __KERNEL__ */
include/net/bluetooth/hci_core.h
View file @
76d53202
...
@@ -262,7 +262,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *src);
...
@@ -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_auth
(
struct
hci_conn
*
conn
);
int
hci_conn_encrypt
(
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
);
mod_timer
(
&
conn
->
timer
,
jiffies
+
timeout
);
}
}
...
@@ -280,8 +280,12 @@ static inline void hci_conn_hold(struct hci_conn *conn)
...
@@ -280,8 +280,12 @@ static inline void hci_conn_hold(struct hci_conn *conn)
static
inline
void
hci_conn_put
(
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_conn_set_timer
(
conn
,
HCI_DISCONN_TIMEOUT
);
}
}
}
/* ----- HCI tasks ----- */
/* ----- HCI tasks ----- */
...
...
include/net/bluetooth/rfcomm.h
View file @
76d53202
...
@@ -146,6 +146,11 @@ struct rfcomm_rpn {
...
@@ -146,6 +146,11 @@ struct rfcomm_rpn {
u16
param_mask
;
u16
param_mask
;
}
__attribute__
((
packed
));
}
__attribute__
((
packed
));
struct
rfcomm_rls
{
u8
dlci
;
u8
status
;
}
__attribute__
((
packed
));
struct
rfcomm_msc
{
struct
rfcomm_msc
{
u8
dlci
;
u8
dlci
;
u8
v24_sig
;
u8
v24_sig
;
...
...
net/bluetooth/hci_conn.c
View file @
76d53202
...
@@ -71,6 +71,7 @@ void hci_acl_connect(struct hci_conn *conn)
...
@@ -71,6 +71,7 @@ void hci_acl_connect(struct hci_conn *conn)
memset
(
&
cp
,
0
,
sizeof
(
cp
));
memset
(
&
cp
,
0
,
sizeof
(
cp
));
bacpy
(
&
cp
.
bdaddr
,
&
conn
->
dst
);
bacpy
(
&
cp
.
bdaddr
,
&
conn
->
dst
);
cp
.
pscan_rep_mode
=
0x01
;
if
((
ie
=
inquiry_cache_lookup
(
hdev
,
&
conn
->
dst
))
&&
if
((
ie
=
inquiry_cache_lookup
(
hdev
,
&
conn
->
dst
))
&&
inquiry_entry_age
(
ie
)
<=
INQUIRY_ENTRY_AGE_MAX
)
{
inquiry_entry_age
(
ie
)
<=
INQUIRY_ENTRY_AGE_MAX
)
{
...
...
net/bluetooth/rfcomm/core.c
View file @
76d53202
...
@@ -798,6 +798,33 @@ static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
...
@@ -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
);
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
)
static
int
rfcomm_send_msc
(
struct
rfcomm_session
*
s
,
int
cr
,
u8
dlci
,
u8
v24_sig
)
{
{
struct
rfcomm_hdr
*
hdr
;
struct
rfcomm_hdr
*
hdr
;
...
@@ -1229,6 +1256,26 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
...
@@ -1229,6 +1256,26 @@ static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_
return
0
;
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
)
static
int
rfcomm_recv_msc
(
struct
rfcomm_session
*
s
,
int
cr
,
struct
sk_buff
*
skb
)
{
{
struct
rfcomm_msc
*
msc
=
(
void
*
)
skb
->
data
;
struct
rfcomm_msc
*
msc
=
(
void
*
)
skb
->
data
;
...
@@ -1279,6 +1326,10 @@ static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
...
@@ -1279,6 +1326,10 @@ static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb)
rfcomm_recv_rpn
(
s
,
cr
,
len
,
skb
);
rfcomm_recv_rpn
(
s
,
cr
,
len
,
skb
);
break
;
break
;
case
RFCOMM_RLS
:
rfcomm_recv_rls
(
s
,
cr
,
skb
);
break
;
case
RFCOMM_MSC
:
case
RFCOMM_MSC
:
rfcomm_recv_msc
(
s
,
cr
,
skb
);
rfcomm_recv_msc
(
s
,
cr
,
skb
);
break
;
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