[Cbe-oss-dev] [PATCH 2/2] hid/hid-sony: get and set Sixaxis bdaddr via sysfs

Bastien Nocera hadess at hadess.net
Thu Sep 2 02:17:54 EST 2010


On Mon, 2010-05-03 at 22:15 +0200, Antonio Ospite wrote:
> Expose to userspace a simple way to get device bdaddr, and get/set master
> bdaddr on Sixaxis controller.
> 
> Right now userspace softwares which manage pairing the controller with a
> bluetooth adapter, rely on libusb and hence have to detach and reattach
> usbhid, which is not very nice.
> 
> Signed-off-by: Antonio Ospite <ospite at studenti.unina.it>
> ---
> 
> As said, ideally this should be done with an interface such as hidraw, but its
> limitations prevent us from doing it the right way; and I am not going to
> touch hidraw myself anytime soon.

Rest looks alright to me. Thanks!

>  drivers/hid/hid-sony.c |  148 +++++++++++++++++++++++++++++++++++++++++++++++-
>  1 files changed, 145 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
> index d61f268..1b611ec 100644
> --- a/drivers/hid/hid-sony.c
> +++ b/drivers/hid/hid-sony.c
> @@ -47,6 +47,131 @@ static void sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
>  }
>  
>  /*
> + * Show and set the master bdaddr for PS3 controller, without disconnecting
> + * the device.
> + */
> +static ssize_t show_sixaxis_master_bdaddr(struct device *dev,
> +		struct device_attribute *attr, char *buf)
> +{
> +	struct usb_interface *intf = to_usb_interface(dev);
> +	struct usb_device *udev = interface_to_usbdev(intf);
> +	__u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
> +	int ret;
> +	unsigned char *mbuf = kmalloc(9, GFP_KERNEL);
> +
> +	if (!mbuf)
> +		return -ENOMEM;
> +
> +	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
> +				 HID_REQ_GET_REPORT,
> +				 USB_DIR_IN | USB_TYPE_CLASS |
> +				 USB_RECIP_INTERFACE,
> +				 (3 << 8) | 0xf5, ifnum, mbuf, 8,
> +				 USB_CTRL_GET_TIMEOUT);
> +	if (ret < 0)
> +		dev_err(dev, "%s failed to get master bdaddr, ret: %d\n",
> +				__func__, ret);
> +	else
> +		/* 18 is strlen("00:00:00:00:00:00\n") */

Could you please check for the actual returned length of mbuf here?

> +		ret = snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x\n",
> +				mbuf[2], mbuf[3], mbuf[4],
> +				mbuf[5], mbuf[6], mbuf[7]);
> +
> +	kfree(mbuf);
> +
> +	return ret;
> +}
> +
> +static ssize_t store_sixaxis_master_bdaddr(struct device *dev,
> +		struct device_attribute *attr, const char *buf, size_t count)
> +{
> +	struct usb_interface *intf = to_usb_interface(dev);
> +	struct usb_device *udev = interface_to_usbdev(intf);
> +	__u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
> +	int ret;
> +	unsigned char *mbuf = kmalloc(9, GFP_KERNEL);

Check for count != 6 and bail?
And also check for mbuf != NULL.

> +	mbuf[0] = 0x01;
> +	mbuf[1] = 0x00;
> +	ret = sscanf(buf, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
> +			&mbuf[2], &mbuf[3], &mbuf[4],
> +			&mbuf[5], &mbuf[6], &mbuf[7]);
> +	if (ret != 6) {
> +		dev_err(dev, "%s failed, ret: %d\n", __func__, ret);
> +		return -EINVAL;
> +	}
> +
> +	ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
> +				 HID_REQ_SET_REPORT,
> +				 USB_DIR_OUT | USB_TYPE_CLASS |
> +				 USB_RECIP_INTERFACE,
> +				 (3 << 8) | 0xf5, ifnum, mbuf, 8,
> +				 USB_CTRL_GET_TIMEOUT);
> +
> +	kfree(mbuf);
> +
> +	if (ret < 0) {
> +		dev_err(dev, "%s failed to set master bdaddr, ret: %d\n",
> +				__func__, ret);
> +		return ret;
> +	}
> +
> +	return count;
> +}
> +
> +/*
> + * Show the bdaddr for PS3 controller, without disconnecting the device.
> + */
> +static ssize_t show_sixaxis_bdaddr(struct device *dev,
> +		struct device_attribute *attr, char *buf)
> +{
> +	struct usb_interface *intf = to_usb_interface(dev);
> +	struct usb_device *udev = interface_to_usbdev(intf);
> +	__u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
> +	int ret;
> +	unsigned char *mbuf = kmalloc(18, GFP_KERNEL);
> +
> +	if (!mbuf)
> +		return -ENOMEM;
> +
> +	ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
> +				 HID_REQ_GET_REPORT,
> +				 USB_DIR_IN | USB_TYPE_CLASS |
> +				 USB_RECIP_INTERFACE,
> +				 (3 << 8) | 0xf2, ifnum, mbuf, 17,
> +				 USB_CTRL_GET_TIMEOUT);
> +	if (ret < 0)
> +		dev_err(dev, "%s failed to get device bdaddr, ret: %d\n",
> +				__func__, ret);
> +	else
> +		/* 18 is strlen("00:00:00:00:00:00\n") */

