2

I've been trying for a while but have not been able to find a way to control the lights on a set of controllers from the game Buzz (wired, from Playstation 2). You can see some of my failed attempts in my questions over on Stack Overflow

So I turned to a more base linux method of sending messages, and failed to do it by piping data to /dev/hidraw0, too.

Then I discovered a file in the linux repository which refers to the buzz controllers specifically (/linux/drivers/hid/hid-sony.c), and the fact that they have a light. It even has a method called buzz_set_leds (line 1512):

static void buzz_set_leds(struct sony_sc *sc)

So I'm 100% sure that this is the code does what I'm trying to do.

I've had a go at including this in a c file, but am unable to include hid-sony because I seem to be missing these files.

#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/leds.h>
#include <linux/power_supply.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/idr.h>
#include <linux/input/mt.h>

#include "hid-ids.h"

In compilation, I get this error:

hid-sony.c:29:26: fatal error: linux/device.h: No such file or directory
 #include <linux/device.h>
                          ^
compilation terminated.

Sorry, I'm a Ruby programmer with no background in C.

How do I get these missing 'linux/' files and refer to them from my c library - or how can I write to the controllers from the shell?

1

with the sony driver loaded the driver provides standard led kernel interfaces:

echo 255 > /sys/class/leds/*buzz1/brightness
echo 0 > /sys/class/leds/*buzz1/brightness
  • I solved this some time ago, and yes, this turns out to be how I did it, via the standard Linux interface. I actually wrapped it up in a ruby gem: rubygems.org/gems/ruby_buzz – AJFaraday Aug 30 '16 at 13:18
6

From a shell script it is relatively simple but requires knowing the right thing to send. /dev/hidraw devices are called "raw" because they are just that (I suspect) - from this article at a website called developerFusion, that I found, a long time ago, (specifically "figure 3") - that author reported that the device wanted a six-byte report to be sent to it to switch the 4 LEDs (one in each of the four "player" controllers) on or off. Briefly, they had found that, for six bytes 1-6, they were used:

Byte 1: don't care - suggest using 0x00
Byte 2: don't care - suggest using 0x00
Byte 3: 0x00 (off) or 0xFF (on) - Handset 1
Byte 4: 0x00 (off) or 0xFF (on) - Handset 2
Byte 5: 0x00 (off) or 0xFF (on) - Handset 3
Byte 6: 0x00 (off) or 0xFF (on) - Handset 4

So, after some experimenting I found that, for a "Buzz" Controller that the udev system(?) has named/symlinked to /dev/hidraw0 the following will flash each of the LED in sequence:

#!/bin/bash

delay=0.1 while [ true ]; do echo -e "\x00\x00\x00\x00\x00\x00\x00" > /dev/hidraw0 sleep ${delay} echo -e "\x00\x00\x00\x00\x00\xff\x00" > /dev/hidraw0 sleep ${delay} echo -e "\x00\x00\x00\x00\xff\x00\x00" > /dev/hidraw0 sleep ${delay} echo -e "\x00\x00\x00\xff\x00\x00\x00" > /dev/hidraw0 sleep ${delay} echo -e "\x00\x00\xff\x00\x00\x00\x00" > /dev/hidraw0 sleep ${delay} echo -e "\x00\x00\x00\x00\x00\x00\x00" > /dev/hidraw0 sleep ${delay} done

I think the last ASCII "nul" character is required to end the string or it might be an artefact of the language that the author of that article was using (.NET / c#) that hid that seven bytes were being used not six - but then those languages are completely foreign to me. What I found was that if the right length string is not used, that last byte is left off - the string doesn't get recognised, at least after the first string sent which I think is consistent with a "fixed report length" requirement.

I wanted to make things simpler by using udev to provide meaningful names for just such devices so I created a /lib/udev/rules.d/10-local.rules file for my Debian Linux "Jessie" PC (using sysV "init" NOT "systemd"):

ACTION!="add|change", GOTO="end"

# Assign a unique number to a buzz symbolic link to any Sony Buzz controllers
SUBSYSTEM=="usb", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="1000", PROGRAM=="/sbin/unique_number /dev buzz", SYMLINK+="buzz%c", TAG+="buzz", OPTIONS+=last_rule
SUBSYSTEM=="usb", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0002", PROGRAM=="/sbin/unique_number /dev buzz", SYMLINK+="buzz%c", TAG+="buzz", OPTIONS+=last_rule

LABEL="end"

and to provide a unique number - especial in the case where I plug in a hub with multiple Buzz controllers on and will have multiple devices added or removed at the same time, I used the following /sbin/unique_number which WAS derived from somewhere on SE - (I WILL accept edits to give valid attributions/copyrights...):

#!/bin/bash

# Copyright (C) 2015 by Stephen Lyons - slysven@virginmedia.com
#
# unique_number: This script is used to provide a unique suffix for a
#                file in a given directory

if [ $# -ne 2 ]; then
    echo "Usage: $0 location prefix\n\n" >&2
    echo "       Finds the first unused integer # suffixed file"
    echo "       of form prefix# in directory given by location,"
    echo "       and prints that number."
    exit 1
fi

location="$1"
prefix="$2"

index=0

while [ -e "/var/lock/unique_number.lock" ]; do
    sleep 0.1;
done

touch "/var/lock/unique_number.lock"

until [ ! -e "${location}/${prefix}${index}" ]; do
    (( index++ ));
done
echo "$index"

rm "/var/lock/unique_number.lock"
exit 0

However, whilst this does provide /dev/buzz0, /dev/buzz1 as I wanted, this combination does not work to provide something that can replace /dev/hidraw0 etc. in the first script.

2

Well, your source file correspond to a source of linux driver. So you will have to compile it as a module. To compile it out of the kernel source tree, I recommend you to use the following makefile:

ifneq ($(KERNELRELEASE),)
        obj-m := hid-sony.o
else
        KDIR ?= /lib/modules/$(shell uname -r)/build
        PWD := $(shell pwd)

default:
        $(MAKE) -C $(KDIR) M=$(PWD) modules
endif

Copy this content to a file that you will name "makefile" in the same location as your c source code, then run the command "make". You will need have linux kernel header installed , you can usually get them from packages ( linux-headers-x.yy.zz-your_arch on debian ). This will produce you a .ko file that you can then load into your kernel with insmod command (need to be root).

  • I asked the same question over on stack overflow and found that the lights were exposed under /sys/class/leds, which actually lets me continue with my project. I might have a go at packaging this up at some point, tho. Looks like an interesting project. – AJFaraday Sep 17 '15 at 23:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.