From: Bastien Nocera <hadess@hadess.net>
To: BlueZ development <bluez-devel@lists.sourceforge.net>
Subject: Re: [Bluez-devel] HID initiated connections and input service
Date: Mon, 18 Jun 2007 14:06:37 +0100 [thread overview]
Message-ID: <1182171997.3161.29.camel@cookie.hadess.net> (raw)
In-Reply-To: <1182111907.3161.16.camel@cookie.hadess.net>
[-- Attachment #1: Type: text/plain, Size: 794 bytes --]
On Sun, 2007-06-17 at 21:25 +0100, Bastien Nocera wrote:
<snip>
> An example program attached, that I'd like to integrate into
> bluez-utils. Not really tested, as my system decided to not give me the
> HID desc report anymore...
An updated program attached. I got the test of getting the report
descriptor the wrong way around. So it does put data in
my /var/lib/bluetooth/*/input now. But I get those errors in
my /var/log/messages now:
Jun 18 13:56:40 cookie kernel: hidp_input_report: Unknown key (scancode 0x84) pressed.
Jun 18 13:56:40 cookie kernel: hidp_input_report: Unknown key (scancode 0x82) pressed.
Jun 18 13:56:40 cookie kernel: hidp_input_report: Unknown key (scancode 0x82) released.
Any ideas? Did I stuff incorrect data in rd_data?
--
Bastien Nocera <hadess@hadess.net>
[-- Attachment #2: sixpair2.c --]
[-- Type: text/x-csrc, Size: 8896 bytes --]
/* To compile
* gcc -g -Wall -DSTORAGEDIR=\"/var/lib/bluetooth\" -o sixpair2 sixpair2.c storage.c ../common/libhelper.a -I../common `pkg-config --libs --cflags glib-2.0 libusb` -lbluetooth
*/
#include <unistd.h>
#include <stdio.h>
#include <inttypes.h>
#include <bluetooth/bluetooth.h>
#include <bluetooth/hidp.h>
#include <glib.h>
#include <usb.h>
#include "storage.h"
/* Vendor and product ID for the Sixaxis PS3 controller */
#define VENDOR 0x054c
#define PRODUCT 0x0268
#define USB_DIR_IN 0x80
#define USB_DIR_OUT 0
gboolean option_get_master = TRUE;
char *option_master= NULL;
gboolean option_store_info = TRUE;
const char *option_device = NULL;
gboolean option_quiet = FALSE;
const GOptionEntry options[] = {
{ "get-master", '\0', 0, G_OPTION_ARG_NONE, &option_get_master, "Get currently set master address", NULL },
{ "set-master", '\0', 0, G_OPTION_ARG_STRING, &option_master, "Set master address (\"auto\" for automatic", NULL },
{ "store-info", '\0', 0, G_OPTION_ARG_NONE, &option_store_info, "Store the HID info into the input database", NULL },
{ "device", '\0', 0, G_OPTION_ARG_STRING, &option_device, "Only handle one device (default, all supported", NULL },
{ "quiet", 'q', 0, G_OPTION_ARG_NONE, &option_quiet, "Quieten the output", NULL },
{ NULL }
};
static gboolean
show_master (usb_dev_handle *devh, int itfnum)
{
unsigned char msg[8];
int res;
res = usb_control_msg (devh,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0x01, 0x03f5, itfnum,
(void*) msg, sizeof(msg),
5000);
if (res < 0) {
g_warning ("Getting the master Bluetooth address failed");
return FALSE;
}
g_print ("Current Bluetooth master: %02x:%02x:%02x:%02x:%02x:%02x\n",
msg[2], msg[3], msg[4], msg[5], msg[6], msg[7]);
return TRUE;
}
static char *
get_bdaddr (usb_dev_handle *devh, int itfnum)
{
unsigned char msg[17];
char *address;
int res;
res = usb_control_msg (devh,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0x01, 0x03f2, itfnum,
(void*) msg, sizeof(msg),
5000);
if (res < 0) {
g_warning ("Getting the device Bluetooth address failed");
return NULL;
}
address = g_strdup_printf ("%02x:%02x:%02x:%02x:%02x:%02x",
msg[4], msg[5], msg[6], msg[7], msg[8], msg[9]);
if (option_quiet == FALSE) {
g_print ("Device Bluetooth address: %s\n", address);
}
return address;
}
static gboolean
set_master_bdaddr (usb_dev_handle *devh, int itfnum, char *host)
{
unsigned char msg[8];
int mac[6];
int res;
if (sscanf(host, "%x:%x:%x:%x:%x:%x",
&mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) != 6) {
return FALSE;
}
msg[0] = 0x01;
msg[1] = 0x00;
msg[2] = mac[0];
msg[3] = mac[1];
msg[4] = mac[2];
msg[5] = mac[3];
msg[6] = mac[4];
msg[7] = mac[5];
res = usb_control_msg (devh,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0x09, 0x03f5, itfnum,
(void*) msg, sizeof(msg),
5000);
if (res < 0) {
g_warning ("Setting the master Bluetooth address failed");
return FALSE;
}
return TRUE;
}
static char *
get_host_bdaddr (void)
{
FILE *f;
int mac[6];
//FIXME use dbus to get the default adapter
f = popen("hcitool dev", "r");
if (f == NULL) {
//FIXME
return NULL;
}
if (fscanf(f, "%*s\n%*s %x:%x:%x:%x:%x:%x",
&mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) != 6) {
//FIXME
return NULL;
}
return g_strdup_printf ("%x:%x:%x:%x:%x:%x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}
static int
get_record_info (struct usb_interface_descriptor *alt, unsigned int *_len, unsigned int *_country, uint16_t *_version)
{
unsigned char *buf;
unsigned int size, len, country;
uint16_t version;
int l;
len = 0;
country = 0;
version = 0;
if (!alt->extralen)
return 0;
size = alt->extralen;
buf = alt->extra;
while (size >= 2 * sizeof(u_int8_t)) {
if (buf[0] < 2 || buf[1] != USB_DT_HID)
continue;
country = buf[4];
// FIXME is this correct?
version = (buf[2] << 8) + buf[3];
for (l = 0; l < buf[5]; l++) {
/* we are just interested in report descriptors*/
if (buf[6+3*l] != USB_DT_REPORT)
continue;
len = buf[7+3*l] | (buf[8+3*l] << 8);
}
size -= buf[0];
buf += buf[0];
}
if (len == 0)
return -1;
*_len = len;
*_country = country;
*_version = version;
return 0;
}
static void
fill_req_from_usb (struct usb_device *dev, struct hidp_connadd_req *req, unsigned char *data, unsigned int len, unsigned int country, uint16_t version)
{
req->vendor = dev->descriptor.idVendor;
req->product = dev->descriptor.idProduct;
req->version = version;
/* req->subclass already set */
req->country = country;
/* Default value */
req->parser = 0x0100;
/* FIXME what are we expecting here? */
req->flags = 0;
req->rd_size = len;
req->rd_data = data;
}
static void
store_info (const char *host, const char *device, struct hidp_connadd_req *req)
{
bdaddr_t dest, src;
if (str2ba (host, &src) < 0) {
//FIXME
return;
}
if (str2ba (device, &dest) < 0) {
//FIXME
return;
}
store_device_info (&src, &dest, req);
}
static int
handle_device (struct usb_device *dev, struct usb_config_descriptor *cfg, int itfnum, struct usb_interface_descriptor *alt)
{
usb_dev_handle *devh;
int res, retval;
retval = -1;
devh = usb_open (dev);
if (devh == NULL) {
g_warning ("Can't open device");
goto bail;
}
usb_detach_kernel_driver_np (devh, itfnum);
res = usb_claim_interface (devh, itfnum);
if (res < 0) {
g_warning ("Can't claim interface %d", itfnum);
goto bail;
}
if (option_get_master != FALSE) {
if (show_master (devh, itfnum) == FALSE)
goto bail;
retval = 0;
}
if (option_master != NULL) {
if (strcmp (option_master, "auto") == 0) {
g_free (option_master);
option_master = get_host_bdaddr ();
if (option_master == NULL) {
g_warning ("Can't get bdaddr from default device");
retval = -1;
goto bail;
}
}
} else {
option_master = get_host_bdaddr ();
if (option_master == NULL) {
g_warning ("Can't get bdaddr from default device");
retval = -1;
goto bail;
}
}
if (option_store_info != FALSE) {
unsigned char data[8192];
struct hidp_connadd_req req;
unsigned int len, country;
int n;
uint16_t version;
char *device;
device = get_bdaddr (devh, itfnum);
if (device == NULL) {
retval = -1;
goto bail;
}
if (get_record_info (alt, &len, &country, &version) < 0) {
g_warning ("Can't get record info");
retval = -1;
goto bail;
}
if ((n = usb_control_msg(devh,
USB_ENDPOINT_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE,
USB_REQ_GET_DESCRIPTOR,
(USB_DT_REPORT << 8),
itfnum, (void *)data, len, 5000)) < 0) {
g_warning ("Can't get report descriptor (length: %d, interface: %d)", len, itfnum);
retval = -1;
goto bail;
}
req.subclass = alt->bInterfaceSubClass;
fill_req_from_usb (dev, &req, data, n, country, version);
store_info (option_master, device, &req);
if (set_master_bdaddr (devh, itfnum, option_master) == FALSE) {
retval = -1;
goto bail;
}
}
bail:
if (devh != NULL)
usb_close (devh);
return retval;
}
int main (int argc, char **argv)
{
GOptionContext *context;
GError *error = NULL;
struct usb_bus *busses, *bus;
context = g_option_context_new ("- Manage Sixaxis PS3 controllers");
g_option_context_add_main_entries (context, options, NULL);
if (g_option_context_parse (context, &argc, &argv, &error) == FALSE) {
g_warning ("Couldn't parse command-line options: %s", error->message);
return 1;
}
/* Check that the passed bdaddr is correct */
if (option_master != NULL && strcmp (option_master, "auto") != 0) {
//FIXME check bdaddr
}
/* Find device(s) */
usb_init ();
if (usb_find_busses () < 0) {
g_warning ("usb_find_busses failed");
return 1;
}
if (usb_find_devices () < 0) {
g_warning ("usb_find_devices failed");
return 1;
}
busses = usb_get_busses();
if (busses == NULL) {
g_warning ("usb_get_busses failed");
return 1;
}
for (bus = busses; bus; bus = bus->next) {
struct usb_device *dev;
for (dev = bus->devices; dev; dev = dev->next) {
struct usb_config_descriptor *cfg;
/* Here we check for the supported devices */
if (dev->descriptor.idVendor != VENDOR || dev->descriptor.idProduct != PRODUCT)
continue;
/* Look for the interface number that interests us */
for (cfg = dev->config; cfg < dev->config + dev->descriptor.bNumConfigurations; ++cfg) {
int itfnum;
for (itfnum = 0; itfnum < cfg->bNumInterfaces; ++itfnum) {
struct usb_interface *itf = &cfg->interface[itfnum];
struct usb_interface_descriptor *alt;
for (alt = itf->altsetting; alt < itf->altsetting + itf->num_altsetting; ++alt) {
if (alt->bInterfaceClass == 3) {
handle_device (dev, cfg, itfnum, alt);
}
}
}
}
}
}
return 0;
}
[-- Attachment #3: Type: text/plain, Size: 286 bytes --]
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
[-- Attachment #4: Type: text/plain, Size: 164 bytes --]
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
next prev parent reply other threads:[~2007-06-18 13:06 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-06-15 16:44 [Bluez-devel] HID initiated connections and input service Bastien Nocera
2007-06-16 7:05 ` Marcel Holtmann
2007-06-16 16:35 ` Bastien Nocera
2007-06-16 19:35 ` Marcel Holtmann
2007-06-17 20:25 ` Bastien Nocera
2007-06-18 13:06 ` Bastien Nocera [this message]
2007-06-18 14:00 ` Pascal
2007-06-18 14:36 ` Bastien Nocera
2007-06-18 16:00 ` Bastien Nocera
2007-06-18 17:30 ` Pascal
2007-06-18 19:23 ` Bastien Nocera
2007-06-18 20:16 ` Pascal
2007-06-18 22:40 ` Bastien Nocera
2007-06-16 7:25 ` Marcel Holtmann
2007-06-16 16:44 ` Bastien Nocera
2007-06-16 19:24 ` Marcel Holtmann
2007-06-18 16:08 ` Bastien Nocera
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1182171997.3161.29.camel@cookie.hadess.net \
--to=hadess@hadess.net \
--cc=bluez-devel@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox