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
e55dbfb1
Commit
e55dbfb1
authored
Feb 06, 2005
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://gkernel.bkbits.net/misc-2.6
into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents
bad53498
7ac1bc3e
Changes
26
Show whitespace changes
Inline
Side-by-side
Showing
26 changed files
with
874 additions
and
63 deletions
+874
-63
Documentation/atomic_ops.txt
Documentation/atomic_ops.txt
+111
-2
arch/i386/crypto/aes.c
arch/i386/crypto/aes.c
+3
-3
arch/sparc64/lib/debuglocks.c
arch/sparc64/lib/debuglocks.c
+2
-0
drivers/atm/horizon.c
drivers/atm/horizon.c
+6
-7
drivers/atm/iphase.c
drivers/atm/iphase.c
+12
-14
drivers/atm/zatm.c
drivers/atm/zatm.c
+9
-18
drivers/bluetooth/Kconfig
drivers/bluetooth/Kconfig
+11
-0
drivers/bluetooth/Makefile
drivers/bluetooth/Makefile
+1
-0
drivers/bluetooth/bpa10x.c
drivers/bluetooth/bpa10x.c
+657
-0
drivers/bluetooth/hci_usb.c
drivers/bluetooth/hci_usb.c
+14
-3
drivers/bluetooth/hci_usb.h
drivers/bluetooth/hci_usb.h
+1
-0
include/asm-sparc64/spinlock.h
include/asm-sparc64/spinlock.h
+2
-1
include/asm-sparc64/system.h
include/asm-sparc64/system.h
+6
-2
include/linux/netfilter_ipv4/ip_conntrack_tcp.h
include/linux/netfilter_ipv4/ip_conntrack_tcp.h
+1
-0
include/linux/netfilter_ipv4/ip_conntrack_tuple.h
include/linux/netfilter_ipv4/ip_conntrack_tuple.h
+2
-2
include/linux/netlink.h
include/linux/netlink.h
+2
-3
include/net/bluetooth/hci_core.h
include/net/bluetooth/hci_core.h
+2
-0
net/bluetooth/hci_core.c
net/bluetooth/hci_core.c
+16
-0
net/ipv4/ipconfig.c
net/ipv4/ipconfig.c
+1
-1
net/ipv4/netfilter/ip_conntrack_ftp.c
net/ipv4/netfilter/ip_conntrack_ftp.c
+3
-4
net/ipv4/netfilter/ip_conntrack_proto_tcp.c
net/ipv4/netfilter/ip_conntrack_proto_tcp.c
+2
-0
net/ipv4/netfilter/ip_nat_core.c
net/ipv4/netfilter/ip_nat_core.c
+1
-0
net/ipv4/netfilter/ipt_hashlimit.c
net/ipv4/netfilter/ipt_hashlimit.c
+1
-1
net/ipv6/ip6_tunnel.c
net/ipv6/ip6_tunnel.c
+2
-2
net/sched/ipt.c
net/sched/ipt.c
+5
-0
net/sched/sch_netem.c
net/sched/sch_netem.c
+1
-0
No files found.
Documentation/atomic_ops.txt
View file @
e55dbfb1
...
@@ -4,8 +4,8 @@
...
@@ -4,8 +4,8 @@
David S. Miller
David S. Miller
This document is intended to serve as a guide to Linux port
This document is intended to serve as a guide to Linux port
maintainers on how to implement atomic counter
and bitops interfaces
maintainers on how to implement atomic counter
, bitops, and spinlock
properly.
interfaces
properly.
The atomic_t type should be defined as a signed integer.
The atomic_t type should be defined as a signed integer.
Also, it should be made opaque such that any kind of cast to a normal
Also, it should be made opaque such that any kind of cast to a normal
...
@@ -242,6 +242,19 @@ happen. Specifically, in the above case the atomic_dec_and_test()
...
@@ -242,6 +242,19 @@ happen. Specifically, in the above case the atomic_dec_and_test()
counter decrement would not become globally visible until the
counter decrement would not become globally visible until the
obj->active update does.
obj->active update does.
As a historical note, 32-bit Sparc used to only allow usage of
24-bits of it's atomic_t type. This was because it used 8 bits
as a spinlock for SMP safety. Sparc32 lacked a "compare and swap"
type instruction. However, 32-bit Sparc has since been moved over
to a "hash table of spinlocks" scheme, that allows the full 32-bit
counter to be realized. Essentially, an array of spinlocks are
indexed into based upon the address of the atomic_t being operated
on, and that lock protects the atomic operation. Parisc uses the
same scheme.
Another note is that the atomic_t operations returning values are
extremely slow on an old 386.
We will now cover the atomic bitmask operations. You will find that
We will now cover the atomic bitmask operations. You will find that
their SMP and memory barrier semantics are similar in shape and scope
their SMP and memory barrier semantics are similar in shape and scope
to the atomic_t ops above.
to the atomic_t ops above.
...
@@ -345,3 +358,99 @@ except that two underscores are prefixed to the interface name.
...
@@ -345,3 +358,99 @@ except that two underscores are prefixed to the interface name.
These non-atomic variants also do not require any special memory
These non-atomic variants also do not require any special memory
barrier semantics.
barrier semantics.
The routines xchg() and cmpxchg() need the same exact memory barriers
as the atomic and bit operations returning values.
Spinlocks and rwlocks have memory barrier expectations as well.
The rule to follow is simple:
1) When acquiring a lock, the implementation must make it globally
visible before any subsequent memory operation.
2) When releasing a lock, the implementation must make it such that
all previous memory operations are globally visible before the
lock release.
Which finally brings us to _atomic_dec_and_lock(). There is an
architecture-neutral version implemented in lib/dec_and_lock.c,
but most platforms will wish to optimize this in assembler.
int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock);
Atomically decrement the given counter, and if will drop to zero
atomically acquire the given spinlock and perform the decrement
of the counter to zero. If it does not drop to zero, do nothing
with the spinlock.
It is actually pretty simple to get the memory barrier correct.
Simply satisfy the spinlock grab requirements, which is make
sure the spinlock operation is globally visible before any
subsequent memory operation.
We can demonstrate this operation more clearly if we define
an abstract atomic operation:
long cas(long *mem, long old, long new);
"cas" stands for "compare and swap". It atomically:
1) Compares "old" with the value currently at "mem".
2) If they are equal, "new" is written to "mem".
3) Regardless, the current value at "mem" is returned.
As an example usage, here is what an atomic counter update
might look like:
void example_atomic_inc(long *counter)
{
long old, new, ret;
while (1) {
old = *counter;
new = old + 1;
ret = cas(counter, old, new);
if (ret == old)
break;
}
}
Let's use cas() in order to build a pseudo-C atomic_dec_and_lock():
int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock)
{
long old, new, ret;
int went_to_zero;
went_to_zero = 0;
while (1) {
old = atomic_read(atomic);
new = old - 1;
if (new == 0) {
went_to_zero = 1;
spin_lock(lock);
}
ret = cas(atomic, old, new);
if (ret == old)
break;
if (went_to_zero) {
spin_unlock(lock);
went_to_zero = 0;
}
}
return went_to_zero;
}
Now, as far as memory barriers go, as long as spin_lock()
strictly orders all subsequent memory operations (including
the cas()) with respect to itself, things will be fine.
Said another way, _atomic_dec_and_lock() must guarentee that
a counter dropping to zero is never made visible before the
spinlock being acquired.
Note that this also means that for the case where the counter
is not dropping to zero, there are no memory ordering
requirements.
arch/i386/crypto/aes.c
View file @
e55dbfb1
...
@@ -93,12 +93,12 @@ static u32 rcon_tab[RC_LENGTH];
...
@@ -93,12 +93,12 @@ static u32 rcon_tab[RC_LENGTH];
u32
ft_tab
[
4
][
256
];
u32
ft_tab
[
4
][
256
];
u32
fl_tab
[
4
][
256
];
u32
fl_tab
[
4
][
256
];
u32
ls_tab
[
4
][
256
];
static
u32
ls_tab
[
4
][
256
];
u32
im_tab
[
4
][
256
];
static
u32
im_tab
[
4
][
256
];
u32
il_tab
[
4
][
256
];
u32
il_tab
[
4
][
256
];
u32
it_tab
[
4
][
256
];
u32
it_tab
[
4
][
256
];
void
gen_tabs
(
void
)
static
void
gen_tabs
(
void
)
{
{
u32
i
,
w
;
u32
i
,
w
;
u8
pow
[
512
],
log
[
256
];
u8
pow
[
512
],
log
[
256
];
...
...
arch/sparc64/lib/debuglocks.c
View file @
e55dbfb1
...
@@ -172,6 +172,7 @@ void _do_read_unlock (rwlock_t *rw, char *str)
...
@@ -172,6 +172,7 @@ void _do_read_unlock (rwlock_t *rw, char *str)
runlock_again:
runlock_again:
/* Spin trying to decrement the counter using casx. */
/* Spin trying to decrement the counter using casx. */
__asm__
__volatile__
(
__asm__
__volatile__
(
" membar #StoreLoad | #LoadLoad
\n
"
" ldx [%0], %%g5
\n
"
" ldx [%0], %%g5
\n
"
" sub %%g5, 1, %%g7
\n
"
" sub %%g5, 1, %%g7
\n
"
" casx [%0], %%g5, %%g7
\n
"
" casx [%0], %%g5, %%g7
\n
"
...
@@ -290,6 +291,7 @@ void _do_write_unlock(rwlock_t *rw)
...
@@ -290,6 +291,7 @@ void _do_write_unlock(rwlock_t *rw)
current
->
thread
.
smp_lock_count
--
;
current
->
thread
.
smp_lock_count
--
;
wlock_again:
wlock_again:
__asm__
__volatile__
(
__asm__
__volatile__
(
" membar #StoreLoad | #LoadLoad
\n
"
" mov 1, %%g3
\n
"
" mov 1, %%g3
\n
"
" sllx %%g3, 63, %%g3
\n
"
" sllx %%g3, 63, %%g3
\n
"
" ldx [%0], %%g5
\n
"
" ldx [%0], %%g5
\n
"
...
...
drivers/atm/horizon.c
View file @
e55dbfb1
...
@@ -39,6 +39,7 @@
...
@@ -39,6 +39,7 @@
#include <linux/uio.h>
#include <linux/uio.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/ioport.h>
#include <linux/wait.h>
#include <asm/system.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/io.h>
...
@@ -1089,13 +1090,11 @@ static inline void rx_bus_master_complete_handler (hrz_dev * dev) {
...
@@ -1089,13 +1090,11 @@ static inline void rx_bus_master_complete_handler (hrz_dev * dev) {
/********** (queue to) become the next TX thread **********/
/********** (queue to) become the next TX thread **********/
static
inline
int
tx_hold
(
hrz_dev
*
dev
)
{
static
inline
int
tx_hold
(
hrz_dev
*
dev
)
{
while
(
test_and_set_bit
(
tx_busy
,
&
dev
->
flags
))
{
PRINTD
(
DBG_TX
,
"sleeping at tx lock %p %lu"
,
dev
,
dev
->
flags
);
PRINTD
(
DBG_TX
,
"sleeping at tx lock %p %lu"
,
dev
,
dev
->
flags
);
interruptible_sleep_on
(
&
dev
->
tx_queue
);
wait_event_interruptible
(
dev
->
tx_queue
,
(
!
test_and_set_bit
(
tx_busy
,
&
dev
->
flags
))
);
PRINTD
(
DBG_TX
,
"woken at tx lock %p %lu"
,
dev
,
dev
->
flags
);
PRINTD
(
DBG_TX
,
"woken at tx lock %p %lu"
,
dev
,
dev
->
flags
);
if
(
signal_pending
(
current
))
if
(
signal_pending
(
current
))
return
-
1
;
return
-
1
;
}
PRINTD
(
DBG_TX
,
"set tx_busy for dev %p"
,
dev
);
PRINTD
(
DBG_TX
,
"set tx_busy for dev %p"
,
dev
);
return
0
;
return
0
;
}
}
...
...
drivers/atm/iphase.c
View file @
e55dbfb1
...
@@ -53,6 +53,7 @@
...
@@ -53,6 +53,7 @@
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/uio.h>
#include <linux/uio.h>
#include <linux/init.h>
#include <linux/init.h>
#include <linux/wait.h>
#include <asm/system.h>
#include <asm/system.h>
#include <asm/io.h>
#include <asm/io.h>
#include <asm/atomic.h>
#include <asm/atomic.h>
...
@@ -2587,13 +2588,13 @@ static int __init ia_start(struct atm_dev *dev)
...
@@ -2587,13 +2588,13 @@ static int __init ia_start(struct atm_dev *dev)
static
void
ia_close
(
struct
atm_vcc
*
vcc
)
static
void
ia_close
(
struct
atm_vcc
*
vcc
)
{
{
DEFINE_WAIT
(
wait
);
u16
*
vc_table
;
u16
*
vc_table
;
IADEV
*
iadev
;
IADEV
*
iadev
;
struct
ia_vcc
*
ia_vcc
;
struct
ia_vcc
*
ia_vcc
;
struct
sk_buff
*
skb
=
NULL
;
struct
sk_buff
*
skb
=
NULL
;
struct
sk_buff_head
tmp_tx_backlog
,
tmp_vcc_backlog
;
struct
sk_buff_head
tmp_tx_backlog
,
tmp_vcc_backlog
;
unsigned
long
closetime
,
flags
;
unsigned
long
closetime
,
flags
;
int
ctimeout
;
iadev
=
INPH_IA_DEV
(
vcc
->
dev
);
iadev
=
INPH_IA_DEV
(
vcc
->
dev
);
ia_vcc
=
INPH_IA_VCC
(
vcc
);
ia_vcc
=
INPH_IA_VCC
(
vcc
);
...
@@ -2606,7 +2607,9 @@ static void ia_close(struct atm_vcc *vcc)
...
@@ -2606,7 +2607,9 @@ static void ia_close(struct atm_vcc *vcc)
skb_queue_head_init
(
&
tmp_vcc_backlog
);
skb_queue_head_init
(
&
tmp_vcc_backlog
);
if
(
vcc
->
qos
.
txtp
.
traffic_class
!=
ATM_NONE
)
{
if
(
vcc
->
qos
.
txtp
.
traffic_class
!=
ATM_NONE
)
{
iadev
->
close_pending
++
;
iadev
->
close_pending
++
;
sleep_on_timeout
(
&
iadev
->
timeout_wait
,
50
);
prepare_to_wait
(
&
iadev
->
timeout_wait
,
&
wait
,
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
50
);
finish_wait
(
&
iadev
->
timeout_wait
,
&
wait
);
spin_lock_irqsave
(
&
iadev
->
tx_lock
,
flags
);
spin_lock_irqsave
(
&
iadev
->
tx_lock
,
flags
);
while
((
skb
=
skb_dequeue
(
&
iadev
->
tx_backlog
)))
{
while
((
skb
=
skb_dequeue
(
&
iadev
->
tx_backlog
)))
{
if
(
ATM_SKB
(
skb
)
->
vcc
==
vcc
){
if
(
ATM_SKB
(
skb
)
->
vcc
==
vcc
){
...
@@ -2619,17 +2622,12 @@ static void ia_close(struct atm_vcc *vcc)
...
@@ -2619,17 +2622,12 @@ static void ia_close(struct atm_vcc *vcc)
while
((
skb
=
skb_dequeue
(
&
tmp_tx_backlog
)))
while
((
skb
=
skb_dequeue
(
&
tmp_tx_backlog
)))
skb_queue_tail
(
&
iadev
->
tx_backlog
,
skb
);
skb_queue_tail
(
&
iadev
->
tx_backlog
,
skb
);
IF_EVENT
(
printk
(
"IA TX Done decs_cnt = %d
\n
"
,
ia_vcc
->
vc_desc_cnt
);)
IF_EVENT
(
printk
(
"IA TX Done decs_cnt = %d
\n
"
,
ia_vcc
->
vc_desc_cnt
);)
closetime
=
jiffies
;
closetime
=
300000
/
ia_vcc
->
pcr
;
ctimeout
=
300000
/
ia_vcc
->
pcr
;
if
(
closetime
==
0
)
if
(
ctimeout
==
0
)
closetime
=
1
;
ctimeout
=
1
;
while
(
ia_vcc
->
vc_desc_cnt
>
0
){
if
((
jiffies
-
closetime
)
>=
ctimeout
)
break
;
spin_unlock_irqrestore
(
&
iadev
->
tx_lock
,
flags
);
spin_unlock_irqrestore
(
&
iadev
->
tx_lock
,
flags
);
sleep_on
(
&
iadev
->
close_wait
);
wait_event_timeout
(
iadev
->
close_wait
,
(
ia_vcc
->
vc_desc_cnt
<=
0
),
closetime
);
spin_lock_irqsave
(
&
iadev
->
tx_lock
,
flags
);
spin_lock_irqsave
(
&
iadev
->
tx_lock
,
flags
);
}
iadev
->
close_pending
--
;
iadev
->
close_pending
--
;
iadev
->
testTable
[
vcc
->
vci
]
->
lastTime
=
0
;
iadev
->
testTable
[
vcc
->
vci
]
->
lastTime
=
0
;
iadev
->
testTable
[
vcc
->
vci
]
->
fract
=
0
;
iadev
->
testTable
[
vcc
->
vci
]
->
fract
=
0
;
...
...
drivers/atm/zatm.c
View file @
e55dbfb1
...
@@ -22,6 +22,7 @@
...
@@ -22,6 +22,7 @@
#include <linux/atm_zatm.h>
#include <linux/atm_zatm.h>
#include <linux/capability.h>
#include <linux/capability.h>
#include <linux/bitops.h>
#include <linux/bitops.h>
#include <linux/wait.h>
#include <asm/byteorder.h>
#include <asm/byteorder.h>
#include <asm/system.h>
#include <asm/system.h>
#include <asm/string.h>
#include <asm/string.h>
...
@@ -867,31 +868,21 @@ static void close_tx(struct atm_vcc *vcc)
...
@@ -867,31 +868,21 @@ static void close_tx(struct atm_vcc *vcc)
struct
zatm_vcc
*
zatm_vcc
;
struct
zatm_vcc
*
zatm_vcc
;
unsigned
long
flags
;
unsigned
long
flags
;
int
chan
;
int
chan
;
struct
sk_buff
*
skb
;
int
once
=
1
;
zatm_vcc
=
ZATM_VCC
(
vcc
);
zatm_vcc
=
ZATM_VCC
(
vcc
);
zatm_dev
=
ZATM_DEV
(
vcc
->
dev
);
zatm_dev
=
ZATM_DEV
(
vcc
->
dev
);
chan
=
zatm_vcc
->
tx_chan
;
chan
=
zatm_vcc
->
tx_chan
;
if
(
!
chan
)
return
;
if
(
!
chan
)
return
;
DPRINTK
(
"close_tx
\n
"
);
DPRINTK
(
"close_tx
\n
"
);
while
(
skb_peek
(
&
zatm_vcc
->
backlog
))
{
if
(
skb_peek
(
&
zatm_vcc
->
backlog
))
{
if
(
once
)
{
printk
(
"waiting for backlog to drain ...
\n
"
);
printk
(
"waiting for backlog to drain ...
\n
"
);
event_dump
();
event_dump
();
wait_event
(
zatm_vcc
->
tx_wait
,
!
skb_peek
(
&
zatm_vcc
->
backlog
));
once
=
0
;
}
}
if
(
skb_peek
(
&
zatm_vcc
->
tx_queue
))
{
sleep_on
(
&
zatm_vcc
->
tx_wait
);
printk
(
"waiting for TX queue to drain ...
\n
"
);
}
event_dump
();
once
=
1
;
wait_event
(
zatm_vcc
->
tx_wait
,
!
skb_peek
(
&
zatm_vcc
->
tx_queue
));
while
((
skb
=
skb_peek
(
&
zatm_vcc
->
tx_queue
)))
{
if
(
once
)
{
printk
(
"waiting for TX queue to drain ... %p
\n
"
,
skb
);
event_dump
();
once
=
0
;
}
DPRINTK
(
"waiting for TX queue to drain ... %p
\n
"
,
skb
);
sleep_on
(
&
zatm_vcc
->
tx_wait
);
}
}
spin_lock_irqsave
(
&
zatm_dev
->
lock
,
flags
);
spin_lock_irqsave
(
&
zatm_dev
->
lock
,
flags
);
#if 0
#if 0
...
...
drivers/bluetooth/Kconfig
View file @
e55dbfb1
...
@@ -75,6 +75,17 @@ config BT_HCIBCM203X
...
@@ -75,6 +75,17 @@ config BT_HCIBCM203X
Say Y here to compile support for HCI BCM203x devices into the
Say Y here to compile support for HCI BCM203x devices into the
kernel or say M to compile it as module (bcm203x).
kernel or say M to compile it as module (bcm203x).
config BT_HCIBPA10X
tristate "HCI BPA10x USB driver"
depends on USB
help
Bluetooth HCI BPA10x USB driver.
This driver provides support for the Digianswer BPA 100/105 Bluetooth
sniffer devices.
Say Y here to compile support for HCI BPA10x devices into the
kernel or say M to compile it as module (bpa10x).
config BT_HCIBFUSB
config BT_HCIBFUSB
tristate "HCI BlueFRITZ! USB driver"
tristate "HCI BlueFRITZ! USB driver"
depends on USB
depends on USB
...
...
drivers/bluetooth/Makefile
View file @
e55dbfb1
...
@@ -6,6 +6,7 @@ obj-$(CONFIG_BT_HCIUSB) += hci_usb.o
...
@@ -6,6 +6,7 @@ obj-$(CONFIG_BT_HCIUSB) += hci_usb.o
obj-$(CONFIG_BT_HCIVHCI)
+=
hci_vhci.o
obj-$(CONFIG_BT_HCIVHCI)
+=
hci_vhci.o
obj-$(CONFIG_BT_HCIUART)
+=
hci_uart.o
obj-$(CONFIG_BT_HCIUART)
+=
hci_uart.o
obj-$(CONFIG_BT_HCIBCM203X)
+=
bcm203x.o
obj-$(CONFIG_BT_HCIBCM203X)
+=
bcm203x.o
obj-$(CONFIG_BT_HCIBPA10X)
+=
bpa10x.o
obj-$(CONFIG_BT_HCIBFUSB)
+=
bfusb.o
obj-$(CONFIG_BT_HCIBFUSB)
+=
bfusb.o
obj-$(CONFIG_BT_HCIDTL1)
+=
dtl1_cs.o
obj-$(CONFIG_BT_HCIDTL1)
+=
dtl1_cs.o
obj-$(CONFIG_BT_HCIBT3C)
+=
bt3c_cs.o
obj-$(CONFIG_BT_HCIBT3C)
+=
bt3c_cs.o
...
...
drivers/bluetooth/bpa10x.c
0 → 100644
View file @
e55dbfb1
/*
*
* Digianswer Bluetooth USB driver
*
* Copyright (C) 2004-2005 Marcel Holtmann <marcel@holtmann.org>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/usb.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#ifndef CONFIG_BT_HCIBPA10X_DEBUG
#undef BT_DBG
#define BT_DBG(D...)
#endif
#define VERSION "0.8"
static
int
ignore
=
0
;
static
struct
usb_device_id
bpa10x_table
[]
=
{
/* Tektronix BPA 100/105 (Digianswer) */
{
USB_DEVICE
(
0x08fd
,
0x0002
)
},
{
}
/* Terminating entry */
};
MODULE_DEVICE_TABLE
(
usb
,
bpa10x_table
);
#define BPA10X_CMD_EP 0x00
#define BPA10X_EVT_EP 0x81
#define BPA10X_TX_EP 0x02
#define BPA10X_RX_EP 0x82
#define BPA10X_CMD_BUF_SIZE 252
#define BPA10X_EVT_BUF_SIZE 16
#define BPA10X_TX_BUF_SIZE 384
#define BPA10X_RX_BUF_SIZE 384
struct
bpa10x_data
{
struct
hci_dev
*
hdev
;
struct
usb_device
*
udev
;
rwlock_t
lock
;
struct
sk_buff_head
cmd_queue
;
struct
urb
*
cmd_urb
;
struct
urb
*
evt_urb
;
struct
sk_buff
*
evt_skb
;
unsigned
int
evt_len
;
struct
sk_buff_head
tx_queue
;
struct
urb
*
tx_urb
;
struct
urb
*
rx_urb
;
};
#define HCI_VENDOR_HDR_SIZE 5
struct
hci_vendor_hdr
{
__u8
type
;
__u16
snum
;
__u16
dlen
;
}
__attribute__
((
packed
));
static
void
bpa10x_recv_bulk
(
struct
bpa10x_data
*
data
,
unsigned
char
*
buf
,
int
count
)
{
struct
hci_acl_hdr
*
ah
;
struct
hci_sco_hdr
*
sh
;
struct
hci_vendor_hdr
*
vh
;
struct
sk_buff
*
skb
;
int
len
;
while
(
count
)
{
switch
(
*
buf
++
)
{
case
HCI_ACLDATA_PKT
:
ah
=
(
struct
hci_acl_hdr
*
)
buf
;
len
=
HCI_ACL_HDR_SIZE
+
__le16_to_cpu
(
ah
->
dlen
);
skb
=
bt_skb_alloc
(
len
,
GFP_ATOMIC
);
if
(
skb
)
{
memcpy
(
skb_put
(
skb
,
len
),
buf
,
len
);
skb
->
dev
=
(
void
*
)
data
->
hdev
;
skb
->
pkt_type
=
HCI_ACLDATA_PKT
;
hci_recv_frame
(
skb
);
}
break
;
case
HCI_SCODATA_PKT
:
sh
=
(
struct
hci_sco_hdr
*
)
buf
;
len
=
HCI_SCO_HDR_SIZE
+
sh
->
dlen
;
skb
=
bt_skb_alloc
(
len
,
GFP_ATOMIC
);
if
(
skb
)
{
memcpy
(
skb_put
(
skb
,
len
),
buf
,
len
);
skb
->
dev
=
(
void
*
)
data
->
hdev
;
skb
->
pkt_type
=
HCI_SCODATA_PKT
;
hci_recv_frame
(
skb
);
}
break
;
case
HCI_VENDOR_PKT
:
vh
=
(
struct
hci_vendor_hdr
*
)
buf
;
len
=
HCI_VENDOR_HDR_SIZE
+
__le16_to_cpu
(
vh
->
dlen
);
skb
=
bt_skb_alloc
(
len
,
GFP_ATOMIC
);
if
(
skb
)
{
memcpy
(
skb_put
(
skb
,
len
),
buf
,
len
);
skb
->
dev
=
(
void
*
)
data
->
hdev
;
skb
->
pkt_type
=
HCI_VENDOR_PKT
;
hci_recv_frame
(
skb
);
}
break
;
default:
len
=
count
-
1
;
break
;
}
buf
+=
len
;
count
-=
(
len
+
1
);
}
}
static
int
bpa10x_recv_event
(
struct
bpa10x_data
*
data
,
unsigned
char
*
buf
,
int
size
)
{
BT_DBG
(
"data %p buf %p size %d"
,
data
,
buf
,
size
);
if
(
data
->
evt_skb
)
{
struct
sk_buff
*
skb
=
data
->
evt_skb
;
memcpy
(
skb_put
(
skb
,
size
),
buf
,
size
);
if
(
skb
->
len
==
data
->
evt_len
)
{
data
->
evt_skb
=
NULL
;
data
->
evt_len
=
0
;
hci_recv_frame
(
skb
);
}
}
else
{
struct
sk_buff
*
skb
;
struct
hci_event_hdr
*
hdr
;
unsigned
char
pkt_type
;
int
pkt_len
=
0
;
if
(
size
<
HCI_EVENT_HDR_SIZE
+
1
)
{
BT_ERR
(
"%s event packet block with size %d is too short"
,
data
->
hdev
->
name
,
size
);
return
-
EILSEQ
;
}
pkt_type
=
*
buf
++
;
size
--
;
if
(
pkt_type
!=
HCI_EVENT_PKT
)
{
BT_ERR
(
"%s unexpected event packet start byte 0x%02x"
,
data
->
hdev
->
name
,
pkt_type
);
return
-
EPROTO
;
}
hdr
=
(
struct
hci_event_hdr
*
)
buf
;
pkt_len
=
HCI_EVENT_HDR_SIZE
+
hdr
->
plen
;
skb
=
bt_skb_alloc
(
pkt_len
,
GFP_ATOMIC
);
if
(
!
skb
)
{
BT_ERR
(
"%s no memory for new event packet"
,
data
->
hdev
->
name
);
return
-
ENOMEM
;
}
skb
->
dev
=
(
void
*
)
data
->
hdev
;
skb
->
pkt_type
=
pkt_type
;
memcpy
(
skb_put
(
skb
,
size
),
buf
,
size
);
if
(
pkt_len
==
size
)
{
hci_recv_frame
(
skb
);
}
else
{
data
->
evt_skb
=
skb
;
data
->
evt_len
=
pkt_len
;
}
}
return
0
;
}
static
void
bpa10x_wakeup
(
struct
bpa10x_data
*
data
)
{
struct
urb
*
urb
;
struct
sk_buff
*
skb
;
int
err
;
BT_DBG
(
"data %p"
,
data
);
urb
=
data
->
cmd_urb
;
if
(
urb
->
status
==
-
EINPROGRESS
)
skb
=
NULL
;
else
skb
=
skb_dequeue
(
&
data
->
cmd_queue
);
if
(
skb
)
{
struct
usb_ctrlrequest
*
cr
;
if
(
skb
->
len
>
BPA10X_CMD_BUF_SIZE
)
{
BT_ERR
(
"%s command packet with size %d is too big"
,
data
->
hdev
->
name
,
skb
->
len
);
kfree_skb
(
skb
);
return
;
}
cr
=
(
struct
usb_ctrlrequest
*
)
urb
->
setup_packet
;
cr
->
wLength
=
__cpu_to_le16
(
skb
->
len
);
memcpy
(
urb
->
transfer_buffer
,
skb
->
data
,
skb
->
len
);
urb
->
transfer_buffer_length
=
skb
->
len
;
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
err
<
0
&&
err
!=
-
ENODEV
)
{
BT_ERR
(
"%s submit failed for command urb %p with error %d"
,
data
->
hdev
->
name
,
urb
,
err
);
skb_queue_head
(
&
data
->
cmd_queue
,
skb
);
}
else
kfree_skb
(
skb
);
}
urb
=
data
->
tx_urb
;
if
(
urb
->
status
==
-
EINPROGRESS
)
skb
=
NULL
;
else
skb
=
skb_dequeue
(
&
data
->
tx_queue
);
if
(
skb
)
{
memcpy
(
urb
->
transfer_buffer
,
skb
->
data
,
skb
->
len
);
urb
->
transfer_buffer_length
=
skb
->
len
;
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
err
<
0
&&
err
!=
-
ENODEV
)
{
BT_ERR
(
"%s submit failed for command urb %p with error %d"
,
data
->
hdev
->
name
,
urb
,
err
);
skb_queue_head
(
&
data
->
tx_queue
,
skb
);
}
else
kfree_skb
(
skb
);
}
}
static
void
bpa10x_complete
(
struct
urb
*
urb
,
struct
pt_regs
*
regs
)
{
struct
bpa10x_data
*
data
=
urb
->
context
;
unsigned
char
*
buf
=
urb
->
transfer_buffer
;
int
err
,
count
=
urb
->
actual_length
;
BT_DBG
(
"data %p urb %p buf %p count %d"
,
data
,
urb
,
buf
,
count
);
read_lock
(
&
data
->
lock
);
if
(
!
test_bit
(
HCI_RUNNING
,
&
data
->
hdev
->
flags
))
goto
unlock
;
if
(
urb
->
status
<
0
||
!
count
)
goto
resubmit
;
if
(
usb_pipein
(
urb
->
pipe
))
{
data
->
hdev
->
stat
.
byte_rx
+=
count
;
if
(
usb_pipetype
(
urb
->
pipe
)
==
PIPE_INTERRUPT
)
bpa10x_recv_event
(
data
,
buf
,
count
);
if
(
usb_pipetype
(
urb
->
pipe
)
==
PIPE_BULK
)
bpa10x_recv_bulk
(
data
,
buf
,
count
);
}
else
{
data
->
hdev
->
stat
.
byte_tx
+=
count
;
bpa10x_wakeup
(
data
);
}
resubmit:
if
(
usb_pipein
(
urb
->
pipe
))
{
err
=
usb_submit_urb
(
urb
,
GFP_ATOMIC
);
if
(
err
<
0
&&
err
!=
-
ENODEV
)
{
BT_ERR
(
"%s urb %p type %d resubmit status %d"
,
data
->
hdev
->
name
,
urb
,
usb_pipetype
(
urb
->
pipe
),
err
);
}
}
unlock:
read_unlock
(
&
data
->
lock
);
}
static
inline
struct
urb
*
bpa10x_alloc_urb
(
struct
usb_device
*
udev
,
unsigned
int
pipe
,
size_t
size
,
int
flags
,
void
*
data
)
{
struct
urb
*
urb
;
struct
usb_ctrlrequest
*
cr
;
unsigned
char
*
buf
;
BT_DBG
(
"udev %p data %p"
,
udev
,
data
);
urb
=
usb_alloc_urb
(
0
,
flags
);
if
(
!
urb
)
return
NULL
;
buf
=
kmalloc
(
size
,
flags
);
if
(
!
buf
)
{
usb_free_urb
(
urb
);
return
NULL
;
}
switch
(
usb_pipetype
(
pipe
))
{
case
PIPE_CONTROL
:
cr
=
kmalloc
(
sizeof
(
*
cr
),
flags
);
if
(
!
cr
)
{
kfree
(
buf
);
usb_free_urb
(
urb
);
return
NULL
;
}
cr
->
bRequestType
=
USB_TYPE_VENDOR
;
cr
->
bRequest
=
0
;
cr
->
wIndex
=
0
;
cr
->
wValue
=
0
;
cr
->
wLength
=
__cpu_to_le16
(
0
);
usb_fill_control_urb
(
urb
,
udev
,
pipe
,
(
void
*
)
cr
,
buf
,
0
,
bpa10x_complete
,
data
);
break
;
case
PIPE_INTERRUPT
:
usb_fill_int_urb
(
urb
,
udev
,
pipe
,
buf
,
size
,
bpa10x_complete
,
data
,
1
);
break
;
case
PIPE_BULK
:
usb_fill_bulk_urb
(
urb
,
udev
,
pipe
,
buf
,
size
,
bpa10x_complete
,
data
);
break
;
default:
kfree
(
buf
);
usb_free_urb
(
urb
);
return
NULL
;
}
return
urb
;
}
static
inline
void
bpa10x_free_urb
(
struct
urb
*
urb
)
{
BT_DBG
(
"urb %p"
,
urb
);
if
(
!
urb
)
return
;
if
(
urb
->
setup_packet
)
kfree
(
urb
->
setup_packet
);
if
(
urb
->
transfer_buffer
)
kfree
(
urb
->
transfer_buffer
);
usb_free_urb
(
urb
);
}
static
int
bpa10x_open
(
struct
hci_dev
*
hdev
)
{
struct
bpa10x_data
*
data
=
hdev
->
driver_data
;
struct
usb_device
*
udev
=
data
->
udev
;
unsigned
long
flags
;
int
err
;
BT_DBG
(
"hdev %p data %p"
,
hdev
,
data
);
if
(
test_and_set_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
return
0
;
data
->
cmd_urb
=
bpa10x_alloc_urb
(
udev
,
usb_sndctrlpipe
(
udev
,
BPA10X_CMD_EP
),
BPA10X_CMD_BUF_SIZE
,
GFP_KERNEL
,
data
);
if
(
!
data
->
cmd_urb
)
{
err
=
-
ENOMEM
;
goto
done
;
}
data
->
evt_urb
=
bpa10x_alloc_urb
(
udev
,
usb_rcvintpipe
(
udev
,
BPA10X_EVT_EP
),
BPA10X_EVT_BUF_SIZE
,
GFP_KERNEL
,
data
);
if
(
!
data
->
evt_urb
)
{
bpa10x_free_urb
(
data
->
cmd_urb
);
err
=
-
ENOMEM
;
goto
done
;
}
data
->
rx_urb
=
bpa10x_alloc_urb
(
udev
,
usb_rcvbulkpipe
(
udev
,
BPA10X_RX_EP
),
BPA10X_RX_BUF_SIZE
,
GFP_KERNEL
,
data
);
if
(
!
data
->
rx_urb
)
{
bpa10x_free_urb
(
data
->
evt_urb
);
bpa10x_free_urb
(
data
->
cmd_urb
);
err
=
-
ENOMEM
;
goto
done
;
}
data
->
tx_urb
=
bpa10x_alloc_urb
(
udev
,
usb_sndbulkpipe
(
udev
,
BPA10X_TX_EP
),
BPA10X_TX_BUF_SIZE
,
GFP_KERNEL
,
data
);
if
(
!
data
->
rx_urb
)
{
bpa10x_free_urb
(
data
->
rx_urb
);
bpa10x_free_urb
(
data
->
evt_urb
);
bpa10x_free_urb
(
data
->
cmd_urb
);
err
=
-
ENOMEM
;
goto
done
;
}
write_lock_irqsave
(
&
data
->
lock
,
flags
);
err
=
usb_submit_urb
(
data
->
evt_urb
,
GFP_ATOMIC
);
if
(
err
<
0
)
{
BT_ERR
(
"%s submit failed for event urb %p with error %d"
,
data
->
hdev
->
name
,
data
->
evt_urb
,
err
);
}
else
{
err
=
usb_submit_urb
(
data
->
rx_urb
,
GFP_ATOMIC
);
if
(
err
<
0
)
{
BT_ERR
(
"%s submit failed for rx urb %p with error %d"
,
data
->
hdev
->
name
,
data
->
evt_urb
,
err
);
usb_kill_urb
(
data
->
evt_urb
);
}
}
write_unlock_irqrestore
(
&
data
->
lock
,
flags
);
done:
if
(
err
<
0
)
clear_bit
(
HCI_RUNNING
,
&
hdev
->
flags
);
return
err
;
}
static
int
bpa10x_close
(
struct
hci_dev
*
hdev
)
{
struct
bpa10x_data
*
data
=
hdev
->
driver_data
;
unsigned
long
flags
;
BT_DBG
(
"hdev %p data %p"
,
hdev
,
data
);
if
(
!
test_and_clear_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
return
0
;
write_lock_irqsave
(
&
data
->
lock
,
flags
);
skb_queue_purge
(
&
data
->
cmd_queue
);
usb_kill_urb
(
data
->
cmd_urb
);
usb_kill_urb
(
data
->
evt_urb
);
usb_kill_urb
(
data
->
rx_urb
);
usb_kill_urb
(
data
->
tx_urb
);
write_unlock_irqrestore
(
&
data
->
lock
,
flags
);
bpa10x_free_urb
(
data
->
cmd_urb
);
bpa10x_free_urb
(
data
->
evt_urb
);
bpa10x_free_urb
(
data
->
rx_urb
);
bpa10x_free_urb
(
data
->
tx_urb
);
return
0
;
}
static
int
bpa10x_flush
(
struct
hci_dev
*
hdev
)
{
struct
bpa10x_data
*
data
=
hdev
->
driver_data
;
BT_DBG
(
"hdev %p data %p"
,
hdev
,
data
);
skb_queue_purge
(
&
data
->
cmd_queue
);
return
0
;
}
static
int
bpa10x_send_frame
(
struct
sk_buff
*
skb
)
{
struct
hci_dev
*
hdev
=
(
struct
hci_dev
*
)
skb
->
dev
;
struct
bpa10x_data
*
data
;
BT_DBG
(
"hdev %p skb %p type %d len %d"
,
hdev
,
skb
,
skb
->
pkt_type
,
skb
->
len
);
if
(
!
hdev
)
{
BT_ERR
(
"Frame for unknown HCI device"
);
return
-
ENODEV
;
}
if
(
!
test_bit
(
HCI_RUNNING
,
&
hdev
->
flags
))
return
-
EBUSY
;
data
=
hdev
->
driver_data
;
/* Prepend skb with frame type */
memcpy
(
skb_push
(
skb
,
1
),
&
(
skb
->
pkt_type
),
1
);
switch
(
skb
->
pkt_type
)
{
case
HCI_COMMAND_PKT
:
hdev
->
stat
.
cmd_tx
++
;
skb_queue_tail
(
&
data
->
cmd_queue
,
skb
);
break
;
case
HCI_ACLDATA_PKT
:
hdev
->
stat
.
acl_tx
++
;
skb_queue_tail
(
&
data
->
tx_queue
,
skb
);
break
;
case
HCI_SCODATA_PKT
:
hdev
->
stat
.
sco_tx
++
;
skb_queue_tail
(
&
data
->
tx_queue
,
skb
);
break
;
};
read_lock
(
&
data
->
lock
);
bpa10x_wakeup
(
data
);
read_unlock
(
&
data
->
lock
);
return
0
;
}
static
void
bpa10x_destruct
(
struct
hci_dev
*
hdev
)
{
struct
bpa10x_data
*
data
=
hdev
->
driver_data
;
BT_DBG
(
"hdev %p data %p"
,
hdev
,
data
);
kfree
(
data
);
}
static
int
bpa10x_probe
(
struct
usb_interface
*
intf
,
const
struct
usb_device_id
*
id
)
{
struct
usb_device
*
udev
=
interface_to_usbdev
(
intf
);
struct
hci_dev
*
hdev
;
struct
bpa10x_data
*
data
;
int
err
;
BT_DBG
(
"intf %p id %p"
,
intf
,
id
);
if
(
ignore
)
return
-
ENODEV
;
data
=
kmalloc
(
sizeof
(
*
data
),
GFP_KERNEL
);
if
(
!
data
)
{
BT_ERR
(
"Can't allocate data structure"
);
return
-
ENOMEM
;
}
memset
(
data
,
0
,
sizeof
(
*
data
));
data
->
udev
=
udev
;
rwlock_init
(
&
data
->
lock
);
skb_queue_head_init
(
&
data
->
cmd_queue
);
skb_queue_head_init
(
&
data
->
tx_queue
);
hdev
=
hci_alloc_dev
();
if
(
!
hdev
)
{
BT_ERR
(
"Can't allocate HCI device"
);
kfree
(
data
);
return
-
ENOMEM
;
}
data
->
hdev
=
hdev
;
hdev
->
type
=
HCI_USB
;
hdev
->
driver_data
=
data
;
SET_HCIDEV_DEV
(
hdev
,
&
intf
->
dev
);
hdev
->
open
=
bpa10x_open
;
hdev
->
close
=
bpa10x_close
;
hdev
->
flush
=
bpa10x_flush
;
hdev
->
send
=
bpa10x_send_frame
;
hdev
->
destruct
=
bpa10x_destruct
;
hdev
->
owner
=
THIS_MODULE
;
err
=
hci_register_dev
(
hdev
);
if
(
err
<
0
)
{
BT_ERR
(
"Can't register HCI device"
);
kfree
(
data
);
hci_free_dev
(
hdev
);
return
err
;
}
usb_set_intfdata
(
intf
,
data
);
return
0
;
}
static
void
bpa10x_disconnect
(
struct
usb_interface
*
intf
)
{
struct
bpa10x_data
*
data
=
usb_get_intfdata
(
intf
);
struct
hci_dev
*
hdev
=
data
->
hdev
;
BT_DBG
(
"intf %p"
,
intf
);
if
(
!
hdev
)
return
;
usb_set_intfdata
(
intf
,
NULL
);
if
(
hci_unregister_dev
(
hdev
)
<
0
)
BT_ERR
(
"Can't unregister HCI device %s"
,
hdev
->
name
);
hci_free_dev
(
hdev
);
}
static
struct
usb_driver
bpa10x_driver
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"bpa10x"
,
.
probe
=
bpa10x_probe
,
.
disconnect
=
bpa10x_disconnect
,
.
id_table
=
bpa10x_table
,
};
static
int
__init
bpa10x_init
(
void
)
{
int
err
;
BT_INFO
(
"Digianswer Bluetooth USB driver ver %s"
,
VERSION
);
err
=
usb_register
(
&
bpa10x_driver
);
if
(
err
<
0
)
BT_ERR
(
"Failed to register USB driver"
);
return
err
;
}
static
void
__exit
bpa10x_exit
(
void
)
{
usb_deregister
(
&
bpa10x_driver
);
}
module_init
(
bpa10x_init
);
module_exit
(
bpa10x_exit
);
module_param
(
ignore
,
bool
,
0644
);
MODULE_PARM_DESC
(
ignore
,
"Ignore devices from the matching table"
);
MODULE_AUTHOR
(
"Marcel Holtmann <marcel@holtmann.org>"
);
MODULE_DESCRIPTION
(
"Digianswer Bluetooth USB driver ver "
VERSION
);
MODULE_VERSION
(
VERSION
);
MODULE_LICENSE
(
"GPL"
);
drivers/bluetooth/hci_usb.c
View file @
e55dbfb1
...
@@ -73,7 +73,7 @@ static int reset = 0;
...
@@ -73,7 +73,7 @@ static int reset = 0;
static
int
isoc
=
2
;
static
int
isoc
=
2
;
#endif
#endif
#define VERSION "2.
7
"
#define VERSION "2.
8
"
static
struct
usb_driver
hci_usb_driver
;
static
struct
usb_driver
hci_usb_driver
;
...
@@ -104,11 +104,11 @@ static struct usb_device_id blacklist_ids[] = {
...
@@ -104,11 +104,11 @@ static struct usb_device_id blacklist_ids[] = {
{
USB_DEVICE
(
0x0a5c
,
0x2033
),
.
driver_info
=
HCI_IGNORE
},
{
USB_DEVICE
(
0x0a5c
,
0x2033
),
.
driver_info
=
HCI_IGNORE
},
/* Broadcom BCM2035 */
/* Broadcom BCM2035 */
{
USB_DEVICE
(
0x0a5c
,
0x2009
),
.
driver_info
=
HCI_RESET
|
HCI_BROKEN_ISOC
},
{
USB_DEVICE
(
0x0a5c
,
0x200a
),
.
driver_info
=
HCI_RESET
|
HCI_BROKEN_ISOC
},
{
USB_DEVICE
(
0x0a5c
,
0x200a
),
.
driver_info
=
HCI_RESET
|
HCI_BROKEN_ISOC
},
{
USB_DEVICE
(
0x0a5c
,
0x2009
),
.
driver_info
=
HCI_BCM92035
},
/* Microsoft Wireless Transceiver for Bluetooth 2.0 */
/* Microsoft Wireless Transceiver for Bluetooth 2.0 */
{
USB_DEVICE
(
0x045e
,
0x009c
),
.
driver_info
=
HCI_
RESET
|
HCI_BROKEN_ISOC
},
{
USB_DEVICE
(
0x045e
,
0x009c
),
.
driver_info
=
HCI_
BCM92035
},
/* ISSC Bluetooth Adapter v3.1 */
/* ISSC Bluetooth Adapter v3.1 */
{
USB_DEVICE
(
0x1131
,
0x1001
),
.
driver_info
=
HCI_RESET
},
{
USB_DEVICE
(
0x1131
,
0x1001
),
.
driver_info
=
HCI_RESET
},
...
@@ -977,6 +977,17 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
...
@@ -977,6 +977,17 @@ static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id
set_bit
(
HCI_QUIRK_RAW_DEVICE
,
&
hdev
->
quirks
);
set_bit
(
HCI_QUIRK_RAW_DEVICE
,
&
hdev
->
quirks
);
}
}
if
(
id
->
driver_info
&
HCI_BCM92035
)
{
unsigned
char
cmd
[]
=
{
0x3b
,
0xfc
,
0x01
,
0x00
};
struct
sk_buff
*
skb
;
skb
=
bt_skb_alloc
(
sizeof
(
cmd
),
GFP_KERNEL
);
if
(
skb
)
{
memcpy
(
skb_put
(
skb
,
sizeof
(
cmd
)),
cmd
,
sizeof
(
cmd
));
skb_queue_tail
(
&
hdev
->
driver_init
,
skb
);
}
}
if
(
hci_register_dev
(
hdev
)
<
0
)
{
if
(
hci_register_dev
(
hdev
)
<
0
)
{
BT_ERR
(
"Can't register HCI device"
);
BT_ERR
(
"Can't register HCI device"
);
hci_free_dev
(
hdev
);
hci_free_dev
(
hdev
);
...
...
drivers/bluetooth/hci_usb.h
View file @
e55dbfb1
...
@@ -33,6 +33,7 @@
...
@@ -33,6 +33,7 @@
#define HCI_DIGIANSWER 0x04
#define HCI_DIGIANSWER 0x04
#define HCI_SNIFFER 0x08
#define HCI_SNIFFER 0x08
#define HCI_BROKEN_ISOC 0x10
#define HCI_BROKEN_ISOC 0x10
#define HCI_BCM92035 0x20
#define HCI_MAX_IFACE_NUM 3
#define HCI_MAX_IFACE_NUM 3
...
...
include/asm-sparc64/spinlock.h
View file @
e55dbfb1
...
@@ -171,12 +171,13 @@ static void inline __read_unlock(rwlock_t *lock)
...
@@ -171,12 +171,13 @@ static void inline __read_unlock(rwlock_t *lock)
unsigned
long
tmp1
,
tmp2
;
unsigned
long
tmp1
,
tmp2
;
__asm__
__volatile__
(
__asm__
__volatile__
(
" membar #StoreLoad | #LoadLoad
\n
"
"1: lduw [%2], %0
\n
"
"1: lduw [%2], %0
\n
"
" sub %0, 1, %1
\n
"
" sub %0, 1, %1
\n
"
" cas [%2], %0, %1
\n
"
" cas [%2], %0, %1
\n
"
" cmp %0, %1
\n
"
" cmp %0, %1
\n
"
" bne,pn %%xcc, 1b
\n
"
" bne,pn %%xcc, 1b
\n
"
"
membar #StoreLoad | #StoreStore
"
"
nop
"
:
"=&r"
(
tmp1
),
"=&r"
(
tmp2
)
:
"=&r"
(
tmp1
),
"=&r"
(
tmp2
)
:
"r"
(
lock
)
:
"r"
(
lock
)
:
"memory"
);
:
"memory"
);
...
...
include/asm-sparc64/system.h
View file @
e55dbfb1
...
@@ -229,6 +229,7 @@ do { if (test_thread_flag(TIF_PERFCTR)) { \
...
@@ -229,6 +229,7 @@ do { if (test_thread_flag(TIF_PERFCTR)) { \
static
__inline__
unsigned
long
xchg32
(
__volatile__
unsigned
int
*
m
,
unsigned
int
val
)
static
__inline__
unsigned
long
xchg32
(
__volatile__
unsigned
int
*
m
,
unsigned
int
val
)
{
{
__asm__
__volatile__
(
__asm__
__volatile__
(
" membar #StoreLoad | #LoadLoad
\n
"
" mov %0, %%g5
\n
"
" mov %0, %%g5
\n
"
"1: lduw [%2], %%g7
\n
"
"1: lduw [%2], %%g7
\n
"
" cas [%2], %%g7, %0
\n
"
" cas [%2], %%g7, %0
\n
"
...
@@ -245,6 +246,7 @@ static __inline__ unsigned long xchg32(__volatile__ unsigned int *m, unsigned in
...
@@ -245,6 +246,7 @@ static __inline__ unsigned long xchg32(__volatile__ unsigned int *m, unsigned in
static
__inline__
unsigned
long
xchg64
(
__volatile__
unsigned
long
*
m
,
unsigned
long
val
)
static
__inline__
unsigned
long
xchg64
(
__volatile__
unsigned
long
*
m
,
unsigned
long
val
)
{
{
__asm__
__volatile__
(
__asm__
__volatile__
(
" membar #StoreLoad | #LoadLoad
\n
"
" mov %0, %%g5
\n
"
" mov %0, %%g5
\n
"
"1: ldx [%2], %%g7
\n
"
"1: ldx [%2], %%g7
\n
"
" casx [%2], %%g7, %0
\n
"
" casx [%2], %%g7, %0
\n
"
...
@@ -289,7 +291,8 @@ extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noret
...
@@ -289,7 +291,8 @@ extern void die_if_kernel(char *str, struct pt_regs *regs) __attribute__ ((noret
static
__inline__
unsigned
long
static
__inline__
unsigned
long
__cmpxchg_u32
(
volatile
int
*
m
,
int
old
,
int
new
)
__cmpxchg_u32
(
volatile
int
*
m
,
int
old
,
int
new
)
{
{
__asm__
__volatile__
(
"cas [%2], %3, %0
\n\t
"
__asm__
__volatile__
(
"membar #StoreLoad | #LoadLoad
\n
"
"cas [%2], %3, %0
\n\t
"
"membar #StoreLoad | #StoreStore"
"membar #StoreLoad | #StoreStore"
:
"=&r"
(
new
)
:
"=&r"
(
new
)
:
"0"
(
new
),
"r"
(
m
),
"r"
(
old
)
:
"0"
(
new
),
"r"
(
m
),
"r"
(
old
)
...
@@ -301,7 +304,8 @@ __cmpxchg_u32(volatile int *m, int old, int new)
...
@@ -301,7 +304,8 @@ __cmpxchg_u32(volatile int *m, int old, int new)
static
__inline__
unsigned
long
static
__inline__
unsigned
long
__cmpxchg_u64
(
volatile
long
*
m
,
unsigned
long
old
,
unsigned
long
new
)
__cmpxchg_u64
(
volatile
long
*
m
,
unsigned
long
old
,
unsigned
long
new
)
{
{
__asm__
__volatile__
(
"casx [%2], %3, %0
\n\t
"
__asm__
__volatile__
(
"membar #StoreLoad | #LoadLoad
\n
"
"casx [%2], %3, %0
\n\t
"
"membar #StoreLoad | #StoreStore"
"membar #StoreLoad | #StoreStore"
:
"=&r"
(
new
)
:
"=&r"
(
new
)
:
"0"
(
new
),
"r"
(
m
),
"r"
(
old
)
:
"0"
(
new
),
"r"
(
m
),
"r"
(
old
)
...
...
include/linux/netfilter_ipv4/ip_conntrack_tcp.h
View file @
e55dbfb1
...
@@ -41,6 +41,7 @@ struct ip_ct_tcp
...
@@ -41,6 +41,7 @@ struct ip_ct_tcp
u_int8_t
retrans
;
/* Number of retransmitted packets */
u_int8_t
retrans
;
/* Number of retransmitted packets */
u_int8_t
last_index
;
/* Index of the last packet */
u_int8_t
last_index
;
/* Index of the last packet */
u_int32_t
last_seq
;
/* Last sequence number seen in dir */
u_int32_t
last_seq
;
/* Last sequence number seen in dir */
u_int32_t
last_ack
;
/* Last sequence number seen in opposite dir */
u_int32_t
last_end
;
/* Last seq + len */
u_int32_t
last_end
;
/* Last seq + len */
};
};
...
...
include/linux/netfilter_ipv4/ip_conntrack_tuple.h
View file @
e55dbfb1
...
@@ -64,10 +64,10 @@ struct ip_conntrack_tuple
...
@@ -64,10 +64,10 @@ struct ip_conntrack_tuple
}
u
;
}
u
;
/* The protocol. */
/* The protocol. */
u
8
protonum
;
u
_int8_t
protonum
;
/* The direction (for tuplehash) */
/* The direction (for tuplehash) */
u
8
dir
;
u
_int8_t
dir
;
}
dst
;
}
dst
;
};
};
...
...
include/linux/netlink.h
View file @
e55dbfb1
...
@@ -133,10 +133,9 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
...
@@ -133,10 +133,9 @@ int netlink_sendskb(struct sock *sk, struct sk_buff *skb, int protocol);
/*
/*
* skb should fit one page. This choice is good for headerless malloc.
* skb should fit one page. This choice is good for headerless malloc.
*
* FIXME: What is the best size for SLAB???? --ANK
*/
*/
#define NLMSG_GOODSIZE (PAGE_SIZE - ((sizeof(struct sk_buff)+0xF)&~0xF))
#define NLMSG_GOODORDER 0
#define NLMSG_GOODSIZE (SKB_MAX_ORDER(0, NLMSG_GOODORDER))
struct
netlink_callback
struct
netlink_callback
...
...
include/net/bluetooth/hci_core.h
View file @
e55dbfb1
...
@@ -119,6 +119,8 @@ struct hci_dev {
...
@@ -119,6 +119,8 @@ struct hci_dev {
struct
hci_dev_stats
stat
;
struct
hci_dev_stats
stat
;
struct
sk_buff_head
driver_init
;
void
*
driver_data
;
void
*
driver_data
;
void
*
core_data
;
void
*
core_data
;
...
...
net/bluetooth/hci_core.c
View file @
e55dbfb1
...
@@ -183,10 +183,22 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
...
@@ -183,10 +183,22 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
static
void
hci_init_req
(
struct
hci_dev
*
hdev
,
unsigned
long
opt
)
static
void
hci_init_req
(
struct
hci_dev
*
hdev
,
unsigned
long
opt
)
{
{
struct
sk_buff
*
skb
;
__u16
param
;
__u16
param
;
BT_DBG
(
"%s %ld"
,
hdev
->
name
,
opt
);
BT_DBG
(
"%s %ld"
,
hdev
->
name
,
opt
);
/* Driver initialization */
/* Special commands */
while
((
skb
=
skb_dequeue
(
&
hdev
->
driver_init
)))
{
skb
->
pkt_type
=
HCI_COMMAND_PKT
;
skb
->
dev
=
(
void
*
)
hdev
;
skb_queue_tail
(
&
hdev
->
cmd_q
,
skb
);
hci_sched_cmd
(
hdev
);
}
skb_queue_purge
(
&
hdev
->
driver_init
);
/* Mandatory initialization */
/* Mandatory initialization */
/* Reset */
/* Reset */
...
@@ -792,6 +804,8 @@ struct hci_dev *hci_alloc_dev(void)
...
@@ -792,6 +804,8 @@ struct hci_dev *hci_alloc_dev(void)
memset
(
hdev
,
0
,
sizeof
(
struct
hci_dev
));
memset
(
hdev
,
0
,
sizeof
(
struct
hci_dev
));
skb_queue_head_init
(
&
hdev
->
driver_init
);
return
hdev
;
return
hdev
;
}
}
EXPORT_SYMBOL
(
hci_alloc_dev
);
EXPORT_SYMBOL
(
hci_alloc_dev
);
...
@@ -799,6 +813,8 @@ EXPORT_SYMBOL(hci_alloc_dev);
...
@@ -799,6 +813,8 @@ EXPORT_SYMBOL(hci_alloc_dev);
/* Free HCI device */
/* Free HCI device */
void
hci_free_dev
(
struct
hci_dev
*
hdev
)
void
hci_free_dev
(
struct
hci_dev
*
hdev
)
{
{
skb_queue_purge
(
&
hdev
->
driver_init
);
/* will free via class release */
/* will free via class release */
class_device_put
(
&
hdev
->
class_dev
);
class_device_put
(
&
hdev
->
class_dev
);
}
}
...
...
net/ipv4/ipconfig.c
View file @
e55dbfb1
...
@@ -1232,7 +1232,7 @@ u32 __init root_nfs_parse_addr(char *name)
...
@@ -1232,7 +1232,7 @@ u32 __init root_nfs_parse_addr(char *name)
if
(
*
cp
==
':'
)
if
(
*
cp
==
':'
)
*
cp
++
=
'\0'
;
*
cp
++
=
'\0'
;
addr
=
in_aton
(
name
);
addr
=
in_aton
(
name
);
strcpy
(
name
,
cp
);
memmove
(
name
,
cp
,
strlen
(
cp
)
+
1
);
}
else
}
else
addr
=
INADDR_NONE
;
addr
=
INADDR_NONE
;
...
...
net/ipv4/netfilter/ip_conntrack_ftp.c
View file @
e55dbfb1
...
@@ -373,9 +373,8 @@ static int help(struct sk_buff **pskb,
...
@@ -373,9 +373,8 @@ static int help(struct sk_buff **pskb,
goto
out_update_nl
;
goto
out_update_nl
;
}
}
DEBUGP
(
"conntrack_ftp: match `%.*s' (%u bytes at %u)
\n
"
,
DEBUGP
(
"conntrack_ftp: match `%s' (%u bytes at %u)
\n
"
,
(
int
)
matchlen
,
data
+
matchoff
,
fb_ptr
+
matchoff
,
matchlen
,
ntohl
(
th
->
seq
)
+
matchoff
);
matchlen
,
ntohl
(
th
->
seq
)
+
matchoff
);
/* Allocate expectation which will be inserted */
/* Allocate expectation which will be inserted */
exp
=
ip_conntrack_expect_alloc
();
exp
=
ip_conntrack_expect_alloc
();
...
...
net/ipv4/netfilter/ip_conntrack_proto_tcp.c
View file @
e55dbfb1
...
@@ -665,11 +665,13 @@ static int tcp_in_window(struct ip_ct_tcp *state,
...
@@ -665,11 +665,13 @@ static int tcp_in_window(struct ip_ct_tcp *state,
if
(
*
index
==
TCP_ACK_SET
)
{
if
(
*
index
==
TCP_ACK_SET
)
{
if
(
state
->
last_dir
==
dir
if
(
state
->
last_dir
==
dir
&&
state
->
last_seq
==
seq
&&
state
->
last_seq
==
seq
&&
state
->
last_ack
==
ack
&&
state
->
last_end
==
end
)
&&
state
->
last_end
==
end
)
state
->
retrans
++
;
state
->
retrans
++
;
else
{
else
{
state
->
last_dir
=
dir
;
state
->
last_dir
=
dir
;
state
->
last_seq
=
seq
;
state
->
last_seq
=
seq
;
state
->
last_ack
=
ack
;
state
->
last_end
=
end
;
state
->
last_end
=
end
;
state
->
retrans
=
0
;
state
->
retrans
=
0
;
}
}
...
...
net/ipv4/netfilter/ip_nat_core.c
View file @
e55dbfb1
...
@@ -543,6 +543,7 @@ int __init ip_nat_init(void)
...
@@ -543,6 +543,7 @@ int __init ip_nat_init(void)
static
int
clean_nat
(
struct
ip_conntrack
*
i
,
void
*
data
)
static
int
clean_nat
(
struct
ip_conntrack
*
i
,
void
*
data
)
{
{
memset
(
&
i
->
nat
,
0
,
sizeof
(
i
->
nat
));
memset
(
&
i
->
nat
,
0
,
sizeof
(
i
->
nat
));
i
->
status
&=
~
(
IPS_NAT_MASK
|
IPS_NAT_DONE_MASK
|
IPS_SEQ_ADJUST
);
return
0
;
return
0
;
}
}
...
...
net/ipv4/netfilter/ipt_hashlimit.c
View file @
e55dbfb1
...
@@ -570,7 +570,7 @@ static void *dl_seq_start(struct seq_file *s, loff_t *pos)
...
@@ -570,7 +570,7 @@ static void *dl_seq_start(struct seq_file *s, loff_t *pos)
if
(
*
pos
>=
htable
->
cfg
.
size
)
if
(
*
pos
>=
htable
->
cfg
.
size
)
return
NULL
;
return
NULL
;
bucket
=
kmalloc
(
sizeof
(
unsigned
int
),
GFP_
KERNEL
);
bucket
=
kmalloc
(
sizeof
(
unsigned
int
),
GFP_
ATOMIC
);
if
(
!
bucket
)
if
(
!
bucket
)
return
ERR_PTR
(
-
ENOMEM
);
return
ERR_PTR
(
-
ENOMEM
);
...
...
net/ipv6/ip6_tunnel.c
View file @
e55dbfb1
...
@@ -180,10 +180,10 @@ ip6ip6_tnl_link(struct ip6_tnl *t)
...
@@ -180,10 +180,10 @@ ip6ip6_tnl_link(struct ip6_tnl *t)
{
{
struct
ip6_tnl
**
tp
=
ip6ip6_bucket
(
&
t
->
parms
);
struct
ip6_tnl
**
tp
=
ip6ip6_bucket
(
&
t
->
parms
);
write_lock_bh
(
&
ip6ip6_lock
);
t
->
next
=
*
tp
;
t
->
next
=
*
tp
;
write_
un
lock_bh
(
&
ip6ip6_lock
);
write_lock_bh
(
&
ip6ip6_lock
);
*
tp
=
t
;
*
tp
=
t
;
write_unlock_bh
(
&
ip6ip6_lock
);
}
}
/**
/**
...
...
net/sched/ipt.c
View file @
e55dbfb1
...
@@ -207,6 +207,11 @@ tcf_ipt(struct sk_buff **pskb, struct tc_action *a)
...
@@ -207,6 +207,11 @@ tcf_ipt(struct sk_buff **pskb, struct tc_action *a)
struct
tcf_ipt
*
p
=
PRIV
(
a
,
ipt
);
struct
tcf_ipt
*
p
=
PRIV
(
a
,
ipt
);
struct
sk_buff
*
skb
=
*
pskb
;
struct
sk_buff
*
skb
=
*
pskb
;
if
(
skb_cloned
(
skb
))
{
if
(
pskb_expand_head
(
skb
,
0
,
0
,
GFP_ATOMIC
))
return
TC_ACT_UNSPEC
;
}
spin_lock
(
&
p
->
lock
);
spin_lock
(
&
p
->
lock
);
p
->
tm
.
lastuse
=
jiffies
;
p
->
tm
.
lastuse
=
jiffies
;
...
...
net/sched/sch_netem.c
View file @
e55dbfb1
...
@@ -177,6 +177,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
...
@@ -177,6 +177,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch)
if
(
q
->
loss
&&
q
->
loss
>=
get_crandom
(
&
q
->
loss_cor
))
{
if
(
q
->
loss
&&
q
->
loss
>=
get_crandom
(
&
q
->
loss_cor
))
{
pr_debug
(
"netem_enqueue: random loss
\n
"
);
pr_debug
(
"netem_enqueue: random loss
\n
"
);
sch
->
qstats
.
drops
++
;
sch
->
qstats
.
drops
++
;
kfree_skb
(
skb
);
return
0
;
/* lie about loss so TCP doesn't know */
return
0
;
/* lie about loss so TCP doesn't know */
}
}
...
...
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