3

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?

3 Answers 3

7

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 - [email protected]
#
# 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.

1
  • Thanks a lot on my Laptop it was /dev/hidraw2.
    – MrSmith42
    Commented Feb 14, 2021 at 17:43
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).

1
  • 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
    Commented Sep 17, 2015 at 23:43
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
1
  • 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
    Commented Aug 30, 2016 at 13:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .