Partial revert of commit aabf6f89. When the hidp session thread
was converted from kernel_thread to kthread, the atomic/wakeups
were replaced with kthread_stop. kthread_stop has blocking semantics
which are inappropriate for the hidp session kthread. In addition,
the kthread signals itself to terminate in hidp_process_hid_control()
- it cannot do this with kthread_stop().
Lastly, a wakeup can be lost if the wakeup happens between checking
for the loop exit condition and setting the current state to
TASK_INTERRUPTIBLE. (Without appropriate synchronization mechanisms,
the task state should not be changed between the condition test and
the yield - via schedule() - as this creates a race between the
wakeup and resetting the state back to interruptible.)
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
		
	
			
		
			
				
	
	
		
			191 lines
		
	
	
	
		
			5.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			191 lines
		
	
	
	
		
			5.1 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
   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 header masks */
 | 
						|
#define HIDP_HEADER_TRANS_MASK			0xf0
 | 
						|
#define HIDP_HEADER_PARAM_MASK			0x0f
 | 
						|
 | 
						|
/* HIDP transaction types */
 | 
						|
#define HIDP_TRANS_HANDSHAKE			0x00
 | 
						|
#define HIDP_TRANS_HID_CONTROL			0x10
 | 
						|
#define HIDP_TRANS_GET_REPORT			0x40
 | 
						|
#define HIDP_TRANS_SET_REPORT			0x50
 | 
						|
#define HIDP_TRANS_GET_PROTOCOL			0x60
 | 
						|
#define HIDP_TRANS_SET_PROTOCOL			0x70
 | 
						|
#define HIDP_TRANS_GET_IDLE			0x80
 | 
						|
#define HIDP_TRANS_SET_IDLE			0x90
 | 
						|
#define HIDP_TRANS_DATA				0xa0
 | 
						|
#define HIDP_TRANS_DATC				0xb0
 | 
						|
 | 
						|
/* HIDP handshake results */
 | 
						|
#define HIDP_HSHK_SUCCESSFUL			0x00
 | 
						|
#define HIDP_HSHK_NOT_READY			0x01
 | 
						|
#define HIDP_HSHK_ERR_INVALID_REPORT_ID		0x02
 | 
						|
#define HIDP_HSHK_ERR_UNSUPPORTED_REQUEST	0x03
 | 
						|
#define HIDP_HSHK_ERR_INVALID_PARAMETER		0x04
 | 
						|
#define HIDP_HSHK_ERR_UNKNOWN			0x0e
 | 
						|
#define HIDP_HSHK_ERR_FATAL			0x0f
 | 
						|
 | 
						|
/* HIDP control operation parameters */
 | 
						|
#define HIDP_CTRL_NOP				0x00
 | 
						|
#define HIDP_CTRL_HARD_RESET			0x01
 | 
						|
#define HIDP_CTRL_SOFT_RESET			0x02
 | 
						|
#define HIDP_CTRL_SUSPEND			0x03
 | 
						|
#define HIDP_CTRL_EXIT_SUSPEND			0x04
 | 
						|
#define HIDP_CTRL_VIRTUAL_CABLE_UNPLUG		0x05
 | 
						|
 | 
						|
/* HIDP data transaction headers */
 | 
						|
#define HIDP_DATA_RTYPE_MASK			0x03
 | 
						|
#define HIDP_DATA_RSRVD_MASK			0x0c
 | 
						|
#define HIDP_DATA_RTYPE_OTHER			0x00
 | 
						|
#define HIDP_DATA_RTYPE_INPUT			0x01
 | 
						|
#define HIDP_DATA_RTYPE_OUPUT			0x02
 | 
						|
#define HIDP_DATA_RTYPE_FEATURE			0x03
 | 
						|
 | 
						|
/* HIDP protocol header parameters */
 | 
						|
#define HIDP_PROTO_BOOT				0x00
 | 
						|
#define HIDP_PROTO_REPORT			0x01
 | 
						|
 | 
						|
/* 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
 | 
						|
#define HIDP_WAITING_FOR_RETURN		10
 | 
						|
#define HIDP_WAITING_FOR_SEND_ACK	11
 | 
						|
 | 
						|
struct hidp_connadd_req {
 | 
						|
	int   ctrl_sock;	/* Connected control socket */
 | 
						|
	int   intr_sock;	/* Connected interrupt socket */
 | 
						|
	__u16 parser;
 | 
						|
	__u16 rd_size;
 | 
						|
	__u8 __user *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 hci_conn *conn;
 | 
						|
 | 
						|
	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;
 | 
						|
	struct task_struct *task;
 | 
						|
 | 
						|
	unsigned char keys[8];
 | 
						|
	unsigned char leds;
 | 
						|
 | 
						|
	struct input_dev *input;
 | 
						|
 | 
						|
	struct hid_device *hid;
 | 
						|
 | 
						|
	struct timer_list timer;
 | 
						|
 | 
						|
	struct sk_buff_head ctrl_transmit;
 | 
						|
	struct sk_buff_head intr_transmit;
 | 
						|
 | 
						|
	/* Used in hidp_get_raw_report() */
 | 
						|
	int waiting_report_type; /* HIDP_DATA_RTYPE_* */
 | 
						|
	int waiting_report_number; /* -1 for not numbered */
 | 
						|
	struct mutex report_mutex;
 | 
						|
	struct sk_buff *report_return;
 | 
						|
	wait_queue_head_t report_queue;
 | 
						|
 | 
						|
	/* Used in hidp_output_raw_report() */
 | 
						|
	int output_report_success; /* boolean */
 | 
						|
 | 
						|
	/* Report descriptor */
 | 
						|
	__u8 *rd_data;
 | 
						|
	uint rd_size;
 | 
						|
 | 
						|
	wait_queue_head_t startup_queue;
 | 
						|
	int waiting_for_startup;
 | 
						|
};
 | 
						|
 | 
						|
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(sk_sleep(ctrl_sk));
 | 
						|
	wake_up_interruptible(sk_sleep(intr_sk));
 | 
						|
}
 | 
						|
 | 
						|
/* HIDP init defines */
 | 
						|
extern int __init hidp_init_sockets(void);
 | 
						|
extern void __exit hidp_cleanup_sockets(void);
 | 
						|
 | 
						|
#endif /* __HIDP_H */
 |