Hi,

From the linux-usb, I found "Philips PSC805 HID Report documentation",
but I found no tools to set the hid values, so with pieces of other hid
code, I wrote the attached hidset.c.
I wasn't sure where to send this source. If somewhere/someone else is
better, let me know.

PSC805, works with 'snd_usb_audio', but by default, does not output to
SPDIF.
To enable SPDIF output:
  hidset ff000086 1
  hidset ff000097 1
And if you want raw data to go over SPDIF, (so you can play ac3/a52
directly with something like 'cat song.ac3 | ac3spdif | aplay -t raw -f
dat -f S16_BE' )
  hidset ff000088 1

-Don Mahurin
/* hidset
 * Don Mahurin, 2006
 * code from dumpev.c and hid-ups ( Paul Stewart)
 *
 * To enable spdif sound in a Philips psc805:
 *   hidset ff000086 1
 *   hidset ff000097 1
 *   To enable raw data stream passthrough (for a52,...)
 *     hidset ff000088 1
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#define HID_MAX_USAGES 1024

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/signal.h>
#include <asm/types.h>
#include <linux/hiddev.h>

static inline int find_application(int fd, unsigned usage) {
        int i = 0;
        unsigned ret;

        while ((ret = ioctl(fd, HIDIOCAPPLICATION, i)) != -1 &&
                ret != usage) { printf("App: %08x\n", ret); i++; }
        if (ret < 0) {
                fprintf(stderr, "GUSAGE returns %x", ret);
                perror("");
        }
        return (ret == usage);
}

static inline int find_usage_ref( int fd, int ucode, struct hiddev_usage_ref 
*usage_ref)
{
  int found = 0;
  int report_type;
  struct hiddev_report_info rep_info;
  unsigned int alv, yalv;
  struct hiddev_field_info field_info;

  /* Initialise the internal report structures */
  if (ioctl(fd, HIDIOCINITREPORT,0) < 0) {
    return 0;
  }
  for (report_type = HID_REPORT_TYPE_MIN; report_type <= HID_REPORT_TYPE_MAX; 
report_type++)
  {
    rep_info.report_type = report_type;
    rep_info.report_id = HID_REPORT_ID_FIRST;
    while (ioctl(fd, HIDIOCGREPORTINFO, &rep_info) >= 0)
    {
#ifdef DEBUG
        printf("  Report id: %d  type: %d (%d fields)\n",
          rep_info.report_id, rep_info.report_type, rep_info.num_fields);
#endif
      for (alv = 0; alv < rep_info.num_fields; alv++)
      { 
        memset(&field_info, 0, sizeof(field_info));
        field_info.report_type = rep_info.report_type;
        field_info.report_id = rep_info.report_id;
        field_info.field_index = alv;
        ioctl(fd, HIDIOCGFIELDINFO, &field_info);
#ifdef DEBUG
        printf("    Field: %d: app: %04x phys %04x flags %x "
               "(%d usages) unit %x exp %d\n", 
               alv, field_info.application, field_info.physical, 
               field_info.flags, field_info.maxusage, field_info.unit,
               field_info.unit_exponent);
#endif
        memset(usage_ref, 0, sizeof(*usage_ref));
        for (yalv = 0; yalv < field_info.maxusage; yalv++)
        {
          usage_ref->report_type = field_info.report_type;
          usage_ref->report_id = field_info.report_id;
          usage_ref->field_index = alv;
          usage_ref->usage_index = yalv;
          ioctl(fd, HIDIOCGUCODE, usage_ref);
          ioctl(fd, HIDIOCGUSAGE, usage_ref);
          if(usage_ref->usage_code == ucode)
          {
            found = 1;
            break;
          }
        }
        if(found) break;
      }
      if(found) break;
      rep_info.report_id |= HID_REPORT_ID_NEXT;
    }
    if(found) break;
  }
  return found;
}

int main (int argc, char **argv)
{
        int fd = -1, i, found = 0;
        struct hiddev_report_info rinfo;
        struct hiddev_usage_ref uref;
        int ucode;
        int findex, uindex;
        int value;

        memset(&uref, 0, sizeof(uref));

        argc--; argv++;
        if(argc < 2)
        {
                printf("usage hidset USAGE_CODE VALUE\n");
                return 1;
        }
        sscanf(*argv, "%x", &ucode);
        argc--; argv++;
        value = atoi(*argv);
        argc--; argv++;

        char evdev[20];
        for (i = 0; i < 4; i++)
        {
                sprintf(evdev, "/dev/hiddev%d", i);
                if ((fd = open(evdev, O_RDONLY)) >= 0) {
                        if (find_usage_ref(fd, ucode, &uref)) {
#ifdef DEBUG
                                printf("application usage code found.\n");
#endif
                                found = 1;
                                break;
                        }
                }
        }
        if (! found) {
                fprintf(stderr, "Couldn't find hiddev device.\n");
                exit(1);
        }

        assert(uref.report_type == HID_REPORT_TYPE_OUTPUT);
        printf ("changing value from %d to %d\n", uref.value, value);
        uref.value = value;
/*fprintf(stderr,"u %u %u %u %u %x %d\n",
        uref.report_type,
        uref.report_id,
        uref.field_index,
        uref.usage_index,
        uref.usage_code,
        uref.value);
*/

        if (ioctl(fd, HIDIOCSUSAGE, &uref) != 0) perror("SUSAGE/S");
        rinfo.report_type = uref.report_type;
        rinfo.report_id = uref.report_id;
        if (ioctl(fd, HIDIOCSREPORT, &rinfo) != 0) perror("SREPORT/S");

        return 0;
}

Reply via email to