Commit 3a4bc665 authored by David S. Miller's avatar David S. Miller

Merge http://linux-mh.bkbits.net/bluetooth-2.6

into nuts.davemloft.net:/disk1/BK/net-2.6
parents 5ade92b8 1dd7f7ca
...@@ -1405,6 +1405,7 @@ W: http://www.holtmann.org ...@@ -1405,6 +1405,7 @@ W: http://www.holtmann.org
D: Maintainer of the Linux Bluetooth Subsystem D: Maintainer of the Linux Bluetooth Subsystem
D: Author and maintainer of the various Bluetooth HCI drivers 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 CAPI message transport protocol driver
D: Author and maintainer of the Bluetooth HID protocol driver
D: Various other Bluetooth related patches, cleanups and fixes D: Various other Bluetooth related patches, cleanups and fixes
S: Germany S: Germany
......
...@@ -396,6 +396,11 @@ P: Marcel Holtmann ...@@ -396,6 +396,11 @@ P: Marcel Holtmann
M: marcel@holtmann.org M: marcel@holtmann.org
S: Maintained S: Maintained
BLUETOOTH HIDP LAYER
P: Marcel Holtmann
M: marcel@holtmann.org
S: Maintained
BLUETOOTH HCI UART DRIVER BLUETOOTH HCI UART DRIVER
P: Marcel Holtmann P: Marcel Holtmann
M: marcel@holtmann.org M: marcel@holtmann.org
......
...@@ -585,6 +585,9 @@ static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int ...@@ -585,6 +585,9 @@ static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int
return -EBUSY; return -EBUSY;
} }
bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0;
bfusb->udev->halted[0] = bfusb->udev->halted[1] = 0;
buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC); buf = kmalloc(BFUSB_MAX_BLOCK_SIZE + 3, GFP_ATOMIC);
if (!buf) { if (!buf) {
BT_ERR("Can't allocate memory chunk for firmware"); BT_ERR("Can't allocate memory chunk for firmware");
...@@ -624,6 +627,9 @@ static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int ...@@ -624,6 +627,9 @@ static int bfusb_load_firmware(struct bfusb *bfusb, unsigned char *firmware, int
goto error; goto error;
} }
bfusb->udev->toggle[0] = bfusb->udev->toggle[1] = 0;
bfusb->udev->halted[0] = bfusb->udev->halted[1] = 0;
BT_INFO("BlueFRITZ! USB device ready"); BT_INFO("BlueFRITZ! USB device ready");
kfree(buf); kfree(buf);
......
...@@ -194,10 +194,8 @@ static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) ...@@ -194,10 +194,8 @@ static int bt3c_write(unsigned int iobase, int fifo_size, __u8 *buf, int len)
} }
static void bt3c_write_wakeup(bt3c_info_t *info, int from) static void bt3c_write_wakeup(bt3c_info_t *info)
{ {
unsigned long flags;
if (!info) { if (!info) {
BT_ERR("Unknown device"); BT_ERR("Unknown device");
return; return;
...@@ -206,8 +204,6 @@ static void bt3c_write_wakeup(bt3c_info_t *info, int from) ...@@ -206,8 +204,6 @@ static void bt3c_write_wakeup(bt3c_info_t *info, int from)
if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) if (test_and_set_bit(XMIT_SENDING, &(info->tx_state)))
return; return;
spin_lock_irqsave(&(info->lock), flags);
do { do {
register unsigned int iobase = info->link.io.BasePort1; register unsigned int iobase = info->link.io.BasePort1;
register struct sk_buff *skb; register struct sk_buff *skb;
...@@ -234,8 +230,6 @@ static void bt3c_write_wakeup(bt3c_info_t *info, int from) ...@@ -234,8 +230,6 @@ static void bt3c_write_wakeup(bt3c_info_t *info, int from)
info->hdev->stat.byte_tx += len; info->hdev->stat.byte_tx += len;
} while (0); } while (0);
spin_unlock_irqrestore(&(info->lock), flags);
} }
...@@ -391,7 +385,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs) ...@@ -391,7 +385,7 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst, struct pt_regs *regs)
if (stat & 0x0002) { if (stat & 0x0002) {
//BT_ERR("Ack (stat=0x%04x)", stat); //BT_ERR("Ack (stat=0x%04x)", stat);
clear_bit(XMIT_SENDING, &(info->tx_state)); clear_bit(XMIT_SENDING, &(info->tx_state));
bt3c_write_wakeup(info, 1); bt3c_write_wakeup(info);
} }
bt3c_io_write(iobase, 0x7001, 0x0000); bt3c_io_write(iobase, 0x7001, 0x0000);
...@@ -444,6 +438,7 @@ static int bt3c_hci_send_frame(struct sk_buff *skb) ...@@ -444,6 +438,7 @@ static int bt3c_hci_send_frame(struct sk_buff *skb)
{ {
bt3c_info_t *info; bt3c_info_t *info;
struct hci_dev *hdev = (struct hci_dev *)(skb->dev); struct hci_dev *hdev = (struct hci_dev *)(skb->dev);
unsigned long flags;
if (!hdev) { if (!hdev) {
BT_ERR("Frame for unknown HCI device (hdev=NULL)"); BT_ERR("Frame for unknown HCI device (hdev=NULL)");
...@@ -468,7 +463,11 @@ static int bt3c_hci_send_frame(struct sk_buff *skb) ...@@ -468,7 +463,11 @@ static int bt3c_hci_send_frame(struct sk_buff *skb)
memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); memcpy(skb_push(skb, 1), &(skb->pkt_type), 1);
skb_queue_tail(&(info->txq), skb); skb_queue_tail(&(info->txq), skb);
bt3c_write_wakeup(info, 0); spin_lock_irqsave(&(info->lock), flags);
bt3c_write_wakeup(info);
spin_unlock_irqrestore(&(info->lock), flags);
return 0; return 0;
} }
...@@ -489,12 +488,19 @@ static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long ...@@ -489,12 +488,19 @@ static int bt3c_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long
/* ======================== Card services HCI interaction ======================== */ /* ======================== Card services HCI interaction ======================== */
static struct device bt3c_device = { static struct device *bt3c_device(void)
.bus_id = "pcmcia", {
.kobj = { static char *kobj_name = "bt3c";
.k_name = "bt3c"
} static struct device dev = {
}; .bus_id = "pcmcia",
};
dev.kobj.k_name = kmalloc(strlen(kobj_name) + 1, GFP_KERNEL);
strcpy(dev.kobj.k_name, kobj_name);
kobject_init(&dev.kobj);
return &dev;
}
static int bt3c_load_firmware(bt3c_info_t *info, unsigned char *firmware, int count) static int bt3c_load_firmware(bt3c_info_t *info, unsigned char *firmware, int count)
...@@ -617,7 +623,7 @@ int bt3c_open(bt3c_info_t *info) ...@@ -617,7 +623,7 @@ int bt3c_open(bt3c_info_t *info)
hdev->owner = THIS_MODULE; hdev->owner = THIS_MODULE;
/* Load firmware */ /* Load firmware */
err = request_firmware(&firmware, "BT3CPCC.bin", &bt3c_device); err = request_firmware(&firmware, "BT3CPCC.bin", bt3c_device());
if (err < 0) { if (err < 0) {
BT_ERR("Firmware request failed"); BT_ERR("Firmware request failed");
goto error; goto error;
......
...@@ -1960,6 +1960,11 @@ static int do_blkgetsize64(unsigned int fd, unsigned int cmd, ...@@ -1960,6 +1960,11 @@ static int do_blkgetsize64(unsigned int fd, unsigned int cmd,
#define CMTPGETCONNLIST _IOR('C', 210, int) #define CMTPGETCONNLIST _IOR('C', 210, int)
#define CMTPGETCONNINFO _IOR('C', 211, 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 floppy_struct32 { struct floppy_struct32 {
compat_uint_t size; compat_uint_t size;
compat_uint_t sect; compat_uint_t sect;
......
...@@ -640,6 +640,10 @@ COMPATIBLE_IOCTL(CMTPCONNADD) ...@@ -640,6 +640,10 @@ COMPATIBLE_IOCTL(CMTPCONNADD)
COMPATIBLE_IOCTL(CMTPCONNDEL) COMPATIBLE_IOCTL(CMTPCONNDEL)
COMPATIBLE_IOCTL(CMTPGETCONNLIST) COMPATIBLE_IOCTL(CMTPGETCONNLIST)
COMPATIBLE_IOCTL(CMTPGETCONNINFO) COMPATIBLE_IOCTL(CMTPGETCONNINFO)
COMPATIBLE_IOCTL(HIDPCONNADD)
COMPATIBLE_IOCTL(HIDPCONNDEL)
COMPATIBLE_IOCTL(HIDPGETCONNLIST)
COMPATIBLE_IOCTL(HIDPGETCONNINFO)
/* CAPI */ /* CAPI */
COMPATIBLE_IOCTL(CAPI_REGISTER) COMPATIBLE_IOCTL(CAPI_REGISTER)
COMPATIBLE_IOCTL(CAPI_GET_MANUFACTURER) COMPATIBLE_IOCTL(CAPI_GET_MANUFACTURER)
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#define BTPROTO_BNEP 4 #define BTPROTO_BNEP 4
#define BTPROTO_CMTP 5 #define BTPROTO_CMTP 5
#define BTPROTO_HIDP 6 #define BTPROTO_HIDP 6
#define BTPROTO_AVDTP 7
#define SOL_HCI 0 #define SOL_HCI 0
#define SOL_L2CAP 6 #define SOL_L2CAP 6
......
...@@ -195,10 +195,8 @@ static inline long inquiry_entry_age(struct inquiry_entry *e) ...@@ -195,10 +195,8 @@ static inline long inquiry_entry_age(struct inquiry_entry *e)
return jiffies - e->timestamp; return jiffies - e->timestamp;
} }
struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
void inquiry_cache_update(struct hci_dev *hdev, struct inquiry_info *info); void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_info *info);
void inquiry_cache_flush(struct hci_dev *hdev);
int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf);
/* ----- HCI Connections ----- */ /* ----- HCI Connections ----- */
enum { enum {
......
...@@ -56,5 +56,7 @@ source "net/bluetooth/bnep/Kconfig" ...@@ -56,5 +56,7 @@ source "net/bluetooth/bnep/Kconfig"
source "net/bluetooth/cmtp/Kconfig" source "net/bluetooth/cmtp/Kconfig"
source "net/bluetooth/hidp/Kconfig"
source "drivers/bluetooth/Kconfig" source "drivers/bluetooth/Kconfig"
...@@ -8,5 +8,6 @@ obj-$(CONFIG_BT_SCO) += sco.o ...@@ -8,5 +8,6 @@ obj-$(CONFIG_BT_SCO) += sco.o
obj-$(CONFIG_BT_RFCOMM) += rfcomm/ obj-$(CONFIG_BT_RFCOMM) += rfcomm/
obj-$(CONFIG_BT_BNEP) += bnep/ obj-$(CONFIG_BT_BNEP) += bnep/
obj-$(CONFIG_BT_CMTP) += cmtp/ obj-$(CONFIG_BT_CMTP) += cmtp/
obj-$(CONFIG_BT_HIDP) += hidp/
bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o
...@@ -51,13 +51,13 @@ ...@@ -51,13 +51,13 @@
#define BT_DBG(D...) #define BT_DBG(D...)
#endif #endif
#define VERSION "2.5" #define VERSION "2.6"
struct proc_dir_entry *proc_bt; struct proc_dir_entry *proc_bt;
EXPORT_SYMBOL(proc_bt); EXPORT_SYMBOL(proc_bt);
/* Bluetooth sockets */ /* Bluetooth sockets */
#define BT_MAX_PROTO 7 #define BT_MAX_PROTO 8
static struct net_proto_family *bt_proto[BT_MAX_PROTO]; static struct net_proto_family *bt_proto[BT_MAX_PROTO];
static kmem_cache_t *bt_sock_cache; static kmem_cache_t *bt_sock_cache;
......
...@@ -69,7 +69,7 @@ void hci_acl_connect(struct hci_conn *conn) ...@@ -69,7 +69,7 @@ void hci_acl_connect(struct hci_conn *conn)
bacpy(&cp.bdaddr, &conn->dst); bacpy(&cp.bdaddr, &conn->dst);
cp.pscan_rep_mode = 0x02; cp.pscan_rep_mode = 0x02;
if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) && if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst)) &&
inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
cp.pscan_rep_mode = ie->info.pscan_rep_mode; cp.pscan_rep_mode = ie->info.pscan_rep_mode;
cp.pscan_mode = ie->info.pscan_mode; cp.pscan_mode = ie->info.pscan_mode;
......
...@@ -287,7 +287,7 @@ struct hci_dev *hci_dev_get(int index) ...@@ -287,7 +287,7 @@ struct hci_dev *hci_dev_get(int index)
EXPORT_SYMBOL(hci_dev_get); EXPORT_SYMBOL(hci_dev_get);
/* ---- Inquiry support ---- */ /* ---- Inquiry support ---- */
void inquiry_cache_flush(struct hci_dev *hdev) static void inquiry_cache_flush(struct hci_dev *hdev)
{ {
struct inquiry_cache *cache = &hdev->inq_cache; struct inquiry_cache *cache = &hdev->inq_cache;
struct inquiry_entry *next = cache->list, *e; struct inquiry_entry *next = cache->list, *e;
...@@ -301,7 +301,7 @@ void inquiry_cache_flush(struct hci_dev *hdev) ...@@ -301,7 +301,7 @@ void inquiry_cache_flush(struct hci_dev *hdev)
} }
} }
struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
{ {
struct inquiry_cache *cache = &hdev->inq_cache; struct inquiry_cache *cache = &hdev->inq_cache;
struct inquiry_entry *e; struct inquiry_entry *e;
...@@ -314,14 +314,14 @@ struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdadd ...@@ -314,14 +314,14 @@ struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdadd
return e; return e;
} }
void inquiry_cache_update(struct hci_dev *hdev, struct inquiry_info *info) void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_info *info)
{ {
struct inquiry_cache *cache = &hdev->inq_cache; struct inquiry_cache *cache = &hdev->inq_cache;
struct inquiry_entry *e; struct inquiry_entry *e;
BT_DBG("cache %p, %s", cache, batostr(&info->bdaddr)); BT_DBG("cache %p, %s", cache, batostr(&info->bdaddr));
if (!(e = inquiry_cache_lookup(hdev, &info->bdaddr))) { if (!(e = hci_inquiry_cache_lookup(hdev, &info->bdaddr))) {
/* Entry not in the cache. Add new one. */ /* Entry not in the cache. Add new one. */
if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC))) if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
return; return;
...@@ -335,7 +335,7 @@ void inquiry_cache_update(struct hci_dev *hdev, struct inquiry_info *info) ...@@ -335,7 +335,7 @@ void inquiry_cache_update(struct hci_dev *hdev, struct inquiry_info *info)
cache->timestamp = jiffies; cache->timestamp = jiffies;
} }
int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf) static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
{ {
struct inquiry_cache *cache = &hdev->inq_cache; struct inquiry_cache *cache = &hdev->inq_cache;
struct inquiry_info *info = (struct inquiry_info *) buf; struct inquiry_info *info = (struct inquiry_info *) buf;
......
...@@ -358,7 +358,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) ...@@ -358,7 +358,7 @@ static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
status, batostr(&cp->bdaddr), conn); status, batostr(&cp->bdaddr), conn);
if (status) { if (status) {
if (conn) { if (conn && conn->state == BT_CONNECT) {
conn->state = BT_CLOSED; conn->state = BT_CLOSED;
hci_proto_connect_cfm(conn, status); hci_proto_connect_cfm(conn, status);
hci_conn_del(conn); hci_conn_del(conn);
...@@ -486,7 +486,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * ...@@ -486,7 +486,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
hci_dev_lock(hdev); hci_dev_lock(hdev);
for (; num_rsp; num_rsp--) for (; num_rsp; num_rsp--)
inquiry_cache_update(hdev, info++); hci_inquiry_cache_update(hdev, info++);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
...@@ -508,7 +508,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct ...@@ -508,7 +508,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
memcpy(tmp.dev_class, &info->dev_class, 3); memcpy(tmp.dev_class, &info->dev_class, 3);
tmp.clock_offset = info->clock_offset; tmp.clock_offset = info->clock_offset;
info++; info++;
inquiry_cache_update(hdev, &tmp); hci_inquiry_cache_update(hdev, &tmp);
} }
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
} }
......
config BT_HIDP
tristate "HIDP protocol support"
depends on BT && BT_L2CAP
select INPUT
help
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).
#
# Makefile for the Linux Bluetooth HIDP layer
#
obj-$(CONFIG_BT_HIDP) += hidp.o
hidp-objs := core.o sock.o
This diff is collapsed.
/*
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 __user *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->sk_sleep);
wake_up_interruptible(intr_sk->sk_sleep);
}
/* HIDP init defines */
extern int __init hidp_init_sockets(void);
extern void __exit hidp_cleanup_sockets(void);
#endif /* __HIDP_H */
/*
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);
return 0;
}
static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *) 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, argp, 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->sk_state != BT_CONNECTED || isock->sk->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(argp, &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, argp, sizeof(cd)))
return -EFAULT;
return hidp_del_connection(&cd);
case HIDPGETCONNLIST:
if (copy_from_user(&cl, argp, sizeof(cl)))
return -EFAULT;
if (cl.cnum <= 0)
return -EINVAL;
err = hidp_get_connlist(&cl);
if (!err && copy_to_user(argp, &cl, sizeof(cl)))
return -EFAULT;
return err;
case HIDPGETCONNINFO:
if (copy_from_user(&ci, argp, sizeof(ci)))
return -EFAULT;
err = hidp_get_conninfo(&ci);
if (!err && copy_to_user(argp, &ci, sizeof(ci)))
return -EFAULT;
return err;
}
return -EINVAL;
}
static struct proto_ops hidp_sock_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.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;
if (!(sk = bt_sock_alloc(sock, PF_BLUETOOTH, 0, GFP_KERNEL)))
return -ENOMEM;
sk_set_owner(sk, THIS_MODULE);
sock->ops = &hidp_sock_ops;
sock->state = SS_UNCONNECTED;
sk->sk_destruct = NULL;
sk->sk_protocol = protocol;
return 0;
}
static struct net_proto_family hidp_sock_family_ops = {
.family = PF_BLUETOOTH,
.owner = THIS_MODULE,
.create = hidp_sock_create
};
int __init hidp_init_sockets(void)
{
int err;
err = bt_sock_register(BTPROTO_HIDP, &hidp_sock_family_ops);
if (err < 0)
BT_ERR("Can't register HIDP socket");
return err;
}
void __exit hidp_cleanup_sockets(void)
{
if (bt_sock_unregister(BTPROTO_HIDP) < 0)
BT_ERR("Can't unregister HIDP socket");
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment