206 changes: 92 additions & 114 deletions net/bluetooth/hidp/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ static void __hidp_unlink_session(struct hidp_session *session)
module_put(THIS_MODULE);
}

static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
static void hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
{
memset(ci, 0, sizeof(*ci));
bacpy(&ci->bdaddr, &session->bdaddr);
Expand Down Expand Up @@ -151,58 +151,80 @@ static void __hidp_copy_session(struct hidp_session *session, struct hidp_connin
}
}

static int hidp_queue_event(struct hidp_session *session, struct input_dev *dev,
unsigned int type, unsigned int code, int value)
/* assemble skb, queue message on @transmit and wake up the session thread */
static int hidp_send_message(struct hidp_session *session, struct socket *sock,
struct sk_buff_head *transmit, unsigned char hdr,
const unsigned char *data, int size)
{
unsigned char newleds;
struct sk_buff *skb;
struct sock *sk = sock->sk;

BT_DBG("session %p type %d code %d value %d", session, type, code, value);

if (type != EV_LED)
return -1;

newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
(!!test_bit(LED_COMPOSE, dev->led) << 3) |
(!!test_bit(LED_SCROLLL, dev->led) << 2) |
(!!test_bit(LED_CAPSL, dev->led) << 1) |
(!!test_bit(LED_NUML, dev->led));

if (session->leds == newleds)
return 0;
BT_DBG("session %p data %p size %d", session, data, size);

session->leds = newleds;
if (atomic_read(&session->terminate))
return -EIO;

skb = alloc_skb(3, GFP_ATOMIC);
skb = alloc_skb(size + 1, GFP_ATOMIC);
if (!skb) {
BT_ERR("Can't allocate memory for new frame");
return -ENOMEM;
}

*skb_put(skb, 1) = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
*skb_put(skb, 1) = 0x01;
*skb_put(skb, 1) = newleds;

skb_queue_tail(&session->intr_transmit, skb);
*skb_put(skb, 1) = hdr;
if (data && size > 0)
memcpy(skb_put(skb, size), data, size);

hidp_schedule(session);
skb_queue_tail(transmit, skb);
wake_up_interruptible(sk_sleep(sk));

return 0;
}

static int hidp_hidinput_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
static int hidp_send_ctrl_message(struct hidp_session *session,
unsigned char hdr, const unsigned char *data,
int size)
{
struct hid_device *hid = input_get_drvdata(dev);
struct hidp_session *session = hid->driver_data;
return hidp_send_message(session, session->ctrl_sock,
&session->ctrl_transmit, hdr, data, size);
}

return hidp_queue_event(session, dev, type, code, value);
static int hidp_send_intr_message(struct hidp_session *session,
unsigned char hdr, const unsigned char *data,
int size)
{
return hidp_send_message(session, session->intr_sock,
&session->intr_transmit, hdr, data, size);
}

static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
static int hidp_input_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
struct hidp_session *session = input_get_drvdata(dev);
unsigned char newleds;
unsigned char hdr, data[2];

BT_DBG("session %p type %d code %d value %d",
session, type, code, value);

return hidp_queue_event(session, dev, type, code, value);
if (type != EV_LED)
return -1;

newleds = (!!test_bit(LED_KANA, dev->led) << 3) |
(!!test_bit(LED_COMPOSE, dev->led) << 3) |
(!!test_bit(LED_SCROLLL, dev->led) << 2) |
(!!test_bit(LED_CAPSL, dev->led) << 1) |
(!!test_bit(LED_NUML, dev->led));

if (session->leds == newleds)
return 0;

session->leds = newleds;

hdr = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
data[0] = 0x01;
data[1] = newleds;

return hidp_send_intr_message(session, hdr, data, 2);
}

static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
Expand Down Expand Up @@ -260,94 +282,61 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
input_sync(dev);
}

static int __hidp_send_ctrl_message(struct hidp_session *session,
unsigned char hdr, unsigned char *data, int size)
static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
{
struct sk_buff *skb;

BT_DBG("session %p data %p size %d", session, data, size);

skb = alloc_skb(size + 1, GFP_ATOMIC);
if (!skb) {
BT_ERR("Can't allocate memory for new frame");
return -ENOMEM;
}
unsigned char buf[32], hdr;
int rsize;

*skb_put(skb, 1) = hdr;
if (data && size > 0)
memcpy(skb_put(skb, size), data, size);
rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
if (rsize > sizeof(buf))
return -EIO;

skb_queue_tail(&session->ctrl_transmit, skb);
hid_output_report(report, buf);
hdr = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;

return 0;
return hidp_send_intr_message(session, hdr, buf, rsize);
}

static inline int hidp_send_ctrl_message(struct hidp_session *session,
unsigned char hdr, unsigned char *data, int size)
static int hidp_hidinput_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
int err;

err = __hidp_send_ctrl_message(session, hdr, data, size);

hidp_schedule(session);

return err;
}
struct hid_device *hid = input_get_drvdata(dev);
struct hidp_session *session = hid->driver_data;
struct hid_field *field;
int offset;

