Bluez hid analysis-Linux kernel Section

Source: Internet
Author: User
Tags sendmsg

This article introduces the kernel section of Bluetooth protocol stack bluez which implements the hid function in Linux.

In Linux kernel, the implementation code of bluez for HID is in the/NET/Bluetooth/hidp folder, which includes three files: sock. C, core. C, and hidp. h. Bluez provides a socket interface by which user space programs control hid. The Protocol number used by this socket is btproto_hidp.

1. Initialization

The hidp is initialized in the hidp_init_sockets function of sock. C.

Int _ init hidp_init_sockets (void)

Err = proto_register (& hidp_proto, 0); // register proto, which can be ignored

// Register a btproto_hidp Protocol Number

Err = bt_sock_register (btproto_hidp, & hidp_sock_family_ops );

Bt_sock_register is a bluez internal function that registers the passed-in to the net_proto_family struct to the Global Array bt_proto.

Int bt_sock_register (INT proto, const struct net_proto_family * OPS)

...

Bt_proto [proto] = OPS;

...

The idea used here is similar to the MISC driver in the character device driver. After registration, the user space can use the standard socket operation to obtain the socket of the hidp:

Int Sk = socket (af_bluetooth, sock_raw, btproto_hidp );

Next let's take a look at the content of the hidp_sock_family_ops struct:

Static const struct net_proto_family hidp_sock_family_ops = {

. Family = pf_bluetooth,

. Owner = this_module,

. Create = hidp_sock_create

};

The most important here is the hidp_socke_create function, which specifies the socket proto_ops.

Static int hidp_sock_create (struct net * Net, struct socket * sock, int protocol,

Int Kern)

Struct sock * SK;

If (sock-> type! = Sock_raw)

Return-esocktnosupport;

SK = sk_alloc (net, pf_bluetooth, gfp_atomic, & hidp_proto );

Sock_init_data (sock, SK );

Sock-> Ops = & hidp_sock_ops;

Sock-> state = ss_unconnected;

Sock_reset_flag (SK, sock_zapped );

SK-> sk_protocol = protocol;

SK-> sk_state = bt_open;

...

Definition of hidp_sock_ops:

Static const 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

};

It can be seen from hidp_sock_ops that the socket of btproto_hidp does not support common socket operations, such as bind, connnect, sendmsg, and recvmsg. The socket actually supports only the ioctl operation. The list of commands supported in IOCTL is as follows:

Hidpconnadd // Add a HID device

Hidpconndel // Delete the specified HID device

Hidpgetconnlist // obtain the list of all current hid Devices

Hidpgetconninfo // obtain the information of the specified HID device.

2. hidpconnadd

The hidpconnadd command is used to add a HID device. The parameter passed down by the user space is the struct hidp_connadd_req:

Struct hidp_connadd_req {

Int ctrl_sock; // control socket, similar to control pipe in USB

Int intr_sock; // interrupt socket, similar to int pipe in USB

_ B2parser;

_ 2010rd_size; // report descriptor size

_ U8 _ User * rd_data; // report Descriptor

_ U8 country; // Country Code. For example, if the keyboard is an American or a French keyboard

_ U8 subclass;

_ 2010vendor;

_ 2010product;

_ 2010version;

_ U32 flags;

_ U32 idle_to;

Char name [128];

};

It can be seen from the struct that the socket sends/receives external data through ctrl_sock and intr_sock. These two sockets are passed in after the user space is created.

The process of hidpconnadd is as follows:

Struct socket * csock;

Struct socket * isock;

Struct hidp_connadd_req CA;

...

Csock = sockfd_lookup (ca. ctrl_sock, & ERR );

Isock = sockfd_lookup (ca. intr_sock, & ERR );

Hidp_add_connection (& Ca, csock, isock );

 

Int hidp_add_connection (struct hidp_connadd_req * req, struct socket * ctrl_sock, struct socket * intr_sock)

...

// Ensure that the Source and Destination addresses of CTRL socket and intr socket are the same

