Merge commit 'AU_LINUX_ANDROID_ICS.04.00.04.00.126' into msm-3.4
AU_LINUX_ANDROID_ICS.04.00.04.00.126 from msm-3.0.
First parent is from google/android-3.4.
* commit 'AU_LINUX_ANDROID_ICS.04.00.04.00.126': (8712 commits)
PRNG: Device tree entry for qrng device.
vidc:1080p: Set video core timeout value for Thumbnail mode
msm: sps: improve the debugging support in SPS driver
board-8064 msm: Overlap secure and non secure video firmware heaps.
msm: clock: Add handoff ops for 7x30 and copper XO clocks
msm_fb: display: Wait for external vsync before DTV IOMMU unmap
msm: Fix ciruclar dependency in debug UART settings
msm: gdsc: Add GDSC regulator driver for msm-copper
defconfig: Enable Mobicore Driver.
mobicore: Add mobicore driver.
mobicore: rename variable to lower case.
mobicore: rename folder.
mobicore: add makefiles
mobicore: initial import of kernel driver
ASoC: msm: Add SLIMBUS_2_RX CPU DAI
board-8064-gpio: Update FUNC for EPM SPI CS
msm_fb: display: Remove chicken bit config during video playback
mmc: msm_sdcc: enable the sanitize capability
msm-fb: display: lm2 writeback support on mpq platfroms
msm_fb: display: Disable LVDS phy & pll during panel off
...
Signed-off-by: Steve Muckle <smuckle@codeaurora.org>
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 9652707..1390eca 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -39,6 +39,7 @@
#include <linux/mutex.h>
#include <linux/kthread.h>
#include <linux/slab.h>
+#include <linux/interrupt.h>
#include <net/sock.h>
#include <linux/uaccess.h>
@@ -50,6 +51,9 @@
#include <net/bluetooth/rfcomm.h>
#define VERSION "1.11"
+/* 1 Byte DLCI, 1 Byte Control filed, 2 Bytes Length, 1 Byte for Credits,
+ * 1 Byte FCS */
+#define RFCOMM_HDR_SIZE 6
static bool disable_cfc;
static bool l2cap_ertm;
@@ -62,6 +66,7 @@
#define rfcomm_lock() mutex_lock(&rfcomm_mutex)
#define rfcomm_unlock() mutex_unlock(&rfcomm_mutex)
+static unsigned long rfcomm_event;
static LIST_HEAD(session_list);
@@ -81,7 +86,9 @@
static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
bdaddr_t *dst,
u8 sec_level,
- int *err);
+ int *err,
+ u8 channel,
+ struct rfcomm_dlc *d);
static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst);
static void rfcomm_session_del(struct rfcomm_session *s);
@@ -115,10 +122,17 @@
#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
#define __get_rpn_parity(line) (((line) >> 3) & 0x7)
+struct rfcomm_sock_release_work {
+ struct work_struct work;
+ struct socket *sock;
+ int state;
+};
+
static inline void rfcomm_schedule(void)
{
if (!rfcomm_thread)
return;
+ set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
wake_up_process(rfcomm_thread);
}
@@ -230,8 +244,6 @@
static inline int rfcomm_check_security(struct rfcomm_dlc *d)
{
struct sock *sk = d->session->sock->sk;
- struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
-
__u8 auth_type;
switch (d->sec_level) {
@@ -246,7 +258,8 @@
break;
}
- return hci_conn_security(conn->hcon, d->sec_level, auth_type);
+ return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level,
+ auth_type);
}
static void rfcomm_session_timeout(unsigned long arg)
@@ -377,11 +390,13 @@
static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
{
struct rfcomm_dlc *d;
+ struct list_head *p;
- list_for_each_entry(d, &s->dlcs, list)
+ list_for_each(p, &s->dlcs) {
+ d = list_entry(p, struct rfcomm_dlc, list);
if (d->dlci == dlci)
return d;
-
+ }
return NULL;
}
@@ -402,31 +417,31 @@
s = rfcomm_session_get(src, dst);
if (!s) {
- s = rfcomm_session_create(src, dst, d->sec_level, &err);
+ s = rfcomm_session_create(src, dst,
+ d->sec_level, &err, channel, d);
if (!s)
return err;
+ } else {
+ dlci = __dlci(!s->initiator, channel);
+
+ /* Check if DLCI already exists */
+ if (rfcomm_dlc_get(s, dlci))
+ return -EBUSY;
+
+ rfcomm_dlc_clear_state(d);
+
+ d->dlci = dlci;
+ d->addr = __addr(s->initiator, dlci);
+ d->priority = 7;
+
+ d->state = BT_CONFIG;
+ rfcomm_dlc_link(s, d);
+
+ d->out = 1;
+
+ d->mtu = s->mtu;
+ d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
}
-
- dlci = __dlci(!s->initiator, channel);
-
- /* Check if DLCI already exists */
- if (rfcomm_dlc_get(s, dlci))
- return -EBUSY;
-
- rfcomm_dlc_clear_state(d);
-
- d->dlci = dlci;
- d->addr = __addr(s->initiator, dlci);
- d->priority = 7;
-
- d->state = BT_CONFIG;
- rfcomm_dlc_link(s, d);
-
- d->out = 1;
-
- d->mtu = s->mtu;
- d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
-
if (s->state == BT_CONNECTED) {
if (rfcomm_check_security(d))
rfcomm_send_pn(s, 1, d);
@@ -622,9 +637,25 @@
return s;
}
+static void rfcomm_sock_release_worker(struct work_struct *work)
+{
+ struct rfcomm_sock_release_work *release_work =
+ container_of(work, struct rfcomm_sock_release_work, work);
+
+ BT_DBG("sock %p", release_work->sock);
+
+ sock_release(release_work->sock);
+ if (release_work->state != BT_LISTEN)
+ module_put(THIS_MODULE);
+
+ kfree(release_work);
+}
+
static void rfcomm_session_del(struct rfcomm_session *s)
{
int state = s->state;
+ struct socket *sock = s->sock;
+ struct rfcomm_sock_release_work *release_work;
BT_DBG("session %p state %ld", s, s->state);
@@ -634,11 +665,19 @@
rfcomm_send_disc(s, 0);
rfcomm_session_clear_timer(s);
- sock_release(s->sock);
+
kfree(s);
- if (state != BT_LISTEN)
- module_put(THIS_MODULE);
+ release_work = kzalloc(sizeof(*release_work), GFP_ATOMIC);
+ if (release_work) {
+ INIT_WORK(&release_work->work, rfcomm_sock_release_worker);
+ release_work->sock = sock;
+ release_work->state = state;
+
+ if (!schedule_work(&release_work->work))
+ kfree(release_work);
+ }
+
}
static struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
@@ -682,12 +721,15 @@
static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
bdaddr_t *dst,
u8 sec_level,
- int *err)
+ int *err,
+ u8 channel,
+ struct rfcomm_dlc *d)
{
struct rfcomm_session *s = NULL;
struct sockaddr_l2 addr;
struct socket *sock;
struct sock *sk;
+ u8 dlci;
BT_DBG("%s %s", batostr(src), batostr(dst));
@@ -706,10 +748,10 @@
/* Set L2CAP options */
sk = sock->sk;
lock_sock(sk);
- l2cap_pi(sk)->chan->imtu = l2cap_mtu;
- l2cap_pi(sk)->chan->sec_level = sec_level;
+ l2cap_pi(sk)->imtu = l2cap_mtu;
+ l2cap_pi(sk)->sec_level = sec_level;
if (l2cap_ertm)
- l2cap_pi(sk)->chan->mode = L2CAP_MODE_ERTM;
+ l2cap_pi(sk)->mode = L2CAP_MODE_ERTM;
release_sock(sk);
s = rfcomm_session_add(sock, BT_BOUND);
@@ -724,11 +766,30 @@
addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = cpu_to_le16(RFCOMM_PSM);
addr.l2_cid = 0;
+ dlci = __dlci(!s->initiator, channel);
+
+ /* Check if DLCI already exists */
+ if (rfcomm_dlc_get(s, dlci))
+ return NULL;
+
+ rfcomm_dlc_clear_state(d);
+
+ d->dlci = dlci;
+ d->addr = __addr(s->initiator, dlci);
+ d->priority = 7;
+
+ d->state = BT_CONFIG;
+ rfcomm_dlc_link(s, d);
+
+ d->out = 1;
+
+ d->mtu = s->mtu;
+ d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
*err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
if (*err == 0 || *err == -EINPROGRESS)
return s;
-
- rfcomm_session_del(s);
+ BT_ERR("error ret is %d, going to delete session", *err);
+ rfcomm_dlc_unlink(d);
return NULL;
failed:
@@ -748,6 +809,7 @@
/* ---- RFCOMM frame sending ---- */
static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
{
+ struct socket *sock = s->sock;
struct kvec iv = { data, len };
struct msghdr msg;
@@ -755,14 +817,7 @@
memset(&msg, 0, sizeof(msg));
- return kernel_sendmsg(s->sock, &msg, &iv, 1, len);
-}
-
-static int rfcomm_send_cmd(struct rfcomm_session *s, struct rfcomm_cmd *cmd)
-{
- BT_DBG("%p cmd %u", s, cmd->ctrl);
-
- return rfcomm_send_frame(s, (void *) cmd, sizeof(*cmd));
+ return kernel_sendmsg(sock, &msg, &iv, 1, len);
}
static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
@@ -776,7 +831,7 @@
cmd.len = __len8(0);
cmd.fcs = __fcs2((u8 *) &cmd);
- return rfcomm_send_cmd(s, &cmd);
+ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
}
static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
@@ -790,7 +845,7 @@
cmd.len = __len8(0);
cmd.fcs = __fcs2((u8 *) &cmd);
- return rfcomm_send_cmd(s, &cmd);
+ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
}
static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
@@ -804,7 +859,7 @@
cmd.len = __len8(0);
cmd.fcs = __fcs2((u8 *) &cmd);
- return rfcomm_send_cmd(s, &cmd);
+ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
}
static int rfcomm_queue_disc(struct rfcomm_dlc *d)
@@ -840,7 +895,7 @@
cmd.len = __len8(0);
cmd.fcs = __fcs2((u8 *) &cmd);
- return rfcomm_send_cmd(s, &cmd);
+ return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
}
static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
@@ -1163,18 +1218,12 @@
break;
case BT_DISCONN:
- /* rfcomm_session_put is called later so don't do
- * anything here otherwise we will mess up the session
- * reference counter:
- *
- * (a) when we are the initiator dlc_unlink will drive
- * the reference counter to 0 (there is no initial put
- * after session_add)
- *
- * (b) when we are not the initiator rfcomm_rx_process
- * will explicitly call put to balance the initial hold
- * done after session add.
- */
+ /* When socket is closed and we are not RFCOMM
+ * initiator rfcomm_process_rx already calls
+ * rfcomm_session_put() */
+ if (s->sock->sk->sk_state != BT_CLOSED)
+ if (list_empty(&s->dlcs))
+ rfcomm_session_put(s);
break;
}
}
@@ -1250,7 +1299,6 @@
void rfcomm_dlc_accept(struct rfcomm_dlc *d)
{
struct sock *sk = d->session->sock->sk;
- struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
BT_DBG("dlc %p", d);
@@ -1264,7 +1312,7 @@
rfcomm_dlc_unlock(d);
if (d->role_switch)
- hci_conn_switch_role(conn->hcon, 0x00);
+ hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00);
rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
}
@@ -1812,11 +1860,6 @@
continue;
}
- if (test_bit(RFCOMM_ENC_DROP, &d->flags)) {
- __rfcomm_dlc_close(d, ECONNREFUSED);
- continue;
- }
-
if (test_and_clear_bit(RFCOMM_AUTH_ACCEPT, &d->flags)) {
rfcomm_dlc_clear_timer(d);
if (d->out) {
@@ -1907,9 +1950,10 @@
rfcomm_session_hold(s);
/* We should adjust MTU on incoming sessions.
- * L2CAP MTU minus UIH header and FCS. */
- s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu,
- l2cap_pi(nsock->sk)->chan->imtu) - 5;
+ * L2CAP MTU minus UIH header and FCS.
+ * Need to accomodate 1 Byte credits information */
+ s->mtu = min(l2cap_pi(nsock->sk)->omtu,
+ l2cap_pi(nsock->sk)->imtu) - RFCOMM_HDR_SIZE;
rfcomm_schedule();
} else
@@ -1927,8 +1971,9 @@
s->state = BT_CONNECT;
/* We can adjust MTU on outgoing sessions.
- * L2CAP MTU minus UIH header and FCS. */
- s->mtu = min(l2cap_pi(sk)->chan->omtu, l2cap_pi(sk)->chan->imtu) - 5;
+ * L2CAP MTU minus UIH header, Credits and FCS. */
+ s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) -
+ RFCOMM_HDR_SIZE;
rfcomm_send_sabm(s, 0);
break;
@@ -2011,7 +2056,7 @@
/* Set L2CAP options */
sk = sock->sk;
lock_sock(sk);
- l2cap_pi(sk)->chan->imtu = l2cap_mtu;
+ l2cap_pi(sk)->imtu = l2cap_mtu;
release_sock(sk);
/* Start listening on the socket */
@@ -2054,18 +2099,19 @@
rfcomm_add_listener(BDADDR_ANY);
- while (1) {
+ while (!kthread_should_stop()) {
set_current_state(TASK_INTERRUPTIBLE);
-
- if (kthread_should_stop())
- break;
+ if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) {
+ /* No pending events. Let's sleep.
+ * Incoming connections and data will wake us up. */
+ schedule();
+ }
+ set_current_state(TASK_RUNNING);
/* Process stuff */
+ clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event);
rfcomm_process_sessions();
-
- schedule();
}
- __set_current_state(TASK_RUNNING);
rfcomm_kill_listener();
@@ -2092,7 +2138,7 @@
if (test_and_clear_bit(RFCOMM_SEC_PENDING, &d->flags)) {
rfcomm_dlc_clear_timer(d);
if (status || encrypt == 0x00) {
- set_bit(RFCOMM_ENC_DROP, &d->flags);
+ __rfcomm_dlc_close(d, ECONNREFUSED);
continue;
}
}
@@ -2103,7 +2149,7 @@
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
continue;
} else if (d->sec_level == BT_SECURITY_HIGH) {
- set_bit(RFCOMM_ENC_DROP, &d->flags);
+ __rfcomm_dlc_close(d, ECONNREFUSED);
continue;
}
}
@@ -2111,7 +2157,7 @@
if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
continue;
- if (!status && hci_conn_check_secure(conn, d->sec_level))
+ if (!status)
set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
else
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
@@ -2130,13 +2176,15 @@
static int rfcomm_dlc_debugfs_show(struct seq_file *f, void *x)
{
struct rfcomm_session *s;
+ struct list_head *pp, *p;
rfcomm_lock();
- list_for_each_entry(s, &session_list, list) {
- struct rfcomm_dlc *d;
- list_for_each_entry(d, &s->dlcs, list) {
+ list_for_each(p, &session_list) {
+ s = list_entry(p, struct rfcomm_session, list);
+ list_for_each(pp, &s->dlcs) {
struct sock *sk = s->sock->sk;
+ struct rfcomm_dlc *d = list_entry(pp, struct rfcomm_dlc, list);
seq_printf(f, "%s %s %ld %d %d %d %d\n",
batostr(&bt_sk(sk)->src),
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index a55a43e..66cc1f0 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -42,9 +42,9 @@
#include <linux/device.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
-#include <linux/security.h>
#include <net/sock.h>
+#include <asm/system.h>
#include <linux/uaccess.h>
#include <net/bluetooth/bluetooth.h>
@@ -264,8 +264,6 @@
pi->sec_level = rfcomm_pi(parent)->sec_level;
pi->role_switch = rfcomm_pi(parent)->role_switch;
-
- security_sk_clone(parent, sk);
} else {
pi->dlc->defer_setup = 0;
@@ -369,7 +367,7 @@
goto done;
}
- write_lock(&rfcomm_sk_list.lock);
+ write_lock_bh(&rfcomm_sk_list.lock);
if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) {
err = -EADDRINUSE;
@@ -380,7 +378,7 @@
sk->sk_state = BT_BOUND;
}
- write_unlock(&rfcomm_sk_list.lock);
+ write_unlock_bh(&rfcomm_sk_list.lock);
done:
release_sock(sk);
@@ -454,7 +452,7 @@
err = -EINVAL;
- write_lock(&rfcomm_sk_list.lock);
+ write_lock_bh(&rfcomm_sk_list.lock);
for (channel = 1; channel < 31; channel++)
if (!__rfcomm_get_sock_by_addr(channel, src)) {
@@ -463,7 +461,7 @@
break;
}
- write_unlock(&rfcomm_sk_list.lock);
+ write_unlock_bh(&rfcomm_sk_list.lock);
if (err < 0)
goto done;
@@ -487,6 +485,11 @@
lock_sock(sk);
+ if (sk->sk_state != BT_LISTEN) {
+ err = -EBADFD;
+ goto done;
+ }
+
if (sk->sk_type != SOCK_STREAM) {
err = -EINVAL;
goto done;
@@ -498,20 +501,19 @@
/* Wait for an incoming connection. (wake-one). */
add_wait_queue_exclusive(sk_sleep(sk), &wait);
- while (1) {
+ while (!(nsk = bt_accept_dequeue(sk, newsock))) {
set_current_state(TASK_INTERRUPTIBLE);
-
- if (sk->sk_state != BT_LISTEN) {
- err = -EBADFD;
+ if (!timeo) {
+ err = -EAGAIN;
break;
}
- nsk = bt_accept_dequeue(sk, newsock);
- if (nsk)
- break;
+ release_sock(sk);
+ timeo = schedule_timeout(timeo);
+ lock_sock(sk);
- if (!timeo) {
- err = -EAGAIN;
+ if (sk->sk_state != BT_LISTEN) {
+ err = -EBADFD;
break;
}
@@ -519,12 +521,8 @@
err = sock_intr_errno(timeo);
break;
}
-
- release_sock(sk);
- timeo = schedule_timeout(timeo);
- lock_sock(sk);
}
- __set_current_state(TASK_RUNNING);
+ set_current_state(TASK_RUNNING);
remove_wait_queue(sk_sleep(sk), &wait);
if (err)
@@ -599,8 +597,6 @@
break;
}
- skb->priority = sk->sk_priority;
-
err = rfcomm_dlc_send(d, skb);
if (err < 0) {
kfree_skb(skb);
@@ -683,8 +679,7 @@
{
struct sock *sk = sock->sk;
struct bt_security sec;
- int err = 0;
- size_t len;
+ int len, err = 0;
u32 opt;
BT_DBG("sk %p", sk);
@@ -746,8 +741,8 @@
static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
+ struct sock *l2cap_sk;
struct rfcomm_conninfo cinfo;
- struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
int len, err = 0;
u32 opt;
@@ -790,9 +785,10 @@
break;
}
- memset(&cinfo, 0, sizeof(cinfo));
- cinfo.hci_handle = conn->hcon->handle;
- memcpy(cinfo.dev_class, conn->hcon->dev_class, 3);
+ l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
+
+ cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle;
+ memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3);
len = min_t(unsigned int, len, sizeof(cinfo));
if (copy_to_user(optval, (char *) &cinfo, len))
@@ -955,8 +951,6 @@
if (!sk)
goto done;
- bt_sock_reclassify_lock(sk, BTPROTO_RFCOMM);
-
rfcomm_sock_init(sk, parent);
bacpy(&bt_sk(sk)->src, &src);
bacpy(&bt_sk(sk)->dst, &dst);
@@ -983,7 +977,7 @@
struct sock *sk;
struct hlist_node *node;
- read_lock(&rfcomm_sk_list.lock);
+ read_lock_bh(&rfcomm_sk_list.lock);
sk_for_each(sk, node, &rfcomm_sk_list.head) {
seq_printf(f, "%s %s %d %d\n",
@@ -992,7 +986,7 @@
sk->sk_state, rfcomm_pi(sk)->channel);
}
- read_unlock(&rfcomm_sk_list.lock);
+ read_unlock_bh(&rfcomm_sk_list.lock);
return 0;
}
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 4bf54b3..e18781c 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -26,6 +26,7 @@
*/
#include <linux/module.h>
+#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
@@ -34,7 +35,6 @@
#include <linux/capability.h>
#include <linux/slab.h>
#include <linux/skbuff.h>
-#include <linux/workqueue.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -66,7 +66,7 @@
struct rfcomm_dlc *dlc;
struct tty_struct *tty;
wait_queue_head_t wait;
- struct work_struct wakeup_task;
+ struct tasklet_struct wakeup_task;
struct device *tty_dev;
@@ -76,13 +76,13 @@
};
static LIST_HEAD(rfcomm_dev_list);
-static DEFINE_SPINLOCK(rfcomm_dev_lock);
+static DEFINE_RWLOCK(rfcomm_dev_lock);
static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
-static void rfcomm_tty_wakeup(struct work_struct *work);
+static void rfcomm_tty_wakeup(unsigned long arg);
/* ---- Device functions ---- */
static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
@@ -134,10 +134,13 @@
static struct rfcomm_dev *__rfcomm_dev_get(int id)
{
struct rfcomm_dev *dev;
+ struct list_head *p;
- list_for_each_entry(dev, &rfcomm_dev_list, list)
+ list_for_each(p, &rfcomm_dev_list) {
+ dev = list_entry(p, struct rfcomm_dev, list);
if (dev->id == id)
return dev;
+ }
return NULL;
}
@@ -146,7 +149,7 @@
{
struct rfcomm_dev *dev;
- spin_lock(&rfcomm_dev_lock);
+ read_lock(&rfcomm_dev_lock);
dev = __rfcomm_dev_get(id);
@@ -157,7 +160,7 @@
rfcomm_dev_hold(dev);
}
- spin_unlock(&rfcomm_dev_lock);
+ read_unlock(&rfcomm_dev_lock);
return dev;
}
@@ -195,8 +198,8 @@
static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
{
- struct rfcomm_dev *dev, *entry;
- struct list_head *head = &rfcomm_dev_list;
+ struct rfcomm_dev *dev;
+ struct list_head *head = &rfcomm_dev_list, *p;
int err = 0;
BT_DBG("id %d channel %d", req->dev_id, req->channel);
@@ -205,22 +208,24 @@
if (!dev)
return -ENOMEM;
- spin_lock(&rfcomm_dev_lock);
+ write_lock_bh(&rfcomm_dev_lock);
if (req->dev_id < 0) {
dev->id = 0;
- list_for_each_entry(entry, &rfcomm_dev_list, list) {
- if (entry->id != dev->id)
+ list_for_each(p, &rfcomm_dev_list) {
+ if (list_entry(p, struct rfcomm_dev, list)->id != dev->id)
break;
dev->id++;
- head = &entry->list;
+ head = p;
}
} else {
dev->id = req->dev_id;
- list_for_each_entry(entry, &rfcomm_dev_list, list) {
+ list_for_each(p, &rfcomm_dev_list) {
+ struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list);
+
if (entry->id == dev->id) {
err = -EADDRINUSE;
goto out;
@@ -229,7 +234,7 @@
if (entry->id > dev->id - 1)
break;
- head = &entry->list;
+ head = p;
}
}
@@ -253,7 +258,7 @@
atomic_set(&dev->opened, 0);
init_waitqueue_head(&dev->wait);
- INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup);
+ tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
skb_queue_head_init(&dev->pending);
@@ -290,7 +295,7 @@
__module_get(THIS_MODULE);
out:
- spin_unlock(&rfcomm_dev_lock);
+ write_unlock_bh(&rfcomm_dev_lock);
if (err < 0)
goto free;
@@ -327,9 +332,9 @@
if (atomic_read(&dev->opened) > 0)
return;
- spin_lock(&rfcomm_dev_lock);
+ write_lock_bh(&rfcomm_dev_lock);
list_del_init(&dev->list);
- spin_unlock(&rfcomm_dev_lock);
+ write_unlock_bh(&rfcomm_dev_lock);
rfcomm_dev_put(dev);
}
@@ -347,7 +352,7 @@
struct rfcomm_dev *dev = (void *) skb->sk;
atomic_sub(skb->truesize, &dev->wmem_alloc);
if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
- queue_work(system_nrt_wq, &dev->wakeup_task);
+ tasklet_schedule(&dev->wakeup_task);
rfcomm_dev_put(dev);
}
@@ -451,9 +456,9 @@
static int rfcomm_get_dev_list(void __user *arg)
{
- struct rfcomm_dev *dev;
struct rfcomm_dev_list_req *dl;
struct rfcomm_dev_info *di;
+ struct list_head *p;
int n = 0, size, err;
u16 dev_num;
@@ -473,9 +478,10 @@
di = dl->dev_info;
- spin_lock(&rfcomm_dev_lock);
+ read_lock_bh(&rfcomm_dev_lock);
- list_for_each_entry(dev, &rfcomm_dev_list, list) {
+ list_for_each(p, &rfcomm_dev_list) {
+ struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
continue;
(di + n)->id = dev->id;
@@ -488,7 +494,7 @@
break;
}
- spin_unlock(&rfcomm_dev_lock);
+ read_unlock_bh(&rfcomm_dev_lock);
dl->dev_num = n;
size = sizeof(*dl) + n * sizeof(*di);
@@ -630,10 +636,9 @@
}
/* ---- TTY functions ---- */
-static void rfcomm_tty_wakeup(struct work_struct *work)
+static void rfcomm_tty_wakeup(unsigned long arg)
{
- struct rfcomm_dev *dev = container_of(work, struct rfcomm_dev,
- wakeup_task);
+ struct rfcomm_dev *dev = (void *) arg;
struct tty_struct *tty = dev->tty;
if (!tty)
return;
@@ -758,7 +763,7 @@
rfcomm_dlc_close(dev->dlc, 0);
clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
- cancel_work_sync(&dev->wakeup_task);
+ tasklet_kill(&dev->wakeup_task);
rfcomm_dlc_lock(dev->dlc);
tty->driver_data = NULL;
@@ -766,9 +771,9 @@
rfcomm_dlc_unlock(dev->dlc);
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) {
- spin_lock(&rfcomm_dev_lock);
+ write_lock_bh(&rfcomm_dev_lock);
list_del_init(&dev->list);
- spin_unlock(&rfcomm_dev_lock);
+ write_unlock_bh(&rfcomm_dev_lock);
rfcomm_dev_put(dev);
}
@@ -1151,12 +1156,11 @@
int __init rfcomm_init_ttys(void)
{
- int error;
-
rfcomm_tty_driver = alloc_tty_driver(RFCOMM_TTY_PORTS);
if (!rfcomm_tty_driver)
- return -ENOMEM;
+ return -1;
+ rfcomm_tty_driver->owner = THIS_MODULE;
rfcomm_tty_driver->driver_name = "rfcomm";
rfcomm_tty_driver->name = "rfcomm";
rfcomm_tty_driver->major = RFCOMM_TTY_MAJOR;
@@ -1169,11 +1173,10 @@
rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
- error = tty_register_driver(rfcomm_tty_driver);
- if (error) {
+ if (tty_register_driver(rfcomm_tty_driver)) {
BT_ERR("Can't register RFCOMM TTY driver");
put_tty_driver(rfcomm_tty_driver);
- return error;
+ return -1;
}
BT_INFO("RFCOMM TTY layer initialized");