Well, I fired off some emails to the mythtv users mailing list a long time ago with the intention of getting the lola remote to work out of the box with knoppmyth. I have had no time at all to devote to it, so now I'm passing the torch. I'd upload the code to here that I got from the mailing list to pretty much make the lola remote work, but it doesn't look like this list supports uploading code, so i'll put it as text here and if you want a better copy then email me.
Here's an lircrc file:
Code:
#Starts the mythfrontend from X
begin
prog = irexec
button = power
config = sudo /sbin/shutdown -r now
end
begin
prog = irexec
button = 2
config = sudo /sbin/service mythbackend restart
end
begin
prog = irexec
button = 1
config = /usr/bin/mythfrontend -l ~/frontend.log
end
#MythTV - Number button config
begin
prog = mythtv
button = 0
config = 0
end
begin
prog = mythtv
button = 1
config = 1
end
begin
prog = mythtv
button = 2
config = 2
end
begin
prog = mythtv
button = 3
config = 3
end
begin
prog = mythtv
button = 4
config = 4
end
begin
prog = mythtv
button = 5
config = 5
end
begin
prog = mythtv
button = 6
config = 6
end
begin
prog = mythtv
button = 7
config = 7
end
begin
prog = mythtv
button = 8
config = 8
end
begin
prog = mythtv
button = 9
config = 9
end
#MythTV - Circle button config
begin
prog = mythtv
button = up
config = Up
end
begin
prog = mythtv
button = down
config = Down
end
begin
prog = mythtv
button = right
config = Right
end
begin
prog = mythtv
button = left
config = Left
end
begin
prog = mythtv
button = menu
config = Enter
end
#MythTV - Thumb button config
begin
prog = mythtv
button = toggle_up
config = Up
end
begin
prog = mythtv
button = toggle_down
config = Down
end
begin
prog = mythtv
button = toggle_left
config = Left
end
begin
prog = mythtv
button = toggle_right
config = Right
end
begin
prog = mythtv
button = toggle_enter
config = Enter
end
#MythTV - Page Up button Config
begin
prog = mythtv
button = pg_up
config = Esc
end
#MythTV - Action button config
begin
prog = mythtv
button = play
config = Enter
end
begin
prog = mythtv
button = pause
config = p
end
begin
prog = mythtv
button = rec
config = r
end
begin
prog = mythtv
button = stop
config = Esc
end
begin
prog = mythtv
button = ff
config = Right
end
begin
prog = mythtv
button = rew
config = Left
end
begin
prog = mythtv
button = scan-
config = PgUp
end
begin
prog = mythtv
button = scan+
config = PgDown
end
#MythTV - Misc button config
begin
prog = mythtv
button = end_bt
config = i
end
begin
prog = mythtv
button = find
config = o
end
begin
prog = mythtv
button = top_bt
config = m
end
begin
prog = mythtv
button = select
config = c
end
# Xine - Confiuration
begin
prog = xine
button = pg_up
config = Quit
end
begin
prog = xine
button = play
config = Play
end
begin
prog = xine
button = stop
config = Stop
end
begin
prog = xine
button = pause
config = Pause
end
begin
prog = xine
button = ff
config = RIGHT
end
begin
prog = xine
button = toggle_up
config = EventUp
end
begin
prog = xine
button = toggle_down
config = EventDown
end
begin
prog = xine
button = toggle_right
config = EventRight
end
begin
prog = xine
button = toggle_left
config = EventLeft
end
begin
prog = xine
button = toggle_enter
config = EventSelect
end
begin
prog = xine
button = menu
config = Menu
end
begin
prog = xine
button = ff
config = SeekRelative+30
end
begin
prog = xine
button = rew
config = SeekRelative-30
end
begin
prog = xine
button = toggle_right
config = SeekRelative+600
end
begin
prog = xine
button = toggle_left
config = SeekRelative-600
end
begin
prog = xine
button = scan-
config = EventPrior
end
begin
prog = xine
button = scan+
config = EventNext
end
Here's an lircd.conf file:
Code:
# Please make this file available to others
# by sending it to <lirc@bartelmus.de>
#
# this config file was automatically generated
# using lirc-0.7.0-CVS(atiusb) on Fri May 28 22:10:23 2004
#
# contributed by
#
# brand: lircd.conf
# model no. of remote control:
# devices being controlled by this remote:
#
begin remote
name lircd.conf
bits 40
eps 30
aeps 100
one 0 0
zero 0 0
gap 139898
toggle_bit 0
begin codes
power 0x0000001457028000
up 0x00000014600B8000
down 0x00000014610C8000
left 0x000000145D088000
right 0x000000145E098000
menu 0x000000145F0A8000
1 0x00000014620D8000
2 0x00000014630E8000
3 0x00000014640F8000
4 0x0000001465108000
5 0x0000001466118000
6 0x0000001467128000
7 0x0000001468138000
8 0x0000001469148000
9 0x000000146A158000
0 0x000000146C178000
a_d 0x000000146B168000
a_b 0x000000146D188000
album 0x000000146E198000
artist 0x00000014701B8000
genre 0x0000001476218000
track 0x0000001478238000
pg_up 0x00000014711C8000
pg_down 0x0000001475208000
toggle_up 0x000000146F1A8000
toggle_down 0x0000001477228000
toggle_left 0x00000014721D8000
toggle_right 0x00000014741F8000
toggle_enter 0x00000014731E8000
Playlist 0x0000001456018000
playing 0x00000014822D8000
top_bt 0x00000014832E8000
end_bt 0x00000014842F8000
find 0x000000145C078000
select 0x0000001485308000
scan- 0x00000014802B8000
rew 0x0000001479248000
play 0x000000147A258000
ff 0x000000147B268000
scan+ 0x000000147F2A8000
rec 0x000000147C278000
stop 0x000000147D288000
pause 0x000000147E298000
end codes
end remote
Here's an modified ati remote source:
Code:
/*
*
* Copyright (c) 2002 Vladimir Dergachev
*
* USB ATI Remote support
*
*/
/*
* 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
*
* Should you need to contact me, the author, you can do so by
* e-mail - mail your message to volodya@mindspring.com
*
* This driver was derived from usbati_remote and usbkbd drivers by Vojtech Pavlik
*/
#include <linux/config.h>
#if defined(CONFIG_MODVERSIONS) && !defined(__GENKSYMS__) && !defined(__DEPEND__)
#define MODVERSIONS
#include <linux/modversions.h>
#endif
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>
/*
* Version Information
*/
#define DRIVER_VERSION "2.1.0"
#define DRIVER_AUTHOR "Vladimir Dergachev <volodya@minspring.com>"
#define DRIVER_DESC "USB ATI Remote driver"
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
MODULE_LICENSE("GPL");
MODULE_PARM(channel_mask, "i");
MODULE_PARM_DESC(channel_mask, "bitmask that determines which remote control channels to ignore");
int channel_mask=0;
/* Get hi and low bytes of a 16-bits int */
#define HI(a) ((unsigned char)((a) >> 8))
#define LO(a) ((unsigned char)((a) & 0xff))
#define SEND_FLAG_IN_PROGRESS 1
#define SEND_FLAG_COMPLETE 2
struct ati_remote {
unsigned char data[8];
char name[128];
char input_name[16][160];
unsigned char old[16][2];
unsigned long old_jiffies[16];
struct usb_device *usbdev;
struct input_dev dev[16];
struct urb irq, out;
wait_queue_head_t wait;
int open;
int send_flags;
};
static char init1[]={
0x01, 0x00, 0x20, 0x14 };
static char init2[]={
0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
#define KIND_END 0
#define KIND_LITERAL 1
#define KIND_FILTERED 2
#define KIND_LU 3
#define KIND_RU 4
#define KIND_LD 5
#define KIND_RD 6
#define KIND_ACCEL 7
static struct {
short kind;
unsigned char data1, data2;
int type;
unsigned int code;
int value;
} ati_remote_translation_table[]={
{KIND_LITERAL, 0x3d, 0x78, EV_KEY, BTN_LEFT, 1}, /* left ati_remote button */
{KIND_LITERAL, 0x3e, 0x79, EV_KEY, BTN_LEFT, 0},
{KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1}, /* right ati_remote button */
{KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},
/* ati_remote */
{KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */
{KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */
{KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */
{KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */
{KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */
{KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */
{KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */
{KIND_RD, 0x3b, 0x76, EV_REL, 0, 0}, /* right down */
/* keyboard.. */
{KIND_FILTERED, 0xe2, 0x1d, EV_KEY, KEY_LEFT, 1}, /* key left */
{KIND_FILTERED, 0xe4, 0x1f, EV_KEY, KEY_RIGHT, 1}, /* key right */
{KIND_FILTERED, 0xe7, 0x22, EV_KEY, KEY_DOWN, 1}, /* key down */
{KIND_FILTERED, 0xdf, 0x1a, EV_KEY, KEY_UP, 1}, /* key left */
{KIND_FILTERED, 0xe3, 0x1e, EV_KEY, KEY_ENTER, 1}, /* key enter */
{KIND_FILTERED, 0xd2, 0x0d, EV_KEY, KEY_1, 1},
{KIND_FILTERED, 0xd3, 0x0e, EV_KEY, KEY_2, 1},
{KIND_FILTERED, 0xd4, 0x0f, EV_KEY, KEY_3, 1},
{KIND_FILTERED, 0xd5, 0x10, EV_KEY, KEY_4, 1},
{KIND_FILTERED, 0xd6, 0x11, EV_KEY, KEY_5, 1},
{KIND_FILTERED, 0xd7, 0x12, EV_KEY, KEY_6, 1},
{KIND_FILTERED, 0xd8, 0x13, EV_KEY, KEY_7, 1},
{KIND_FILTERED, 0xd9, 0x14, EV_KEY, KEY_8, 1},
{KIND_FILTERED, 0xda, 0x15, EV_KEY, KEY_9, 1},
{KIND_FILTERED, 0xdc, 0x17, EV_KEY, KEY_0, 1},
{KIND_FILTERED, 0xdd, 0x18, EV_KEY, KEY_C, 1}, /* key A/B */
{KIND_FILTERED, 0xc5, 0x00, EV_KEY, KEY_A, 1},
{KIND_FILTERED, 0xc6, 0x01, EV_KEY, KEY_M, 1}, /* key playlist */
{KIND_FILTERED, 0xde, 0x19, EV_KEY, KEY_G, 1}, /* key album */
{KIND_FILTERED, 0xe0, 0x1b, EV_KEY, KEY_L, 1}, /* key artist */
{KIND_FILTERED, 0xe6, 0x21, EV_KEY, KEY_GRAVE, 1}, /* key genre */
{KIND_FILTERED, 0xe8, 0x23, EV_KEY, KEY_F, 1}, /* key track */
{KIND_FILTERED, 0xdb, 0x16, EV_KEY, KEY_D, 1}, /* key add/del */
{KIND_FILTERED, 0xc7, 0x02, EV_KEY, KEY_ESC, 1}, /* key power */
{KIND_FILTERED, 0xc8, 0x03, EV_KEY, KEY_PROG1, 1}, /* key TV */
{KIND_FILTERED, 0xc9, 0x04, EV_KEY, KEY_PROG2, 1}, /* key DVD */
{KIND_FILTERED, 0xca, 0x05, EV_KEY, KEY_WWW, 1}, /* key Web */
{KIND_FILTERED, 0xcb, 0x06, EV_KEY, KEY_BOOKMARKS, 1}, /* key "open book" */
{KIND_FILTERED, 0xcc, 0x07, EV_KEY, KEY_O, 1}, /* key find */
{KIND_FILTERED, 0xe1, 0x1c, EV_KEY, KEY_PAGEUP, 1}, /* key "timer" */
{KIND_FILTERED, 0xce, 0x09, EV_KEY, KEY_RIGHTBRACE, 1}, /* key vol+ */
{KIND_FILTERED, 0xcd, 0x08, EV_KEY, KEY_LEFTBRACE, 1}, /* key vol- */
{KIND_FILTERED, 0xcf, 0x0a, EV_KEY, KEY_F9, 1}, /* key mute */
{KIND_FILTERED, 0xd1, 0x0c, EV_KEY, KEY_DOWN, 1}, /* next channel*/
{KIND_FILTERED, 0xd0, 0x0b, EV_KEY, KEY_UP, 1}, /* prev channel */
{KIND_FILTERED, 0xec, 0x27, EV_KEY, KEY_R, 1}, /* key record */
{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_P, 1}, /* key play */
{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_LEFT, 1}, /* key rewind */
{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_RIGHT, 1}, /* key ffwd */
{KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_ESC, 1}, /* key stop */
{KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_P, 1}, /* key pause */
{KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_Q, 1}, /* key scan- */
{KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_Z, 1}, /* key scan+ */
{KIND_FILTERED, 0xf2, 0x2d, EV_KEY, KEY_I, 1}, /* key playing */
{KIND_FILTERED, 0xf3, 0x2e, EV_KEY, KEY_HOME, 1}, /* key top */
{KIND_FILTERED, 0xf4, 0x2f, EV_KEY, KEY_END, 1}, /* key end */
{KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_H, 1}, /* key select */
{KIND_FILTERED, 0xe5, 0x20, EV_KEY, KEY_PAGEDOWN, 1}, /* maximize */
{KIND_END, 0x00, 0x00, EV_MAX+1, 0, 0} /* END */
};
/*
* Send a packet of bytes to the device
*/
static void send_packet(struct ati_remote *ati_remote, u16 cmd, unsigned char* data)
{
DECLARE_WAITQUEUE(wait, current);
int timeout = HZ; /* 1 second */
memcpy(ati_remote->out.transfer_buffer + 1, data, LO(cmd));
((char*)ati_remote->out.transfer_buffer)[0] = HI(cmd);
ati_remote->out.transfer_buffer_length = LO(cmd) + 1;
ati_remote->out.dev = ati_remote->usbdev;
ati_remote->send_flags=SEND_FLAG_IN_PROGRESS;
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&ati_remote->wait, &wait);
if (usb_submit_urb(&ati_remote->out)) {
set_current_state(TASK_RUNNING);
remove_wait_queue(&ati_remote->wait, &wait);
printk("done\n");
return;
}
while (timeout && (ati_remote->out.status == -EINPROGRESS) &&
!(ati_remote->send_flags & SEND_FLAG_COMPLETE)){
timeout = schedule_timeout(timeout);
rmb();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&ati_remote->wait, &wait);
usb_unlink_urb(&ati_remote->out);
}
static void ati_remote_irq(struct urb *urb)
{
struct ati_remote *ati_remote = urb->context;
unsigned char *data = ati_remote->data;
struct input_dev *dev = &(ati_remote->dev[0x0f]);
int i;
int accel;
int remote_num=0x0f;
if (urb->status) return;
if(urb->actual_length==4){
if((data[0]!=0x14)||((data[3] & 0x0f)!=0x00))
printk("** weird key=%02x%02x%02x%02x\n", data[0], data[1], data[2], data[3]);
remote_num=(data[3]>>4)&0x0f;
dev=&(ati_remote->dev[remote_num]);
if(channel_mask & (1<<(remote_num+1)))return; /* ignore signals from this channel */
} else
if(urb->actual_length==1){
if((data[0]!=(unsigned char)0xff)&&(data[0]!=0x00))
printk("** weird byte=0x%02x\n", data[0]);
} else {
printk("length=%d %02x %02x %02x %02x %02x %02x %02x %02x\n",
urb->actual_length, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
}
accel=1;
if((urb->actual_length==4) && (ati_remote->old[remote_num][0]==data[1])&&(ati_remote->old[remote_num][1]==data[2])){
if(ati_remote->old_jiffies[remote_num]+4*HZ<jiffies)accel=8;
else
if(ati_remote->old_jiffies[remote_num]+3*HZ<jiffies)accel=6;
else
if(ati_remote->old_jiffies[remote_num]+2*HZ<jiffies)accel=4;
else
if(ati_remote->old_jiffies[remote_num]+HZ<jiffies)accel=3;
else
if(ati_remote->old_jiffies[remote_num]+(HZ>>1)<jiffies)accel=2;
}
if((urb->actual_length==4) && (data[0]==0x14) && ((data[3]&0x0f)==0x00)){
for(i=0;ati_remote_translation_table[i].kind!=KIND_END;i++){
if((((ati_remote_translation_table[i].data1 & 0x0f)==(data[1] & 0x0f))) &&
((((ati_remote_translation_table[i].data1>>4)-(data[1]>>4)+remote_num)&0x0f)==0x0f) &&
(ati_remote_translation_table[i].data2==data[2])){
switch(ati_remote_translation_table[i].kind){
case KIND_LITERAL:
input_event(dev, ati_remote_translation_table[i].type,
ati_remote_translation_table[i].code,
ati_remote_translation_table[i].value);
break;
case KIND_ACCEL:
input_event(dev, ati_remote_translation_table[i].type,
ati_remote_translation_table[i].code,
ati_remote_translation_table[i].value*accel);
break;
case KIND_LU:
input_report_rel(dev, REL_X, -accel);
input_report_rel(dev, REL_Y, -accel);
break;
case KIND_RU:
input_report_rel(dev, REL_X, accel);
input_report_rel(dev, REL_Y, -accel);
break;
case KIND_LD:
input_report_rel(dev, REL_X, -accel);
input_report_rel(dev, REL_Y, accel);
break;
case KIND_RD:
input_report_rel(dev, REL_X, accel);
input_report_rel(dev, REL_Y, accel);
break;
case KIND_FILTERED:
if((ati_remote->old[remote_num][0]==data[1])&&(ati_remote->old[remote_num][1]==data[2])&&((ati_remote->old_jiffies[remote_num]+(HZ>>2))>jiffies)){
return;
}
input_event(dev, ati_remote_translation_table[i].type,
ati_remote_translation_table[i].code,
1);
input_event(dev, ati_remote_translation_table[i].type,
ati_remote_translation_table[i].code,
0);
ati_remote->old_jiffies[remote_num]=jiffies;
break;
default:
printk("kind=%d\n", ati_remote_translation_table[i].kind);
}
break;
}
}
if(ati_remote_translation_table[i].kind==KIND_END){
printk("** unknown key=%02x%02x\n", data[1], data[2]);
}
if((ati_remote->old[remote_num][0]!=data[1])||(ati_remote->old[remote_num][1]!=data[2]))
ati_remote->old_jiffies[remote_num]=jiffies;
ati_remote->old[remote_num][0]=data[1];
ati_remote->old[remote_num][1]=data[2];
}
}
static int ati_remote_open(struct input_dev *dev)
{
struct ati_remote *ati_remote = dev->private;
/* printk("ati_remote_open %d\n", ati_remote->open); */
if (ati_remote->open++)
return 0;
ati_remote->irq.dev = ati_remote->usbdev;
if (usb_submit_urb(&ati_remote->irq)){
printk(KERN_ERR "ati_remote: error submitting urb\n");
return -EIO;
}
/* printk("done: ati_remote_open now open=%d\n", ati_remote->open); */
return 0;
}
static void ati_remote_close(struct input_dev *dev)
{
struct ati_remote *ati_remote = dev->private;
if (!--ati_remote->open)
usb_unlink_urb(&ati_remote->irq);
}
static void ati_remote_usb_out(struct urb *urb)
{
struct ati_remote *ati_remote = urb->context;
if (urb->status) return;
ati_remote->send_flags|=SEND_FLAG_COMPLETE;
wmb();
if (waitqueue_active(&ati_remote->wait))
wake_up(&ati_remote->wait);
}
static void *ati_remote_probe(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
{
struct usb_interface *iface;
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint, *epout;
struct ati_remote *ati_remote;
int pipe, maxp;
char *buf;
int i,j;
iface = &dev->actconfig->interface[ifnum];
interface = &iface->altsetting[iface->act_altsetting];
if (interface->bNumEndpoints != 2) return NULL;
/* use the first endpoint only for now */
endpoint = interface->endpoint + 0;
if (!(endpoint->bEndpointAddress & 0x80)) return NULL;
if ((endpoint->bmAttributes & 3) != 3) return NULL;
epout = interface->endpoint + 1;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
printk("maxp=%d endpoint=0x%02x\n", maxp, endpoint->bEndpointAddress);
usb_set_idle(dev, interface->bInterfaceNumber, 0, 0);
if (!(ati_remote = kmalloc(sizeof(struct ati_remote)+32, GFP_KERNEL))) return NULL;
memset(ati_remote, 0, sizeof(struct ati_remote)+32);
ati_remote->usbdev = dev;
if (!(buf = kmalloc(63, GFP_KERNEL))) {
kfree(ati_remote);
return NULL;
}
if (dev->descriptor.iManufacturer &&
usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0)
strcat(ati_remote->name, buf);
if (dev->descriptor.iProduct &&
usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
sprintf(ati_remote->name, "%s %s", ati_remote->name, buf);
if (!strlen(ati_remote->name))
sprintf(ati_remote->name, "USB ATI (X10) remote %04x:%04x",
dev->descriptor.idVendor, dev->descriptor.idProduct);
kfree(buf);
for(i=0;i<16;i++){
for(j=0;ati_remote_translation_table[j].kind!=KIND_END;j++)
if(ati_remote_translation_table[j].type==EV_KEY)
set_bit(ati_remote_translation_table[j].code, ati_remote->dev[i].keybit);
clear_bit(BTN_LEFT, ati_remote->dev[i].keybit);
clear_bit(BTN_RIGHT, ati_remote->dev[i].keybit);
ati_remote->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
ati_remote->dev[i].keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
ati_remote->dev[i].relbit[0] = BIT(REL_X) | BIT(REL_Y);
ati_remote->dev[i].keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
ati_remote->dev[i].relbit[0] |= BIT(REL_WHEEL);
ati_remote->dev[i].private = ati_remote;
ati_remote->dev[i].open = ati_remote_open;
ati_remote->dev[i].close = ati_remote_close;
sprintf(ati_remote->input_name[i], "%s remote channel %d", ati_remote->name, i+1);
ati_remote->dev[i].name = ati_remote->input_name[i];
ati_remote->dev[i].idbus = BUS_USB;
ati_remote->dev[i].idvendor = dev->descriptor.idVendor;
ati_remote->dev[i].idproduct = dev->descriptor.idProduct;
ati_remote->dev[i].idversion = dev->descriptor.bcdDevice;
ati_remote->old[i][0]=0;
ati_remote->old[i][1]=0;
ati_remote->old_jiffies[i]=jiffies;
}
init_waitqueue_head(&ati_remote->wait);
printk("bInterval=%d\n", endpoint->bInterval);
FILL_INT_URB(&ati_remote->irq, dev, pipe, ati_remote->data, maxp > 8 ? 8 : maxp,
ati_remote_irq, ati_remote, endpoint->bInterval);
FILL_INT_URB(&ati_remote->out, dev, usb_sndintpipe(dev, epout->bEndpointAddress),
ati_remote + 1, 32, ati_remote_usb_out, ati_remote, epout->bInterval);
printk(KERN_INFO "%s on usb%d:%d.%d\n",
ati_remote->name, dev->bus->busnum, dev->devnum, ifnum);
for(i=0;i<16;i++){
input_register_device(&(ati_remote->dev[i]));
printk(KERN_INFO "\tremote control channel %d corresponds to input%d\n",
i+1, ati_remote->dev[i].number);
}
send_packet(ati_remote, 0x8004, init1);
send_packet(ati_remote, 0x8007, init2);
return ati_remote;
}
static void ati_remote_disconnect(struct usb_device *dev, void *ptr)
{
int i;
struct ati_remote *ati_remote = ptr;
usb_unlink_urb(&ati_remote->irq);
for(i=0;i<16;i++)
input_unregister_device(&(ati_remote->dev[i]));
kfree(ati_remote);
}
static struct usb_device_id ati_remote_id_table [] = {
{ USB_DEVICE(0x0bc7, 0x004) },
{ USB_DEVICE(0x0bc7, 0x002) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, ati_remote_id_table);
static struct usb_driver ati_remote_driver = {
name: "ati_remote",
probe: ati_remote_probe,
disconnect: ati_remote_disconnect,
id_table: ati_remote_id_table,
};
static int __init ati_remote_init(void)
{
usb_register(&ati_remote_driver);
info(DRIVER_VERSION ":" DRIVER_DESC);
return 0;
}
static void __exit ati_remote_exit(void)
{
usb_deregister(&ati_remote_driver);
}
module_init(ati_remote_init);
module_exit(ati_remote_exit);
Here's the makefile for the above file:
Code:
ifeq ($(KDIR),)
export KDIR := /usr/src/linux
endif
ifeq ($(PWD),)
export PWD := $(shell pwd)
endif
ifeq ($(KERNELRELEASE),)
.DEFAULT:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) $(@)
else
ifeq ($(PATCHLEVEL),6)
obj-m := ati_remote26.o
endif
ifeq ($(PATCHLEVEL),4)
obj-m := ati_remote.o
TOPDIR := $(KDIR)
include $(TOPDIR)/Rules.make
endif
endif
.PHONY: install test remove clean tarball
all: modules
install: modules
echo "Installation rule TODO (is tricky)"
test: modules
sync
insmod $(PWD)/ati_remote26.ko || insmod $(PWD)/ati_remote.o
remove:
sync
rmmod ati_remote26 || rmmod ati_remote
clean:
rm -f $(PWD)/*.o $(PWD)/*.ko $(PWD)/*.bck $(PWD)/*.bak $(PWD)/core
rm -f $(PWD)/*.mod.c $(PWD)/.*.cmd $(PWD)/.*.flags
tarball:
(cd $(PWD)/.. ; tar cvf - ati_remote/ati_remote.c ati_remote/ati_remote26.c ati_remote/Makefile ati_remote/README ati_remote/README_LIRC ati_remote/README.Makefile | gzip - ) > $(PWD)/ati_remote.tgz
Above is two ways to do it, one with lirc and one with modified ati remote driver. have fun guys;)
Chris