If (bacmp (& bt_sk (ctrl_sock-> SK)-> SRC, & bt_sk (intr_sock-> SK)-> SRC) |

Bacmp (& bt_sk (ctrl_sock-> SK)-> DST, & bt_sk (intr_sock-> SK)-> DST ))

Return-enotuniq;

// Initialize the hidp_session Structure

Session-> ctrl_sock = ctrl_sock;

Session-> intr_sock = intr_sock;

Session-> state = bt_connected;

Setup_timer (& session-> timer, hidp_idle_timeout, (unsigned long) session );

Skb_queue_head_init (& session-> ctrl_transmit );

Skb_queue_head_init (& session-> intr_transmit );

...

// If a report descriptor exists, create the HID device and parse the descriptor through the hid framework.

If (req-> rd_size> 0)

Err = hidp_setup_hid (Session, req );

...

// If no report descriptor exists in req, no HID device is created, and an input device is created. This condition is only valid for HID Boot Protocol devices and does not require a report descriptor for such devices. For more information, see the document of the HID device. Since the input device is relatively simple, we will not discuss it here

If (! Session-> hid)

Err = hidp_setup_input (Session, req );

...

// Mount the session to the hidp_session_list linked list

...

// Create a kernel task

Kernel_thread (hidp_session, session, clone_kernel );

At this point, the remaining two functions need further analysis. One is hidp_setup_hid, and the other is hidp_session. Hidp_session is relatively simple:

Static int hidp_session (void * Arg)

Loop

// If CTRL socket receives data, it receives and processes the data. The data content in the CTRL channel establishes a connection, the notification of the other party's disconnection, and the user data received through the CTRL channel.

// If the int channel receives data, it receives and processes the data. Transmit user data in the int channel. For example, move the mouse or press the keyboard. If this session uses a HID device, call hid_input_report to send the data to the hid framework, which sends the data to the user space program. If the input device is used, then, the system finally calls input_report_key to send data to the user space.

// If the control channel has data to send, it will be sent to CTRL socket, for example, actively initiated connection disconnection and connection establishment.

// If data in the int channel is to be sent, it is sent. Send user data here, such as controlling LED lights on the keyboard.

 

Next we will analyze the hidp_setup_hid function, which initializes a HID device and registers it to the hid system.

Static int hidp_setup_hid (struct hidp_session * Session, struct hidp_connadd_req * req)

Struct hid_device * hid;

...

Hid = hid_allocate_device ();

Session-> hid = hid;

Hid-> driver_data = session;

...

// Set the parent device of the hid to its HCI Device

Hid-> Dev. Parent = hidp_get_device (session );

// Set the physical layer driver for the HID device

Hid-> ll_driver = & hidp_hid_driver;

// When the hid framework needs to send data to the device, the hid_output_raw_report,

// The data sent here will go through CTRL socket

Hid-> hid_output_raw_report = hidp_output_raw_report;

Hid_add_device (HID );

...

Hidp_hid_driver is a struct used to describe the physical layer driver corresponding to the HID device.

Static struct hid_ll_driver hidp_hid_driver = {

// The hid Framework's hid_parse_report will be called to complete report descriptor parsing.

. Parse = hidp_parse,

// The start function is strange. It may be implemented according to the hid protocol specification.

. Start = hidp_start,

// Clear the cached data to be sent

. Stop = hidp_stop,

. Open = hidp_open, // empty Function

. Close = hidp_close, // empty Function

// Here the input_event is from the local device to the device, that is, the function called when data is sent, using the int socket Channel

. Hidinput_input_event = hidp_hidinput_event,

};

 

In summary, when data is received from the device to the local machine, it is processed in the hidp_session kernel task. when data is sent from the local machine to the device, the hid Framework calls hidp_hidinput_event or hidp_output_raw_report, depending on whether the data is CTRL or Int channel data. All data is sent and received through CTRL socket and INT socket, and these two sockets are passed in by calling IOCTL hidpconnadd of btproto_hidp socket after the user space is created.

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.