diff options
Diffstat (limited to 'recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-mh1.patch')
-rw-r--r-- | recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-mh1.patch | 1134 |
1 files changed, 1134 insertions, 0 deletions
diff --git a/recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-mh1.patch b/recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-mh1.patch new file mode 100644 index 0000000000..f5379f0077 --- /dev/null +++ b/recipes/linux/opensimpad-2.4.27-vrs1-pxa1-jpm1/2.4.27-mh1.patch @@ -0,0 +1,1134 @@ + +# +# Patch managed by http://www.holgerschurig.de/patcher.html +# + +--- linux-2.4.27/arch/sparc64/kernel/ioctl32.c~patch-2.4.27-mh1 ++++ linux-2.4.27/arch/sparc64/kernel/ioctl32.c +@@ -4322,6 +4322,11 @@ + #define CMTPGETCONNLIST _IOR('C', 210, int) + #define CMTPGETCONNINFO _IOR('C', 211, int) + ++#define HIDPCONNADD _IOW('H', 200, int) ++#define HIDPCONNDEL _IOW('H', 201, int) ++#define HIDPGETCONNLIST _IOR('H', 210, int) ++#define HIDPGETCONNINFO _IOR('H', 211, int) ++ + struct ioctl_trans { + unsigned int cmd; + unsigned int handler; +@@ -5050,6 +5055,10 @@ + COMPATIBLE_IOCTL(CMTPCONNDEL) + COMPATIBLE_IOCTL(CMTPGETCONNLIST) + COMPATIBLE_IOCTL(CMTPGETCONNINFO) ++COMPATIBLE_IOCTL(HIDPCONNADD) ++COMPATIBLE_IOCTL(HIDPCONNDEL) ++COMPATIBLE_IOCTL(HIDPGETCONNLIST) ++COMPATIBLE_IOCTL(HIDPGETCONNINFO) + /* Scanner */ + COMPATIBLE_IOCTL(SCANNER_IOCTL_VENDOR) + COMPATIBLE_IOCTL(SCANNER_IOCTL_PRODUCT) +--- linux-2.4.27/CREDITS~patch-2.4.27-mh1 ++++ linux-2.4.27/CREDITS +@@ -1348,6 +1348,7 @@ + D: Maintainer of the Linux Bluetooth Subsystem + D: Author and maintainer of the various Bluetooth HCI drivers + D: Author and maintainer of the CAPI message transport protocol driver ++D: Author and maintainer of the Bluetooth HID protocol driver + D: Various other Bluetooth related patches, cleanups and fixes + S: Germany + +--- linux-2.4.27/Documentation/Configure.help~patch-2.4.27-mh1 ++++ linux-2.4.27/Documentation/Configure.help +@@ -23313,6 +23313,7 @@ + RFCOMM Module (RFCOMM Protocol) + BNEP Module (Bluetooth Network Encapsulation Protocol) + CMTP Module (CAPI Message Transport Protocol) ++ HIDP Module (Human Interface Device Protocol) + + Say Y here to compile Bluetooth support into the kernel or say M to + compile it as module (bluez.o). +@@ -23378,6 +23379,15 @@ + Say Y here to compile CMTP support into the kernel or say M to + compile it as module (cmtp.o). + ++HIDP protocol support ++CONFIG_BLUEZ_HIDP ++ HIDP (Human Interface Device Protocol) is a transport layer ++ for HID reports. HIDP is required for the Bluetooth Human ++ Interface Device Profile. ++ ++ Say Y here to compile HIDP support into the kernel or say M to ++ compile it as module (hidp.o). ++ + HCI UART driver + CONFIG_BLUEZ_HCIUART + Bluetooth HCI UART driver. +--- linux-2.4.27/MAINTAINERS~patch-2.4.27-mh1 ++++ linux-2.4.27/MAINTAINERS +@@ -359,6 +359,11 @@ + M: marcel@holtmann.org + S: Maintained + ++BLUETOOTH HIDP LAYER ++P: Marcel Holtmann ++M: marcel@holtmann.org ++S: Maintained ++ + BLUETOOTH HCI UART DRIVER + P: Marcel Holtmann + M: marcel@holtmann.org +--- linux-2.4.27/net/bluetooth/Config.in~patch-2.4.27-mh1 ++++ linux-2.4.27/net/bluetooth/Config.in +@@ -14,6 +14,7 @@ + source net/bluetooth/rfcomm/Config.in + source net/bluetooth/bnep/Config.in + source net/bluetooth/cmtp/Config.in ++ source net/bluetooth/hidp/Config.in + source drivers/bluetooth/Config.in + fi + +--- /dev/null ++++ linux-2.4.27/net/bluetooth/hidp/Config.in +@@ -0,0 +1,5 @@ ++# ++# Bluetooth HIDP layer configuration ++# ++ ++dep_tristate 'HIDP protocol support' CONFIG_BLUEZ_HIDP $CONFIG_INPUT $CONFIG_BLUEZ_L2CAP +--- /dev/null ++++ linux-2.4.27/net/bluetooth/hidp/core.c +@@ -0,0 +1,655 @@ ++/* ++ HIDP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2003-2004 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 version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/skbuff.h> ++#include <linux/socket.h> ++#include <linux/ioctl.h> ++#include <linux/file.h> ++#include <linux/init.h> ++#include <net/sock.h> ++ ++#include <linux/input.h> ++ ++#include <net/bluetooth/bluetooth.h> ++#include <net/bluetooth/l2cap.h> ++ ++#include "hidp.h" ++ ++#ifndef CONFIG_BT_HIDP_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++#define VERSION "1.0" ++ ++static DECLARE_RWSEM(hidp_session_sem); ++static LIST_HEAD(hidp_session_list); ++ ++static unsigned char hidp_keycode[256] = { ++ 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, ++ 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, ++ 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, ++ 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, ++ 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, ++ 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, ++ 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, ++ 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, ++ 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, ++ 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ++ 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, ++ 150,158,159,128,136,177,178,176,142,152,173,140 ++}; ++ ++static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr) ++{ ++ struct hidp_session *session; ++ struct list_head *p; ++ ++ BT_DBG(""); ++ ++ list_for_each(p, &hidp_session_list) { ++ session = list_entry(p, struct hidp_session, list); ++ if (!bacmp(bdaddr, &session->bdaddr)) ++ return session; ++ } ++ return NULL; ++} ++ ++static void __hidp_link_session(struct hidp_session *session) ++{ ++ MOD_INC_USE_COUNT; ++ list_add(&session->list, &hidp_session_list); ++} ++ ++static void __hidp_unlink_session(struct hidp_session *session) ++{ ++ list_del(&session->list); ++ MOD_DEC_USE_COUNT; ++} ++ ++static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci) ++{ ++ bacpy(&ci->bdaddr, &session->bdaddr); ++ ++ ci->flags = session->flags; ++ ci->state = session->state; ++ ++ ci->vendor = 0x0000; ++ ci->product = 0x0000; ++ ci->version = 0x0000; ++ memset(ci->name, 0, 128); ++ ++ if (session->input) { ++ ci->vendor = session->input->idvendor; ++ ci->product = session->input->idproduct; ++ ci->version = session->input->idversion; ++ if (session->input->name) ++ strncpy(ci->name, session->input->name, 128); ++ else ++ strncpy(ci->name, "HID Boot Device", 128); ++ } ++} ++ ++static int hidp_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) ++{ ++ struct hidp_session *session = dev->private; ++ struct sk_buff *skb; ++ unsigned char newleds; ++ ++ BT_DBG("session %p hid %p data %p size %d", session, device, data, size); ++ ++ 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; ++ ++ if (!(skb = alloc_skb(3, GFP_ATOMIC))) { ++ BT_ERR("Can't allocate memory for new frame"); ++ return -ENOMEM; ++ } ++ ++ *skb_put(skb, 1) = 0xa2; ++ *skb_put(skb, 1) = 0x01; ++ *skb_put(skb, 1) = newleds; ++ ++ skb_queue_tail(&session->intr_transmit, skb); ++ ++ hidp_schedule(session); ++ ++ return 0; ++} ++ ++static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb) ++{ ++ struct input_dev *dev = session->input; ++ unsigned char *keys = session->keys; ++ unsigned char *udata = skb->data + 1; ++ signed char *sdata = skb->data + 1; ++ int i, size = skb->len - 1; ++ ++ switch (skb->data[0]) { ++ case 0x01: /* Keyboard report */ ++ for (i = 0; i < 8; i++) ++ input_report_key(dev, hidp_keycode[i + 224], (udata[0] >> i) & 1); ++ ++ for (i = 2; i < 8; i++) { ++ if (keys[i] > 3 && memscan(udata + 2, keys[i], 6) == udata + 8) { ++ if (hidp_keycode[keys[i]]) ++ input_report_key(dev, hidp_keycode[keys[i]], 0); ++ else ++ BT_ERR("Unknown key (scancode %#x) released.", keys[i]); ++ } ++ ++ if (udata[i] > 3 && memscan(keys + 2, udata[i], 6) == keys + 8) { ++ if (hidp_keycode[udata[i]]) ++ input_report_key(dev, hidp_keycode[udata[i]], 1); ++ else ++ BT_ERR("Unknown key (scancode %#x) pressed.", udata[i]); ++ } ++ } ++ ++ memcpy(keys, udata, 8); ++ break; ++ ++ case 0x02: /* Mouse report */ ++ input_report_key(dev, BTN_LEFT, sdata[0] & 0x01); ++ input_report_key(dev, BTN_RIGHT, sdata[0] & 0x02); ++ input_report_key(dev, BTN_MIDDLE, sdata[0] & 0x04); ++ input_report_key(dev, BTN_SIDE, sdata[0] & 0x08); ++ input_report_key(dev, BTN_EXTRA, sdata[0] & 0x10); ++ ++ input_report_rel(dev, REL_X, sdata[1]); ++ input_report_rel(dev, REL_Y, sdata[2]); ++ ++ if (size > 3) ++ input_report_rel(dev, REL_WHEEL, sdata[3]); ++ break; ++ } ++ ++ input_event(dev, EV_RST, 0, 0); ++} ++ ++static void hidp_idle_timeout(unsigned long arg) ++{ ++ struct hidp_session *session = (struct hidp_session *) arg; ++ ++ atomic_inc(&session->terminate); ++ hidp_schedule(session); ++} ++ ++static inline void hidp_set_timer(struct hidp_session *session) ++{ ++ if (session->idle_to > 0) ++ mod_timer(&session->timer, jiffies + HZ * session->idle_to); ++} ++ ++static inline void hidp_del_timer(struct hidp_session *session) ++{ ++ if (session->idle_to > 0) ++ del_timer(&session->timer); ++} ++ ++static inline void hidp_send_message(struct hidp_session *session, unsigned char hdr) ++{ ++ struct sk_buff *skb; ++ ++ BT_DBG("session %p", session); ++ ++ if (!(skb = alloc_skb(1, GFP_ATOMIC))) { ++ BT_ERR("Can't allocate memory for message"); ++ return; ++ } ++ ++ *skb_put(skb, 1) = hdr; ++ ++ skb_queue_tail(&session->ctrl_transmit, skb); ++ ++ hidp_schedule(session); ++} ++ ++static inline int hidp_recv_frame(struct hidp_session *session, struct sk_buff *skb) ++{ ++ __u8 hdr; ++ ++ BT_DBG("session %p skb %p len %d", session, skb, skb->len); ++ ++ hdr = skb->data[0]; ++ skb_pull(skb, 1); ++ ++ if (hdr == 0xa1) { ++ hidp_set_timer(session); ++ ++ if (session->input) ++ hidp_input_report(session, skb); ++ } else { ++ BT_DBG("Unsupported protocol header 0x%02x", hdr); ++ } ++ ++ kfree_skb(skb); ++ return 0; ++} ++ ++static int hidp_send_frame(struct socket *sock, unsigned char *data, int len) ++{ ++ struct iovec iv = { data, len }; ++ struct msghdr msg; ++ ++ BT_DBG("sock %p data %p len %d", sock, data, len); ++ ++ if (!len) ++ return 0; ++ ++ memset(&msg, 0, sizeof(msg)); ++ msg.msg_iovlen = 1; ++ msg.msg_iov = &iv; ++ ++ return sock_sendmsg(sock, &msg, len); ++} ++ ++static int hidp_process_transmit(struct hidp_session *session) ++{ ++ struct sk_buff *skb; ++ ++ BT_DBG("session %p", session); ++ ++ while ((skb = skb_dequeue(&session->ctrl_transmit))) { ++ if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) { ++ skb_queue_head(&session->ctrl_transmit, skb); ++ break; ++ } ++ ++ hidp_set_timer(session); ++ kfree_skb(skb); ++ } ++ ++ while ((skb = skb_dequeue(&session->intr_transmit))) { ++ if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) { ++ skb_queue_head(&session->intr_transmit, skb); ++ break; ++ } ++ ++ hidp_set_timer(session); ++ kfree_skb(skb); ++ } ++ ++ return skb_queue_len(&session->ctrl_transmit) + ++ skb_queue_len(&session->intr_transmit); ++} ++ ++static int hidp_session(void *arg) ++{ ++ struct hidp_session *session = arg; ++ struct sock *ctrl_sk = session->ctrl_sock->sk; ++ struct sock *intr_sk = session->intr_sock->sk; ++ struct sk_buff *skb; ++ int vendor = 0x0000, product = 0x0000; ++ wait_queue_t ctrl_wait, intr_wait; ++ unsigned long timeo = HZ; ++ ++ BT_DBG("session %p", session); ++ ++ if (session->input) { ++ vendor = session->input->idvendor; ++ product = session->input->idproduct; ++ } ++ ++ daemonize(); reparent_to_init(); ++ ++ sprintf(current->comm, "khidpd_%04x%04x", vendor, product); ++ ++ sigfillset(¤t->blocked); ++ flush_signals(current); ++ ++ current->nice = -15; ++ ++ set_fs(KERNEL_DS); ++ ++ init_waitqueue_entry(&ctrl_wait, current); ++ init_waitqueue_entry(&intr_wait, current); ++ add_wait_queue(ctrl_sk->sleep, &ctrl_wait); ++ add_wait_queue(intr_sk->sleep, &intr_wait); ++ while (!atomic_read(&session->terminate)) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ ++ if (ctrl_sk->state != BT_CONNECTED || intr_sk->state != BT_CONNECTED) ++ break; ++ ++ while ((skb = skb_dequeue(&ctrl_sk->receive_queue))) { ++ skb_orphan(skb); ++ hidp_recv_frame(session, skb); ++ } ++ ++ while ((skb = skb_dequeue(&intr_sk->receive_queue))) { ++ skb_orphan(skb); ++ hidp_recv_frame(session, skb); ++ } ++ ++ hidp_process_transmit(session); ++ ++ schedule(); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(intr_sk->sleep, &intr_wait); ++ remove_wait_queue(ctrl_sk->sleep, &ctrl_wait); ++ ++ down_write(&hidp_session_sem); ++ ++ hidp_del_timer(session); ++ ++ if (intr_sk->state != BT_CONNECTED) { ++ init_waitqueue_entry(&ctrl_wait, current); ++ add_wait_queue(ctrl_sk->sleep, &ctrl_wait); ++ while (timeo && ctrl_sk->state != BT_CLOSED) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ timeo = schedule_timeout(timeo); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(ctrl_sk->sleep, &ctrl_wait); ++ timeo = HZ; ++ } ++ ++ fput(session->ctrl_sock->file); ++ ++ init_waitqueue_entry(&intr_wait, current); ++ add_wait_queue(intr_sk->sleep, &intr_wait); ++ while (timeo && intr_sk->state != BT_CLOSED) { ++ set_current_state(TASK_INTERRUPTIBLE); ++ timeo = schedule_timeout(timeo); ++ } ++ set_current_state(TASK_RUNNING); ++ remove_wait_queue(intr_sk->sleep, &intr_wait); ++ ++ fput(session->intr_sock->file); ++ ++ __hidp_unlink_session(session); ++ ++ if (session->input) { ++ input_unregister_device(session->input); ++ kfree(session->input); ++ } ++ ++ up_write(&hidp_session_sem); ++ ++ kfree(session); ++ return 0; ++} ++ ++static inline void hidp_setup_input(struct hidp_session *session, struct hidp_connadd_req *req) ++{ ++ struct input_dev *input = session->input; ++ int i; ++ ++ input->private = session; ++ ++ input->idbus = BUS_BLUETOOTH; ++ input->idvendor = req->vendor; ++ input->idproduct = req->product; ++ input->idversion = req->version; ++ ++ if (req->subclass & 0x40) { ++ set_bit(EV_KEY, input->evbit); ++ set_bit(EV_LED, input->evbit); ++ set_bit(EV_REP, input->evbit); ++ ++ set_bit(LED_NUML, input->ledbit); ++ set_bit(LED_CAPSL, input->ledbit); ++ set_bit(LED_SCROLLL, input->ledbit); ++ set_bit(LED_COMPOSE, input->ledbit); ++ set_bit(LED_KANA, input->ledbit); ++ ++ for (i = 0; i < sizeof(hidp_keycode); i++) ++ set_bit(hidp_keycode[i], input->keybit); ++ clear_bit(0, input->keybit); ++ } ++ ++ if (req->subclass & 0x80) { ++ input->evbit[0] = BIT(EV_KEY) | BIT(EV_REL); ++ input->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE); ++ input->relbit[0] = BIT(REL_X) | BIT(REL_Y); ++ input->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA); ++ input->relbit[0] |= BIT(REL_WHEEL); ++ } ++ ++ input->event = hidp_input_event; ++ ++ input_register_device(input); ++} ++ ++int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) ++{ ++ struct hidp_session *session, *s; ++ int err; ++ ++ BT_DBG(""); ++ ++ if (bacmp(&bluez_pi(ctrl_sock->sk)->src, &bluez_pi(intr_sock->sk)->src) || ++ bacmp(&bluez_pi(ctrl_sock->sk)->dst, &bluez_pi(intr_sock->sk)->dst)) ++ return -ENOTUNIQ; ++ ++ session = kmalloc(sizeof(struct hidp_session), GFP_KERNEL); ++ if (!session) ++ return -ENOMEM; ++ memset(session, 0, sizeof(struct hidp_session)); ++ ++ session->input = kmalloc(sizeof(struct input_dev), GFP_KERNEL); ++ if (!session->input) { ++ kfree(session); ++ return -ENOMEM; ++ } ++ memset(session->input, 0, sizeof(struct input_dev)); ++ ++ down_write(&hidp_session_sem); ++ ++ s = __hidp_get_session(&bluez_pi(ctrl_sock->sk)->dst); ++ if (s && s->state == BT_CONNECTED) { ++ err = -EEXIST; ++ goto failed; ++ } ++ ++ bacpy(&session->bdaddr, &bluez_pi(ctrl_sock->sk)->dst); ++ ++ session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu); ++ session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu); ++ ++ BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu); ++ ++ session->ctrl_sock = ctrl_sock; ++ session->intr_sock = intr_sock; ++ session->state = BT_CONNECTED; ++ ++ init_timer(&session->timer); ++ ++ session->timer.function = hidp_idle_timeout; ++ session->timer.data = (unsigned long) session; ++ ++ skb_queue_head_init(&session->ctrl_transmit); ++ skb_queue_head_init(&session->intr_transmit); ++ ++ session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID); ++ session->idle_to = req->idle_to; ++ ++ if (session->input) ++ hidp_setup_input(session, req); ++ ++ __hidp_link_session(session); ++ ++ hidp_set_timer(session); ++ ++ err = kernel_thread(hidp_session, session, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); ++ if (err < 0) ++ goto unlink; ++ ++ if (session->input) { ++ hidp_send_message(session, 0x70); ++ session->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE); ++ ++ session->leds = 0xff; ++ hidp_input_event(session->input, EV_LED, 0, 0); ++ } ++ ++ up_write(&hidp_session_sem); ++ return 0; ++ ++unlink: ++ hidp_del_timer(session); ++ ++ __hidp_unlink_session(session); ++ ++ if (session->input) ++ input_unregister_device(session->input); ++ ++failed: ++ up_write(&hidp_session_sem); ++ ++ if (session->input) ++ kfree(session->input); ++ ++ kfree(session); ++ return err; ++} ++ ++int hidp_del_connection(struct hidp_conndel_req *req) ++{ ++ struct hidp_session *session; ++ int err = 0; ++ ++ BT_DBG(""); ++ ++ down_read(&hidp_session_sem); ++ ++ session = __hidp_get_session(&req->bdaddr); ++ if (session) { ++ if (req->flags & (1 << HIDP_VIRTUAL_CABLE_UNPLUG)) { ++ hidp_send_message(session, 0x15); ++ } else { ++ /* Flush the transmit queues */ ++ skb_queue_purge(&session->ctrl_transmit); ++ skb_queue_purge(&session->intr_transmit); ++ ++ /* Kill session thread */ ++ atomic_inc(&session->terminate); ++ hidp_schedule(session); ++ } ++ } else ++ err = -ENOENT; ++ ++ up_read(&hidp_session_sem); ++ return err; ++} ++ ++int hidp_get_connlist(struct hidp_connlist_req *req) ++{ ++ struct list_head *p; ++ int err = 0, n = 0; ++ ++ BT_DBG(""); ++ ++ down_read(&hidp_session_sem); ++ ++ list_for_each(p, &hidp_session_list) { ++ struct hidp_session *session; ++ struct hidp_conninfo ci; ++ ++ session = list_entry(p, struct hidp_session, list); ++ ++ __hidp_copy_session(session, &ci); ++ ++ if (copy_to_user(req->ci, &ci, sizeof(ci))) { ++ err = -EFAULT; ++ break; ++ } ++ ++ if (++n >= req->cnum) ++ break; ++ ++ req->ci++; ++ } ++ req->cnum = n; ++ ++ up_read(&hidp_session_sem); ++ return err; ++} ++ ++int hidp_get_conninfo(struct hidp_conninfo *ci) ++{ ++ struct hidp_session *session; ++ int err = 0; ++ ++ down_read(&hidp_session_sem); ++ ++ session = __hidp_get_session(&ci->bdaddr); ++ if (session) ++ __hidp_copy_session(session, ci); ++ else ++ err = -ENOENT; ++ ++ up_read(&hidp_session_sem); ++ return err; ++} ++ ++static int __init hidp_init(void) ++{ ++ l2cap_load(); ++ ++ hidp_init_sockets(); ++ ++ BT_INFO("BlueZ HIDP ver %s", VERSION); ++ BT_INFO("Copyright (C) 2003-2004 Marcel Holtmann <marcel@holtmann.org>"); ++ ++ return 0; ++} ++ ++static void __exit hidp_exit(void) ++{ ++ hidp_cleanup_sockets(); ++} ++ ++module_init(hidp_init); ++module_exit(hidp_exit); ++ ++MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); ++MODULE_DESCRIPTION("Bluetooth HIDP ver " VERSION); ++MODULE_LICENSE("GPL"); +--- /dev/null ++++ linux-2.4.27/net/bluetooth/hidp/hidp.h +@@ -0,0 +1,122 @@ ++/* ++ HIDP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2003-2004 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 version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++#ifndef __HIDP_H ++#define __HIDP_H ++ ++#include <linux/types.h> ++#include <net/bluetooth/bluetooth.h> ++ ++/* HIDP ioctl defines */ ++#define HIDPCONNADD _IOW('H', 200, int) ++#define HIDPCONNDEL _IOW('H', 201, int) ++#define HIDPGETCONNLIST _IOR('H', 210, int) ++#define HIDPGETCONNINFO _IOR('H', 211, int) ++ ++#define HIDP_VIRTUAL_CABLE_UNPLUG 0 ++#define HIDP_BOOT_PROTOCOL_MODE 1 ++#define HIDP_BLUETOOTH_VENDOR_ID 9 ++ ++struct hidp_connadd_req { ++ int ctrl_sock; // Connected control socket ++ int intr_sock; // Connteted interrupt socket ++ __u16 parser; ++ __u16 rd_size; ++ __u8 *rd_data; ++ __u8 country; ++ __u8 subclass; ++ __u16 vendor; ++ __u16 product; ++ __u16 version; ++ __u32 flags; ++ __u32 idle_to; ++ char name[128]; ++}; ++ ++struct hidp_conndel_req { ++ bdaddr_t bdaddr; ++ __u32 flags; ++}; ++ ++struct hidp_conninfo { ++ bdaddr_t bdaddr; ++ __u32 flags; ++ __u16 state; ++ __u16 vendor; ++ __u16 product; ++ __u16 version; ++ char name[128]; ++}; ++ ++struct hidp_connlist_req { ++ __u32 cnum; ++ struct hidp_conninfo *ci; ++}; ++ ++int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock); ++int hidp_del_connection(struct hidp_conndel_req *req); ++int hidp_get_connlist(struct hidp_connlist_req *req); ++int hidp_get_conninfo(struct hidp_conninfo *ci); ++ ++/* HIDP session defines */ ++struct hidp_session { ++ struct list_head list; ++ ++ struct socket *ctrl_sock; ++ struct socket *intr_sock; ++ ++ bdaddr_t bdaddr; ++ ++ unsigned long state; ++ unsigned long flags; ++ unsigned long idle_to; ++ ++ uint ctrl_mtu; ++ uint intr_mtu; ++ ++ atomic_t terminate; ++ ++ unsigned char keys[8]; ++ unsigned char leds; ++ ++ struct input_dev *input; ++ ++ struct timer_list timer; ++ ++ struct sk_buff_head ctrl_transmit; ++ struct sk_buff_head intr_transmit; ++}; ++ ++static inline void hidp_schedule(struct hidp_session *session) ++{ ++ struct sock *ctrl_sk = session->ctrl_sock->sk; ++ struct sock *intr_sk = session->intr_sock->sk; ++ ++ wake_up_interruptible(ctrl_sk->sleep); ++ wake_up_interruptible(intr_sk->sleep); ++} ++ ++/* HIDP init defines */ ++extern int __init hidp_init_sockets(void); ++extern void __exit hidp_cleanup_sockets(void); ++ ++#endif /* __HIDP_H */ +--- /dev/null ++++ linux-2.4.27/net/bluetooth/hidp/Makefile +@@ -0,0 +1,10 @@ ++# ++# Makefile for the Linux Bluetooth HIDP layer ++# ++ ++O_TARGET := hidp.o ++ ++obj-y := core.o sock.o ++obj-m += $(O_TARGET) ++ ++include $(TOPDIR)/Rules.make +--- /dev/null ++++ linux-2.4.27/net/bluetooth/hidp/sock.c +@@ -0,0 +1,212 @@ ++/* ++ HIDP implementation for Linux Bluetooth stack (BlueZ). ++ Copyright (C) 2003-2004 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 version 2 as ++ published by the Free Software Foundation; ++ ++ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ++ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. ++ IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY ++ CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES ++ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ++ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF ++ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ++ ++ ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, ++ COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS ++ SOFTWARE IS DISCLAIMED. ++*/ ++ ++#include <linux/config.h> ++#include <linux/module.h> ++ ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/kernel.h> ++#include <linux/major.h> ++#include <linux/sched.h> ++#include <linux/slab.h> ++#include <linux/poll.h> ++#include <linux/fcntl.h> ++#include <linux/skbuff.h> ++#include <linux/socket.h> ++#include <linux/ioctl.h> ++#include <linux/file.h> ++#include <linux/init.h> ++#include <net/sock.h> ++ ++#include "hidp.h" ++ ++#ifndef CONFIG_BT_HIDP_DEBUG ++#undef BT_DBG ++#define BT_DBG(D...) ++#endif ++ ++static int hidp_sock_release(struct socket *sock) ++{ ++ struct sock *sk = sock->sk; ++ ++ BT_DBG("sock %p sk %p", sock, sk); ++ ++ if (!sk) ++ return 0; ++ ++ sock_orphan(sk); ++ sock_put(sk); ++ ++ MOD_DEC_USE_COUNT; ++ return 0; ++} ++ ++static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) ++{ ++ struct hidp_connadd_req ca; ++ struct hidp_conndel_req cd; ++ struct hidp_connlist_req cl; ++ struct hidp_conninfo ci; ++ struct socket *csock; ++ struct socket *isock; ++ int err; ++ ++ BT_DBG("cmd %x arg %lx", cmd, arg); ++ ++ switch (cmd) { ++ case HIDPCONNADD: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EACCES; ++ ++ if (copy_from_user(&ca, (void *) arg, sizeof(ca))) ++ return -EFAULT; ++ ++ csock = sockfd_lookup(ca.ctrl_sock, &err); ++ if (!csock) ++ return err; ++ ++ isock = sockfd_lookup(ca.intr_sock, &err); ++ if (!isock) { ++ fput(csock->file); ++ return err; ++ } ++ ++ if (csock->sk->state != BT_CONNECTED || isock->sk->state != BT_CONNECTED) { ++ fput(csock->file); ++ fput(isock->file); ++ return -EBADFD; ++ } ++ ++ err = hidp_add_connection(&ca, csock, isock); ++ if (!err) { ++ if (copy_to_user((void *) arg, &ca, sizeof(ca))) ++ err = -EFAULT; ++ } else { ++ fput(csock->file); ++ fput(isock->file); ++ } ++ ++ return err; ++ ++ case HIDPCONNDEL: ++ if (!capable(CAP_NET_ADMIN)) ++ return -EACCES; ++ ++ if (copy_from_user(&cd, (void *) arg, sizeof(cd))) ++ return -EFAULT; ++ ++ return hidp_del_connection(&cd); ++ ++ case HIDPGETCONNLIST: ++ if (copy_from_user(&cl, (void *) arg, sizeof(cl))) ++ return -EFAULT; ++ ++ if (cl.cnum <= 0) ++ return -EINVAL; ++ ++ err = hidp_get_connlist(&cl); ++ if (!err && copy_to_user((void *) arg, &cl, sizeof(cl))) ++ return -EFAULT; ++ ++ return err; ++ ++ case HIDPGETCONNINFO: ++ if (copy_from_user(&ci, (void *) arg, sizeof(ci))) ++ return -EFAULT; ++ ++ err = hidp_get_conninfo(&ci); ++ if (!err && copy_to_user((void *) arg, &ci, sizeof(ci))) ++ return -EFAULT; ++ ++ return err; ++ } ++ ++ return -EINVAL; ++} ++ ++static struct proto_ops hidp_sock_ops = { ++ family: PF_BLUETOOTH, ++ release: hidp_sock_release, ++ ioctl: hidp_sock_ioctl, ++ bind: sock_no_bind, ++ getname: sock_no_getname, ++ sendmsg: sock_no_sendmsg, ++ recvmsg: sock_no_recvmsg, ++ poll: sock_no_poll, ++ listen: sock_no_listen, ++ shutdown: sock_no_shutdown, ++ setsockopt: sock_no_setsockopt, ++ getsockopt: sock_no_getsockopt, ++ connect: sock_no_connect, ++ socketpair: sock_no_socketpair, ++ accept: sock_no_accept, ++ mmap: sock_no_mmap ++}; ++ ++static int hidp_sock_create(struct socket *sock, int protocol) ++{ ++ struct sock *sk; ++ ++ BT_DBG("sock %p", sock); ++ ++ if (sock->type != SOCK_RAW) ++ return -ESOCKTNOSUPPORT; ++ ++ sock->ops = &hidp_sock_ops; ++ ++ if (!(sk = sk_alloc(PF_BLUETOOTH, GFP_KERNEL, 1))) ++ return -ENOMEM; ++ ++ MOD_INC_USE_COUNT; ++ ++ sock->state = SS_UNCONNECTED; ++ sock_init_data(sock, sk); ++ ++ sk->destruct = NULL; ++ sk->protocol = protocol; ++ ++ return 0; ++} ++ ++static struct net_proto_family hidp_sock_family_ops = { ++ family: PF_BLUETOOTH, ++ create: hidp_sock_create ++}; ++ ++int __init hidp_init_sockets(void) ++{ ++ int err; ++ ++ if ((err = bluez_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops))) ++ BT_ERR("Can't register HIDP socket layer (%d)", err); ++ ++ return err; ++} ++ ++void __exit hidp_cleanup_sockets(void) ++{ ++ int err; ++ ++ if ((err = bluez_sock_unregister(BTPROTO_HIDP))) ++ BT_ERR("Can't unregister HIDP socket layer (%d)", err); ++} +--- linux-2.4.27/net/bluetooth/Makefile~patch-2.4.27-mh1 ++++ linux-2.4.27/net/bluetooth/Makefile +@@ -16,6 +16,7 @@ + subdir-$(CONFIG_BLUEZ_RFCOMM) += rfcomm + subdir-$(CONFIG_BLUEZ_BNEP) += bnep + subdir-$(CONFIG_BLUEZ_CMTP) += cmtp ++subdir-$(CONFIG_BLUEZ_HIDP) += hidp + + ifeq ($(CONFIG_BLUEZ_RFCOMM),y) + obj-y += rfcomm/rfcomm.o +@@ -25,6 +26,14 @@ + obj-y += bnep/bnep.o + endif + ++ifeq ($(CONFIG_BLUEZ_CMTP),y) ++obj-y += cmtp/cmtp.o ++endif ++ ++ifeq ($(CONFIG_BLUEZ_HIDP),y) ++obj-y += hidp/hidp.o ++endif ++ + include $(TOPDIR)/Rules.make + + bluez.o: $(bluez-objs) |