2 HIDP implementation for Linux Bluetooth stack (BlueZ).
3 Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
23 #include <linux/config.h>
24 #include <linux/module.h>
26 #include <linux/types.h>
27 #include <linux/errno.h>
28 #include <linux/kernel.h>
29 #include <linux/sched.h>
30 #include <linux/slab.h>
31 #include <linux/poll.h>
32 #include <linux/fcntl.h>
33 #include <linux/skbuff.h>
34 #include <linux/socket.h>
35 #include <linux/ioctl.h>
36 #include <linux/file.h>
37 #include <linux/init.h>
38 #include <linux/wait.h>
41 #include <linux/input.h>
43 #include <net/bluetooth/bluetooth.h>
44 #include <net/bluetooth/l2cap.h>
48 #ifndef CONFIG_BT_HIDP_DEBUG
55 static DECLARE_RWSEM(hidp_session_sem
);
56 static LIST_HEAD(hidp_session_list
);
58 static unsigned char hidp_keycode
[256] = {
59 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
60 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3,
61 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26,
62 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
63 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
64 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
65 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190,
66 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113,
67 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0,
68 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
71 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
72 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
74 150,158,159,128,136,177,178,176,142,152,173,140
77 static unsigned char hidp_mkeyspat
[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
79 static struct hidp_session
*__hidp_get_session(bdaddr_t
*bdaddr
)
81 struct hidp_session
*session
;
86 list_for_each(p
, &hidp_session_list
) {
87 session
= list_entry(p
, struct hidp_session
, list
);
88 if (!bacmp(bdaddr
, &session
->bdaddr
))
94 static void __hidp_link_session(struct hidp_session
*session
)
96 __module_get(THIS_MODULE
);
97 list_add(&session
->list
, &hidp_session_list
);
100 static void __hidp_unlink_session(struct hidp_session
*session
)
102 list_del(&session
->list
);
103 module_put(THIS_MODULE
);
106 static void __hidp_copy_session(struct hidp_session
*session
, struct hidp_conninfo
*ci
)
108 bacpy(&ci
->bdaddr
, &session
->bdaddr
);
110 ci
->flags
= session
->flags
;
111 ci
->state
= session
->state
;
114 ci
->product
= 0x0000;
115 ci
->version
= 0x0000;
116 memset(ci
->name
, 0, 128);
118 if (session
->input
) {
119 ci
->vendor
= session
->input
->id
.vendor
;
120 ci
->product
= session
->input
->id
.product
;
121 ci
->version
= session
->input
->id
.version
;
122 if (session
->input
->name
)
123 strncpy(ci
->name
, session
->input
->name
, 128);
125 strncpy(ci
->name
, "HID Boot Device", 128);
129 static int hidp_input_event(struct input_dev
*dev
, unsigned int type
, unsigned int code
, int value
)
131 struct hidp_session
*session
= dev
->private;
133 unsigned char newleds
;
135 BT_DBG("input %p type %d code %d value %d", dev
, type
, code
, value
);
140 newleds
= (!!test_bit(LED_KANA
, dev
->led
) << 3) |
141 (!!test_bit(LED_COMPOSE
, dev
->led
) << 3) |
142 (!!test_bit(LED_SCROLLL
, dev
->led
) << 2) |
143 (!!test_bit(LED_CAPSL
, dev
->led
) << 1) |
144 (!!test_bit(LED_NUML
, dev
->led
));
146 if (session
->leds
== newleds
)
149 session
->leds
= newleds
;
151 if (!(skb
= alloc_skb(3, GFP_ATOMIC
))) {
152 BT_ERR("Can't allocate memory for new frame");
156 *skb_put(skb
, 1) = HIDP_TRANS_DATA
| HIDP_DATA_RTYPE_OUPUT
;
157 *skb_put(skb
, 1) = 0x01;
158 *skb_put(skb
, 1) = newleds
;
160 skb_queue_tail(&session
->intr_transmit
, skb
);
162 hidp_schedule(session
);
167 static void hidp_input_report(struct hidp_session
*session
, struct sk_buff
*skb
)
169 struct input_dev
*dev
= session
->input
;
170 unsigned char *keys
= session
->keys
;
171 unsigned char *udata
= skb
->data
+ 1;
172 signed char *sdata
= skb
->data
+ 1;
173 int i
, size
= skb
->len
- 1;
175 switch (skb
->data
[0]) {
176 case 0x01: /* Keyboard report */
177 for (i
= 0; i
< 8; i
++)
178 input_report_key(dev
, hidp_keycode
[i
+ 224], (udata
[0] >> i
) & 1);
180 /* If all the key codes have been set to 0x01, it means
181 * too many keys were pressed at the same time. */
182 if (!memcmp(udata
+ 2, hidp_mkeyspat
, 6))
185 for (i
= 2; i
< 8; i
++) {
186 if (keys
[i
] > 3 && memscan(udata
+ 2, keys
[i
], 6) == udata
+ 8) {
187 if (hidp_keycode
[keys
[i
]])
188 input_report_key(dev
, hidp_keycode
[keys
[i
]], 0);
190 BT_ERR("Unknown key (scancode %#x) released.", keys
[i
]);
193 if (udata
[i
] > 3 && memscan(keys
+ 2, udata
[i
], 6) == keys
+ 8) {
194 if (hidp_keycode
[udata
[i
]])
195 input_report_key(dev
, hidp_keycode
[udata
[i
]], 1);
197 BT_ERR("Unknown key (scancode %#x) pressed.", udata
[i
]);
201 memcpy(keys
, udata
, 8);
204 case 0x02: /* Mouse report */
205 input_report_key(dev
, BTN_LEFT
, sdata
[0] & 0x01);
206 input_report_key(dev
, BTN_RIGHT
, sdata
[0] & 0x02);
207 input_report_key(dev
, BTN_MIDDLE
, sdata
[0] & 0x04);
208 input_report_key(dev
, BTN_SIDE
, sdata
[0] & 0x08);
209 input_report_key(dev
, BTN_EXTRA
, sdata
[0] & 0x10);
211 input_report_rel(dev
, REL_X
, sdata
[1]);
212 input_report_rel(dev
, REL_Y
, sdata
[2]);
215 input_report_rel(dev
, REL_WHEEL
, sdata
[3]);
222 static void hidp_idle_timeout(unsigned long arg
)
224 struct hidp_session
*session
= (struct hidp_session
*) arg
;
226 atomic_inc(&session
->terminate
);
227 hidp_schedule(session
);
230 static inline void hidp_set_timer(struct hidp_session
*session
)
232 if (session
->idle_to
> 0)
233 mod_timer(&session
->timer
, jiffies
+ HZ
* session
->idle_to
);
236 static inline void hidp_del_timer(struct hidp_session
*session
)
238 if (session
->idle_to
> 0)
239 del_timer(&session
->timer
);
242 static int __hidp_send_ctrl_message(struct hidp_session
*session
,
243 unsigned char hdr
, unsigned char *data
, int size
)
247 BT_DBG("session %p data %p size %d", session
, data
, size
);
249 if (!(skb
= alloc_skb(size
+ 1, GFP_ATOMIC
))) {
250 BT_ERR("Can't allocate memory for new frame");
254 *skb_put(skb
, 1) = hdr
;
255 if (data
&& size
> 0)
256 memcpy(skb_put(skb
, size
), data
, size
);
258 skb_queue_tail(&session
->ctrl_transmit
, skb
);
263 static int inline hidp_send_ctrl_message(struct hidp_session
*session
,
264 unsigned char hdr
, unsigned char *data
, int size
)
268 err
= __hidp_send_ctrl_message(session
, hdr
, data
, size
);
270 hidp_schedule(session
);
275 static inline void hidp_process_handshake(struct hidp_session
*session
, unsigned char param
)
277 BT_DBG("session %p param 0x%02x", session
, param
);
280 case HIDP_HSHK_SUCCESSFUL
:
281 /* FIXME: Call into SET_ GET_ handlers here */
284 case HIDP_HSHK_NOT_READY
:
285 case HIDP_HSHK_ERR_INVALID_REPORT_ID
:
286 case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST
:
287 case HIDP_HSHK_ERR_INVALID_PARAMETER
:
288 /* FIXME: Call into SET_ GET_ handlers here */
291 case HIDP_HSHK_ERR_UNKNOWN
:
294 case HIDP_HSHK_ERR_FATAL
:
295 /* Device requests a reboot, as this is the only way this error
296 * can be recovered. */
297 __hidp_send_ctrl_message(session
,
298 HIDP_TRANS_HID_CONTROL
| HIDP_CTRL_SOFT_RESET
, NULL
, 0);
302 __hidp_send_ctrl_message(session
,
303 HIDP_TRANS_HANDSHAKE
| HIDP_HSHK_ERR_INVALID_PARAMETER
, NULL
, 0);
308 static inline void hidp_process_hid_control(struct hidp_session
*session
, unsigned char param
)
310 BT_DBG("session %p param 0x%02x", session
, param
);
316 case HIDP_CTRL_VIRTUAL_CABLE_UNPLUG
:
317 /* Flush the transmit queues */
318 skb_queue_purge(&session
->ctrl_transmit
);
319 skb_queue_purge(&session
->intr_transmit
);
321 /* Kill session thread */
322 atomic_inc(&session
->terminate
);
325 case HIDP_CTRL_HARD_RESET
:
326 case HIDP_CTRL_SOFT_RESET
:
327 case HIDP_CTRL_SUSPEND
:
328 case HIDP_CTRL_EXIT_SUSPEND
:
329 /* FIXME: We have to parse these and return no error */
333 __hidp_send_ctrl_message(session
,
334 HIDP_TRANS_HANDSHAKE
| HIDP_HSHK_ERR_INVALID_PARAMETER
, NULL
, 0);
339 static inline void hidp_process_data(struct hidp_session
*session
, struct sk_buff
*skb
, unsigned char param
)
341 BT_DBG("session %p skb %p len %d param 0x%02x", session
, skb
, skb
->len
, param
);
344 case HIDP_DATA_RTYPE_INPUT
:
345 hidp_set_timer(session
);
348 hidp_input_report(session
, skb
);
351 case HIDP_DATA_RTYPE_OTHER
:
352 case HIDP_DATA_RTYPE_OUPUT
:
353 case HIDP_DATA_RTYPE_FEATURE
:
357 __hidp_send_ctrl_message(session
,
358 HIDP_TRANS_HANDSHAKE
| HIDP_HSHK_ERR_INVALID_PARAMETER
, NULL
, 0);
362 static inline void hidp_recv_ctrl_frame(struct hidp_session
*session
, struct sk_buff
*skb
)
364 unsigned char hdr
, type
, param
;
366 BT_DBG("session %p skb %p len %d", session
, skb
, skb
->len
);
371 type
= hdr
& HIDP_HEADER_TRANS_MASK
;
372 param
= hdr
& HIDP_HEADER_PARAM_MASK
;
375 case HIDP_TRANS_HANDSHAKE
:
376 hidp_process_handshake(session
, param
);
379 case HIDP_TRANS_HID_CONTROL
:
380 hidp_process_hid_control(session
, param
);
383 case HIDP_TRANS_DATA
:
384 hidp_process_data(session
, skb
, param
);
388 __hidp_send_ctrl_message(session
,
389 HIDP_TRANS_HANDSHAKE
| HIDP_HSHK_ERR_UNSUPPORTED_REQUEST
, NULL
, 0);
396 static inline void hidp_recv_intr_frame(struct hidp_session
*session
, struct sk_buff
*skb
)
400 BT_DBG("session %p skb %p len %d", session
, skb
, skb
->len
);
405 if (hdr
== (HIDP_TRANS_DATA
| HIDP_DATA_RTYPE_INPUT
)) {
406 hidp_set_timer(session
);
408 hidp_input_report(session
, skb
);
410 BT_DBG("Unsupported protocol header 0x%02x", hdr
);
416 static int hidp_send_frame(struct socket
*sock
, unsigned char *data
, int len
)
418 struct kvec iv
= { data
, len
};
421 BT_DBG("sock %p data %p len %d", sock
, data
, len
);
426 memset(&msg
, 0, sizeof(msg
));
428 return kernel_sendmsg(sock
, &msg
, &iv
, 1, len
);
431 static int hidp_process_transmit(struct hidp_session
*session
)
435 BT_DBG("session %p", session
);
437 while ((skb
= skb_dequeue(&session
->ctrl_transmit
))) {
438 if (hidp_send_frame(session
->ctrl_sock
, skb
->data
, skb
->len
) < 0) {
439 skb_queue_head(&session
->ctrl_transmit
, skb
);
443 hidp_set_timer(session
);
447 while ((skb
= skb_dequeue(&session
->intr_transmit
))) {
448 if (hidp_send_frame(session
->intr_sock
, skb
->data
, skb
->len
) < 0) {
449 skb_queue_head(&session
->intr_transmit
, skb
);
453 hidp_set_timer(session
);
457 return skb_queue_len(&session
->ctrl_transmit
) +
458 skb_queue_len(&session
->intr_transmit
);
461 static int hidp_session(void *arg
)
463 struct hidp_session
*session
= arg
;
464 struct sock
*ctrl_sk
= session
->ctrl_sock
->sk
;
465 struct sock
*intr_sk
= session
->intr_sock
->sk
;
467 int vendor
= 0x0000, product
= 0x0000;
468 wait_queue_t ctrl_wait
, intr_wait
;
470 BT_DBG("session %p", session
);
472 if (session
->input
) {
473 vendor
= session
->input
->id
.vendor
;
474 product
= session
->input
->id
.product
;
477 daemonize("khidpd_%04x%04x", vendor
, product
);
478 set_user_nice(current
, -15);
479 current
->flags
|= PF_NOFREEZE
;
481 init_waitqueue_entry(&ctrl_wait
, current
);
482 init_waitqueue_entry(&intr_wait
, current
);
483 add_wait_queue(ctrl_sk
->sk_sleep
, &ctrl_wait
);
484 add_wait_queue(intr_sk
->sk_sleep
, &intr_wait
);
485 while (!atomic_read(&session
->terminate
)) {
486 set_current_state(TASK_INTERRUPTIBLE
);
488 if (ctrl_sk
->sk_state
!= BT_CONNECTED
|| intr_sk
->sk_state
!= BT_CONNECTED
)
491 while ((skb
= skb_dequeue(&ctrl_sk
->sk_receive_queue
))) {
493 hidp_recv_ctrl_frame(session
, skb
);
496 while ((skb
= skb_dequeue(&intr_sk
->sk_receive_queue
))) {
498 hidp_recv_intr_frame(session
, skb
);
501 hidp_process_transmit(session
);
505 set_current_state(TASK_RUNNING
);
506 remove_wait_queue(intr_sk
->sk_sleep
, &intr_wait
);
507 remove_wait_queue(ctrl_sk
->sk_sleep
, &ctrl_wait
);
509 down_write(&hidp_session_sem
);
511 hidp_del_timer(session
);
513 if (intr_sk
->sk_state
!= BT_CONNECTED
)
514 wait_event_timeout(*(ctrl_sk
->sk_sleep
), (ctrl_sk
->sk_state
== BT_CLOSED
), HZ
);
516 fput(session
->ctrl_sock
->file
);
518 wait_event_timeout(*(intr_sk
->sk_sleep
), (intr_sk
->sk_state
== BT_CLOSED
), HZ
);
520 fput(session
->intr_sock
->file
);
522 __hidp_unlink_session(session
);
524 if (session
->input
) {
525 input_unregister_device(session
->input
);
526 kfree(session
->input
);
529 up_write(&hidp_session_sem
);
535 static inline void hidp_setup_input(struct hidp_session
*session
, struct hidp_connadd_req
*req
)
537 struct input_dev
*input
= session
->input
;
540 input
->private = session
;
542 input
->id
.bustype
= BUS_BLUETOOTH
;
543 input
->id
.vendor
= req
->vendor
;
544 input
->id
.product
= req
->product
;
545 input
->id
.version
= req
->version
;
547 if (req
->subclass
& 0x40) {
548 set_bit(EV_KEY
, input
->evbit
);
549 set_bit(EV_LED
, input
->evbit
);
550 set_bit(EV_REP
, input
->evbit
);
552 set_bit(LED_NUML
, input
->ledbit
);
553 set_bit(LED_CAPSL
, input
->ledbit
);
554 set_bit(LED_SCROLLL
, input
->ledbit
);
555 set_bit(LED_COMPOSE
, input
->ledbit
);
556 set_bit(LED_KANA
, input
->ledbit
);
558 for (i
= 0; i
< sizeof(hidp_keycode
); i
++)
559 set_bit(hidp_keycode
[i
], input
->keybit
);
560 clear_bit(0, input
->keybit
);
563 if (req
->subclass
& 0x80) {
564 input
->evbit
[0] = BIT(EV_KEY
) | BIT(EV_REL
);
565 input
->keybit
[LONG(BTN_MOUSE
)] = BIT(BTN_LEFT
) | BIT(BTN_RIGHT
) | BIT(BTN_MIDDLE
);
566 input
->relbit
[0] = BIT(REL_X
) | BIT(REL_Y
);
567 input
->keybit
[LONG(BTN_MOUSE
)] |= BIT(BTN_SIDE
) | BIT(BTN_EXTRA
);
568 input
->relbit
[0] |= BIT(REL_WHEEL
);
571 input
->event
= hidp_input_event
;
573 input_register_device(input
);
576 int hidp_add_connection(struct hidp_connadd_req
*req
, struct socket
*ctrl_sock
, struct socket
*intr_sock
)
578 struct hidp_session
*session
, *s
;
583 if (bacmp(&bt_sk(ctrl_sock
->sk
)->src
, &bt_sk(intr_sock
->sk
)->src
) ||
584 bacmp(&bt_sk(ctrl_sock
->sk
)->dst
, &bt_sk(intr_sock
->sk
)->dst
))
587 session
= kmalloc(sizeof(struct hidp_session
), GFP_KERNEL
);
590 memset(session
, 0, sizeof(struct hidp_session
));
592 session
->input
= kmalloc(sizeof(struct input_dev
), GFP_KERNEL
);
593 if (!session
->input
) {
597 memset(session
->input
, 0, sizeof(struct input_dev
));
599 down_write(&hidp_session_sem
);
601 s
= __hidp_get_session(&bt_sk(ctrl_sock
->sk
)->dst
);
602 if (s
&& s
->state
== BT_CONNECTED
) {
607 bacpy(&session
->bdaddr
, &bt_sk(ctrl_sock
->sk
)->dst
);
609 session
->ctrl_mtu
= min_t(uint
, l2cap_pi(ctrl_sock
->sk
)->omtu
, l2cap_pi(ctrl_sock
->sk
)->imtu
);
610 session
->intr_mtu
= min_t(uint
, l2cap_pi(intr_sock
->sk
)->omtu
, l2cap_pi(intr_sock
->sk
)->imtu
);
612 BT_DBG("ctrl mtu %d intr mtu %d", session
->ctrl_mtu
, session
->intr_mtu
);
614 session
->ctrl_sock
= ctrl_sock
;
615 session
->intr_sock
= intr_sock
;
616 session
->state
= BT_CONNECTED
;
618 init_timer(&session
->timer
);
620 session
->timer
.function
= hidp_idle_timeout
;
621 session
->timer
.data
= (unsigned long) session
;
623 skb_queue_head_init(&session
->ctrl_transmit
);
624 skb_queue_head_init(&session
->intr_transmit
);
626 session
->flags
= req
->flags
& (1 << HIDP_BLUETOOTH_VENDOR_ID
);
627 session
->idle_to
= req
->idle_to
;
630 hidp_setup_input(session
, req
);
632 __hidp_link_session(session
);
634 hidp_set_timer(session
);
636 err
= kernel_thread(hidp_session
, session
, CLONE_KERNEL
);
640 if (session
->input
) {
641 hidp_send_ctrl_message(session
,
642 HIDP_TRANS_SET_PROTOCOL
| HIDP_PROTO_BOOT
, NULL
, 0);
643 session
->flags
|= (1 << HIDP_BOOT_PROTOCOL_MODE
);
645 session
->leds
= 0xff;
646 hidp_input_event(session
->input
, EV_LED
, 0, 0);
649 up_write(&hidp_session_sem
);
653 hidp_del_timer(session
);
655 __hidp_unlink_session(session
);
658 input_unregister_device(session
->input
);
661 up_write(&hidp_session_sem
);
664 kfree(session
->input
);
670 int hidp_del_connection(struct hidp_conndel_req
*req
)
672 struct hidp_session
*session
;
677 down_read(&hidp_session_sem
);
679 session
= __hidp_get_session(&req
->bdaddr
);
681 if (req
->flags
& (1 << HIDP_VIRTUAL_CABLE_UNPLUG
)) {
682 hidp_send_ctrl_message(session
,
683 HIDP_TRANS_HID_CONTROL
| HIDP_CTRL_VIRTUAL_CABLE_UNPLUG
, NULL
, 0);
685 /* Flush the transmit queues */
686 skb_queue_purge(&session
->ctrl_transmit
);
687 skb_queue_purge(&session
->intr_transmit
);
689 /* Kill session thread */
690 atomic_inc(&session
->terminate
);
691 hidp_schedule(session
);
696 up_read(&hidp_session_sem
);
700 int hidp_get_connlist(struct hidp_connlist_req
*req
)
707 down_read(&hidp_session_sem
);
709 list_for_each(p
, &hidp_session_list
) {
710 struct hidp_session
*session
;
711 struct hidp_conninfo ci
;
713 session
= list_entry(p
, struct hidp_session
, list
);
715 __hidp_copy_session(session
, &ci
);
717 if (copy_to_user(req
->ci
, &ci
, sizeof(ci
))) {
722 if (++n
>= req
->cnum
)
729 up_read(&hidp_session_sem
);
733 int hidp_get_conninfo(struct hidp_conninfo
*ci
)
735 struct hidp_session
*session
;
738 down_read(&hidp_session_sem
);
740 session
= __hidp_get_session(&ci
->bdaddr
);
742 __hidp_copy_session(session
, ci
);
746 up_read(&hidp_session_sem
);
750 static int __init
hidp_init(void)
754 BT_INFO("HIDP (Human Interface Emulation) ver %s", VERSION
);
756 return hidp_init_sockets();
759 static void __exit
hidp_exit(void)
761 hidp_cleanup_sockets();
764 module_init(hidp_init
);
765 module_exit(hidp_exit
);
767 MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
768 MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION
);
769 MODULE_VERSION(VERSION
);
770 MODULE_LICENSE("GPL");
771 MODULE_ALIAS("bt-proto-6");