static int hidp_queue_report(struct hidp_session *session,
unsigned char *data, int size)
{
struct sk_buff *skb;
BT_DBG("session %p type %d code %d value %d",
session, type, code, value);

BT_DBG("session %p hid %p data %p size %d", session, session->hid, data, size);
if (type != EV_LED)
return -1;

skb = alloc_skb(size + 1, GFP_ATOMIC);
if (!skb) {
BT_ERR("Can't allocate memory for new frame");
return -ENOMEM;
offset = hidinput_find_field(hid, type, code, &field);
if (offset == -1) {
hid_warn(dev, "event field not found\n");
return -1;
}

*skb_put(skb, 1) = 0xa2;
if (size > 0)
memcpy(skb_put(skb, size), data, size);

skb_queue_tail(&session->intr_transmit, skb);
hid_set_field(field, offset, value);

hidp_schedule(session);

return 0;
}

static int hidp_send_report(struct hidp_session *session, struct hid_report *report)
{
unsigned char buf[32];
int rsize;

rsize = ((report->size - 1) >> 3) + 1 + (report->id > 0);
if (rsize > sizeof(buf))
return -EIO;

hid_output_report(report, buf);

return hidp_queue_report(session, buf, rsize);
return hidp_send_report(session, field->report);
}

static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
unsigned char report_type)
{
switch (report_type) {
case HID_FEATURE_REPORT:
report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
break;
case HID_OUTPUT_REPORT:
struct hidp_session *session = hid->driver_data;

if (report_type == HID_OUTPUT_REPORT) {
report_type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
break;
default:
return hidp_send_intr_message(session, report_type,
data, count);
} else if (report_type != HID_FEATURE_REPORT) {
return -EINVAL;
}

if (hidp_send_ctrl_message(hid->driver_data, report_type,
data, count))
report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
if (hidp_send_ctrl_message(session, report_type, data, count))
return -ENOMEM;
return count;
}
Expand Down Expand Up @@ -395,12 +384,12 @@ static void hidp_process_handshake(struct hidp_session *session,
case HIDP_HSHK_ERR_FATAL:
/* Device requests a reboot, as this is the only way this error
* can be recovered. */
__hidp_send_ctrl_message(session,
hidp_send_ctrl_message(session,
HIDP_TRANS_HID_CONTROL | HIDP_CTRL_SOFT_RESET, NULL, 0);
break;

default:
__hidp_send_ctrl_message(session,
hidp_send_ctrl_message(session,
HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
break;
}
Expand Down Expand Up @@ -445,7 +434,7 @@ static void hidp_process_data(struct hidp_session *session, struct sk_buff *skb,
break;

default:
__hidp_send_ctrl_message(session,
hidp_send_ctrl_message(session,
HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_INVALID_PARAMETER, NULL, 0);
}
}
Expand Down Expand Up @@ -477,7 +466,7 @@ static void hidp_recv_ctrl_frame(struct hidp_session *session,
break;

default:
__hidp_send_ctrl_message(session,
hidp_send_ctrl_message(session,
HIDP_TRANS_HANDSHAKE | HIDP_HSHK_ERR_UNSUPPORTED_REQUEST, NULL, 0);
break;
}
Expand Down Expand Up @@ -751,17 +740,6 @@ static int hidp_parse(struct hid_device *hid)

static int hidp_start(struct hid_device *hid)
{
struct hidp_session *session = hid->driver_data;
struct hid_report *report;

list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
report_list, list)
hidp_send_report(session, report);

list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].
report_list, list)
hidp_send_report(session, report);

return 0;
}

Expand Down Expand Up @@ -1003,7 +981,7 @@ int hidp_get_connlist(struct hidp_connlist_req *req)

session = list_entry(p, struct hidp_session, list);

__hidp_copy_session(session, &ci);
hidp_copy_session(session, &ci);

if (copy_to_user(req->ci, &ci, sizeof(ci))) {
err = -EFAULT;
Expand All @@ -1030,7 +1008,7 @@ int hidp_get_conninfo(struct hidp_conninfo *ci)

session = __hidp_get_session(&ci->bdaddr);
if (session)
__hidp_copy_session(session, ci);
hidp_copy_session(session, ci);
else
err = -ENOENT;

Expand Down
15 changes: 0 additions & 15 deletions net/bluetooth/mgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -3399,21 +3399,6 @@ int mgmt_remote_class(u16 index, bdaddr_t *bdaddr, u8 dev_class[3])
return mgmt_event(MGMT_EV_REMOTE_CLASS, index, &ev, sizeof(ev), NULL);
}

int mgmt_remote_version(u16 index, bdaddr_t *bdaddr, u8 ver, u16 mnf,
u16 sub_ver)
{
struct mgmt_ev_remote_version ev;

memset(&ev, 0, sizeof(ev));

bacpy(&ev.bdaddr, bdaddr);
ev.lmp_ver = ver;
ev.manufacturer = mnf;
ev.lmp_subver = sub_ver;

return mgmt_event(MGMT_EV_REMOTE_VERSION, index, &ev, sizeof(ev), NULL);
}

int mgmt_remote_features(u16 index, bdaddr_t *bdaddr, u8 features[8])
{
struct mgmt_ev_remote_features ev;
Expand Down
8 changes: 0 additions & 8 deletions net/bluetooth/sco.c
Original file line number Diff line number Diff line change
Expand Up @@ -814,9 +814,6 @@ static int sco_sock_shutdown(struct socket *sock, int how)
if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
err = bt_sock_wait_state(sk, BT_CLOSED,
sk->sk_lingertime);
else
err = bt_sock_wait_state(sk, BT_CLOSED,
SCO_DISCONN_TIMEOUT);
}
release_sock(sk);
return err;
Expand All @@ -838,11 +835,6 @@ static int sco_sock_release(struct socket *sock)
lock_sock(sk);
err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
release_sock(sk);
} else {
lock_sock(sk);
err = bt_sock_wait_state(sk, BT_CLOSED,
SCO_DISCONN_TIMEOUT);
release_sock(sk);
}

sock_orphan(sk);
Expand Down