length of mbuf != 9?

> +		ret = snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x\n",
> +				mbuf[4], mbuf[5], mbuf[6],
> +				mbuf[7], mbuf[8], mbuf[9]);
> +
> +	kfree(mbuf);
> +
> +	return ret;
> +}
> +
> +static DEVICE_ATTR(sixaxis_master_bdaddr, S_IWUSR|S_IRUGO,
> +		show_sixaxis_master_bdaddr, store_sixaxis_master_bdaddr);
> +
> +static DEVICE_ATTR(sixaxis_bdaddr, S_IRUGO,
> +		show_sixaxis_bdaddr, NULL);
> +
> +static struct attribute *sixaxis_attributes[] = {
> +	&dev_attr_sixaxis_master_bdaddr.attr,
> +	&dev_attr_sixaxis_bdaddr.attr,
> +	NULL
> +};
> +
> +static const struct attribute_group sixaxis_attr_group = {
> +	.attrs = sixaxis_attributes,
> +};
> +
> +
> +/*
>   * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
>   * to "operational".  Without this, the ps3 controller will not report any
>   * events.
> @@ -57,8 +182,9 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
>  	struct usb_device *dev = interface_to_usbdev(intf);
>  	__u16 ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
>  	int ret;
> -	char *buf = kmalloc(18, GFP_KERNEL);
> +	unsigned char *buf = kmalloc(18, GFP_KERNEL);

buf != NULL.

> +	dev_info(&hdev->dev, "Calling %s\n", __func__);
>  	if (!buf)
>  		return -ENOMEM;
>  
> @@ -70,6 +196,9 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
>  				 USB_CTRL_GET_TIMEOUT);
>  	if (ret < 0)
>  		dev_err(&hdev->dev, "can't set operational mode\n");
> +	else
> +		dev_info(&hdev->dev, "Sony PS3 Controller bdaddr: %02x:%02x:%02x:%02x:%02x:%02x\n",
> +				buf[4], buf[5], buf[6], buf[7], buf[8], buf[9]);
>  
>  	kfree(buf);
>  
> @@ -110,9 +239,17 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
>  		goto err_free;
>  	}
>  
> -	if (sc->quirks & SIXAXIS_CONTROLLER_USB)
> +	if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
> +		struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
> +		ret = sysfs_create_group(&intf->dev.kobj, &sixaxis_attr_group);
> +		if (ret < 0) {
> +			dev_err(&hdev->dev,
> +				"cannot register sixaxis sysfs hooks\n");
> +			goto err_stop;
> +		}
> +
>  		ret = sixaxis_set_operational_usb(hdev);
> -	else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
> +	} else if (sc->quirks & SIXAXIS_CONTROLLER_BT)
>  		ret = sixaxis_set_operational_bt(hdev);
>  	else
>  		ret = 0;
> @@ -130,6 +267,11 @@ err_free:
>  
>  static void sony_remove(struct hid_device *hdev)
>  {
> +	struct sony_sc *sc = hid_get_drvdata(hdev);
> +	if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
> +		struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
> +		sysfs_remove_group(&intf->dev.kobj, &sixaxis_attr_group);
> +	}
>  	hid_hw_stop(hdev);
>  	kfree(hid_get_drvdata(hdev));
>  }




More information about the cbe-oss-dev mailing list