POD HD500X Linux

[UPDATE] This patch is already included in Kernel 4.13.
This patch should work in kernel 4.9 and above (until 4.13 in which is included). This is because hd500x use a lot from x3 which is included in kernel 4.9.
Please take into consideration that modifying your kernel can cause severe damage to your system if something goes wrong. To prevent this is good to have more than one Kernel to chose from in grub or similar, so if one gets corrupted, you can boot from the other one.

In the easy fix (PATCH 1) you only need to modify podhd.c, with only that modification you get an "receive length failed (error -11)" error during initialization but that's not a big deal.
If you want to get rid of that error you can read "solving error -11" (PATCH 2) below.
Everything that starts with $ is a terminal command.

First you must backup (move) your current snd-usb-line-ko and snd-usb-podhd.ko modules. In ubuntu it would be:
$ sudo mv -v /lib/modules/$(uname -r)/kernel/sound/usb/line6/snd-usb-line6.ko /lib/modules/$(uname -r)/kernel/sound/usb/line6/snd-usb-line6.ko.backup

$ sudo mv -v /lib/modules/$(uname -r)/kernel/sound/usb/line6/snd-usb-podhd.ko /lib/modules/$(uname -r)/kernel/sound/usb/line6/snd-usb-podhd.ko.backup

Then you need to download the source code of your kernel, then navigate to
YOURKERNELSRC/sound/usb/line6/

There you must backup your current podhd.c
$ sudo cp podhd.c podhd.c.backup

Then you must modify podhd.c finding this lines and adding what is in blue:
enum {
    LINE6_PODHD300,
    LINE6_PODHD400,
    LINE6_PODHD500_0,
    LINE6_PODHD500_1,
    LINE6_PODX3,
    LINE6_PODX3LIVE,
    LINE6_PODHD500X
};


and:

/* table of devices that work with this driver */
static const struct usb_device_id podhd_id_table[] = {
    /* TODO: no need to alloc data interfaces when only audio is used */
    { LINE6_DEVICE(0x5057),    .driver_info = LINE6_PODHD300 },
    { LINE6_DEVICE(0x5058),    .driver_info = LINE6_PODHD400 },
    { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 },
    { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 },
    { LINE6_IF_NUM(0x414A, 0), .driver_info = LINE6_PODX3 },
    { LINE6_IF_NUM(0x414B, 0), .driver_info = LINE6_PODX3LIVE },
    { LINE6_IF_NUM(0x4159, 0), .driver_info = LINE6_PODHD500X },
    {}
};


and:
    [LINE6_PODX3] = {
        .id = "PODX3",
        .name = "POD X3",
        .capabilities    = LINE6_CAP_CONTROL
                | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT ,
        .altsetting = 1,
        .ep_ctrl_r = 0x81,
        .ep_ctrl_w = 0x01,
        .ctrl_if = 1,
        .ep_audio_r = 0x86,
        .ep_audio_w = 0x02,
    },
    [LINE6_PODX3LIVE] = {
        .id = "PODX3LIVE",
        .name = "POD X3 LIVE",
        .capabilities    = LINE6_CAP_CONTROL
                | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
        .altsetting = 1,
        .ep_ctrl_r = 0x81,
        .ep_ctrl_w = 0x01,
        .ctrl_if = 1,
        .ep_audio_r = 0x86,
        .ep_audio_w = 0x02,
    },
    [LINE6_PODHD500X] = {
        .id = "PODHD500X",
        .name = "POD HD500X",
        .capabilities    = LINE6_CAP_CONTROL
                | LINE6_CAP_PCM | LINE6_CAP_HWMON,
        .altsetting = 1,
        .ep_ctrl_r = 0x81,
        .ep_ctrl_w = 0x01,
        .ctrl_if = 1,
        .ep_audio_r = 0x86,
        .ep_audio_w = 0x02,
    },
};


Compiling:
Then you must compile and install the new modules, in YOURKERNELSRC/sound/usb/line6/ run this:
$ sudo make -C /lib/modules/$(uname -r)/build M=$(pwd) modules

$ sudo make -C /lib/modules/$(uname -r)/build M=$(pwd) modules_install

$ sudo rmmod snd-usb-podhd
$ sudo rmmod snd-usb-line6

$ sudo depmod

$ sudo modprobe snd-usb-line6
$ sudo modprobe snd-usb-podhd


Then plug your device to AC first and then to your system (It doesn't work the other way for me). It should be working.

$ cat /proc/asound/cards

you should see your device.
Take into considerantion that the volume could be very low so run alsamixer and with F6 change the soundcard to give more volume. In VLC you can chose wich card to send the audio.
Also you should be able to run jack with it.

##############################################
Solving error -11 (PATCH2)

you must also backup driver.h
$ sudo cp driver.h driver.h.backup

And modify those 2 files.
In driver.h you need to find this lines and add what is in blue:
/* Capability bits */
enum {
    /* device supports settings parameter via USB */
    LINE6_CAP_CONTROL =    1 << 0,
    /* device supports PCM input/output via USB */
    LINE6_CAP_PCM =        1 << 1,
    /* device supports hardware monitoring */
    LINE6_CAP_HWMON =    1 << 2,
    /* device requires output data when input is read */
    LINE6_CAP_IN_NEEDS_OUT = 1 << 3,
    /* device uses raw MIDI via USB (data endpoints) */
    LINE6_CAP_CONTROL_MIDI = 1 << 4,
    /* device provides low-level information */
    LINE6_CAP_CONTROL_INFO = 1 << 5,
};

and in podhd.c you must change the following in the devices:
    [LINE6_PODX3] = {
        .id = "PODX3",
        .name = "POD X3",
        .capabilities    = LINE6_CAP_CONTROL
                | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT | LINE6_CAP_CONTROL_INFO,
        .altsetting = 1,
        .ep_ctrl_r = 0x81,
        .ep_ctrl_w = 0x01,
        .ctrl_if = 1,
        .ep_audio_r = 0x86,
        .ep_audio_w = 0x02,
    },
    [LINE6_PODX3LIVE] = {
        .id = "PODX3LIVE",
        .name = "POD X3 LIVE",
        .capabilities    = LINE6_CAP_CONTROL
                | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT | LINE6_CAP_CONTROL_INFO,
        .altsetting = 1,
        .ep_ctrl_r = 0x81,
        .ep_ctrl_w = 0x01,
        .ctrl_if = 1,
        .ep_audio_r = 0x86,
        .ep_audio_w = 0x02,
    },

and in podhd_disconnect you can remove or comment (here is commmented with /* */) what's in red and add what's in blue:

static void podhd_disconnect(struct usb_line6 *line6)
{
    struct usb_line6_podhd *pod = (struct usb_line6_podhd *)line6;

/*    if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {*/
    if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
        struct usb_interface *intf;

        del_timer_sync(&pod->startup_timer);
        cancel_work_sync(&pod->startup_work);

        intf = usb_ifnum_to_if(line6->usbdev,
                    pod->line6.properties->ctrl_if);
        usb_driver_release_interface(&podhd_driver, intf);
    }
}

same issue here:
static int podhd_init(struct usb_line6 *line6,
              const struct usb_device_id *id)
{
    int err;
    struct usb_line6_podhd *pod = (struct usb_line6_podhd *) line6;
    struct usb_interface *intf;

    line6->disconnect = podhd_disconnect;

    if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
        /* claim the data interface */
        intf = usb_ifnum_to_if(line6->usbdev,
                    pod->line6.properties->ctrl_if);
        if (!intf) {
            dev_err(pod->line6.ifcdev, "interface %d not found\n",
                pod->line6.properties->ctrl_if);
            return -ENODEV;
        }

        err = usb_driver_claim_interface(&podhd_driver, intf, NULL);
        if (err != 0) {
            dev_err(pod->line6.ifcdev, "can't claim interface %d, error %d\n",
                pod->line6.properties->ctrl_if, err);
            return err;
        }
    }/*don't forget this*/
    if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
        /* create sysfs entries: */
        err = snd_card_add_dev_attr(line6->card, &podhd_dev_attr_group);
        if (err < 0)
            return err;
    }

    if (pod->line6.properties->capabilities & LINE6_CAP_PCM) {
        /* initialize PCM subsystem: */
        err = line6_init_pcm(line6,
            (id->driver_info == LINE6_PODX3 ||
            id->driver_info == LINE6_PODX3LIVE) ? &podx3_pcm_properties :
            &podhd_pcm_properties);
        if (err < 0)
            return err;
    }

/*    if (!(pod->line6.properties->capabilities & LINE6_CAP_CONTROL)) {*/
    if (!(pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO)) {
        /* register USB audio system directly */
        return podhd_startup_finalize(pod);
    }

    /* init device and delay registering */
    init_timer(&pod->startup_timer);
    INIT_WORK(&pod->startup_work, podhd_startup_workqueue);
    podhd_startup(pod);
    return 0;
}


And the do the same we described above for compiling.
Comments