Package: linux-source-2.6.18 Severity: wishlist Tags: patch Hello,
I have an Apple MacBook Pro and the appleir kernel module is needed for controling rhythmbox with the IR remote (for example). A patch for appleir is maintained in the mactel SVN repository at http://svn.sourceforge.net/viewvc/mactel-linux/trunk/kernel/mactel-patches-2.6.18/ir.patch?view=log I also include the patch here. The patch should be included in vanilla Linux at some time but maybe not before 2.6.20. It would be nice if the Debian kernel for Etch has support for Apple MacBook Pro and non Pro computers. Thanks -- System Information: Debian Release: 4.0 APT prefers testing APT policy: (500, 'testing'), (90, 'unstable'), (1, 'experimental') Architecture: i386 (i686) Shell: /bin/sh linked to /bin/bash Kernel: Linux 2.6.18-3-686 Locale: LANG=fr_FR.UTF-8, LC_CTYPE=fr_FR.UTF-8 (charmap=UTF-8)
--- linux-2.6.16.1/drivers/usb/input/Makefile 2006-03-28 07:49:02.000000000 +0100 +++ linux-2.6.16.1-imac-sky2-rtc/drivers/usb/input/Makefile 2006-05-22 13:14:40.000000000 +0100 @@ -32,6 +32,7 @@ obj-$(CONFIG_USB_HID) += usbhid.o obj-$(CONFIG_USB_KBD) += usbkbd.o obj-$(CONFIG_USB_KBTAB) += kbtab.o +obj-$(CONFIG_USB_APPLEIR) += appleir.o obj-$(CONFIG_USB_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_USB_MOUSE) += usbmouse.o obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o --- linux-2.6.16.1/drivers/usb/input/Kconfig 2006-03-28 07:49:02.000000000 +0100 +++ linux-2.6.16.1-imac-sky2-rtc/drivers/usb/input/Kconfig 2006-05-22 13:15:16.000000000 +0100 @@ -173,6 +173,10 @@ To compile this driver as a module, choose M here: the module will be called acecad. +config USB_APPLEIR + tristate "Apple Mac Mini USB IR receiver (built in)" + depends on USB && INPUT + config USB_KBTAB tristate "KB Gear JamStudio tablet support" depends on USB && INPUT --- linux-2.6.16.1/drivers/usb/input/appleir.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.16.1-imac-sky2-rtc/drivers/usb/input/appleir.c 2006-05-29 09:47:40.000000000 +0100 @@ -0,0 +1,390 @@ +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/input.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/usb.h> +#include <linux/usb/input.h> +#include <asm/unaligned.h> +#include <asm/byteorder.h> + +/* + * Version Information + * + */ + +#if 0 +#define DUMP_PACKETS +#else +#undef DUMP_PACKETS +#endif + +#define DRIVER_VERSION "v1.1" +#define DRIVER_AUTHOR "James McKenzie" +#define DRIVER_DESC "USB Apple MacMini IR Receiver driver" +#define DRIVER_LICENSE "GPL" + +MODULE_AUTHOR (DRIVER_AUTHOR); +MODULE_DESCRIPTION (DRIVER_DESC); +MODULE_LICENSE (DRIVER_LICENSE); + +#ifndef USB_VENDOR_ID_APPLE +#define USB_VENDOR_ID_APPLE 0x05ac +#endif +#ifndef USB_DEVICE_ID_APPLE_IR +#define USB_DEVICE_ID_APPLE_IR 0x8240 +#endif + +#define URB_SIZE 32 + +#define MAX_KEYS 8 +#define MAX_KEYS_MASK (MAX_KEYS - 1 ) + +struct appleir +{ + struct input_dev *dev; + uint8_t *data; + dma_addr_t dma_buf; + struct usb_device *usbdev; + struct urb *urb; + int timer_initted; + struct timer_list key_up_timer; + int current_key; + char phys[32]; +}; + + +static struct usb_device_id appleir_ids[] = { + {USB_DEVICE (USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR),.driver_info = 0}, + {} +}; + +MODULE_DEVICE_TABLE (usb, appleir_ids); + + +/* I have two devices both of which report the following */ +/* 25 87 ee 83 0a + */ +/* 25 87 ee 83 0c - */ +/* 25 87 ee 83 09 << */ +/* 25 87 ee 83 06 >> */ +/* 25 87 ee 83 05 >" */ +/* 25 87 ee 83 03 menu */ +/* 26 00 00 00 00 for key repeat*/ + +/* Thomas Glanzmann reports the following responses */ +/* 25 87 ee ca 0b + */ +/* 25 87 ee ca 0d - */ +/* 25 87 ee ca 08 << */ +/* 25 87 ee ca 07 >> */ +/* 25 87 ee ca 04 >" */ +/* 25 87 ee ca 02 menu */ +/* 26 00 00 00 00 for key repeat*/ +/* He also observes the following event sometimes */ +/* sent after a key is release, which I interpret */ +/* as a flat battery message */ +/* 25 87 e0 ca 06 flat battery */ + + +static int keymap[MAX_KEYS] = { + KEY_RESERVED, KEY_MENU, + KEY_PLAYPAUSE, KEY_NEXTSONG, + KEY_PREVIOUSSONG, KEY_VOLUMEUP, + KEY_VOLUMEDOWN, KEY_RESERVED +}; + +static void +dump_packet (struct appleir *appleir, char *msg, uint8_t * data, int len) +{ + int i; + + printk (KERN_ERR "appleir: %s (%d bytes)", msg, len); + + for (i = 0; i < len; ++i) + { + printk (" %02x", data[i]); + } + + printk ("\n"); +} + + +static void +key_up (struct appleir *appleir, int key) +{ + //printk (KERN_ERR "key %d up\n", key); + input_report_key (appleir->dev, key, 0); + input_sync (appleir->dev); +} + +static void +key_down (struct appleir *appleir, int key) +{ + //printk (KERN_ERR "key %d down\n", key); + input_report_key (appleir->dev, key, 1); + input_sync (appleir->dev); +} + +static void +battery_flat (struct appleir *appleir) +{ + printk (KERN_ERR "appleir: possible flat battery?\n"); +} + +static void +key_up_tick (unsigned long data) +{ + struct appleir *appleir = (struct appleir *) data; + + if (appleir->current_key) + { + key_up (appleir, appleir->current_key); + appleir->current_key = 0; + } +} + +static void +new_data (struct appleir *appleir, uint8_t * data, int len) +{ + static const uint8_t keydown[] = { 0x25, 0x87, 0xee }; + static const uint8_t keyrepeat[] = { 0x26, 0x00, 0x00, 0x00, 0x00 }; + static const uint8_t flatbattery[] = { 0x25, 0x87, 0xe0 }; + +#ifdef DUMP_PACKETS + dump_packet (appleir, "received", data, len); +#endif + + if (len != 5) + return; + + if (!memcmp (data, keydown, sizeof (keydown))) + { + /*If we already have a key down, take it up before marking */ + /*this one down */ + if (appleir->current_key) + key_up (appleir, appleir->current_key); + appleir->current_key = keymap[(data[4] >> 1) & MAX_KEYS_MASK]; + + key_down (appleir, appleir->current_key); + /*remote doesn't do key up, either pull them up, in the test */ + /*above, or here set a timer which pulls them up after 1/8 s */ + mod_timer (&appleir->key_up_timer, jiffies + HZ / 8); + + return; + } + + if (!memcmp (data, keyrepeat, sizeof (keyrepeat))) + { + key_down (appleir, appleir->current_key); + /*remote doesn't do key up, either pull them up, in the test */ + /*above, or here set a timer which pulls them up after 1/8 s */ + mod_timer (&appleir->key_up_timer, jiffies + HZ / 8); + return; + } + + if (!memcmp (data, flatbattery, sizeof (flatbattery))) + { + battery_flat (appleir); + /*Fall through */ + } + + dump_packet (appleir, "unknown packet", data, len); +} + +static void +appleir_urb (struct urb *urb, struct pt_regs *regs) +{ + struct appleir *appleir = urb->context; + int retval; + + switch (urb->status) + { + case 0: + new_data (appleir, urb->transfer_buffer, urb->actual_length); + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* this urb is terminated, clean up */ + dbg ("%s - urb shutting down with status: %d", __FUNCTION__, + urb->status); + return; + default: + dbg ("%s - nonzero urb status received: %d", __FUNCTION__, urb->status); + } + + retval = usb_submit_urb (urb, GFP_ATOMIC); + if (retval) + err ("%s - usb_submit_urb failed with result %d", __FUNCTION__, retval); +} + + +static int +appleir_open (struct input_dev *dev) +{ + struct appleir *appleir = dev->private; + + //appleir->urb->dev = appleir->usbdev; + + if (usb_submit_urb (appleir->urb, GFP_KERNEL)) + return -EIO; + + return 0; +} + +static void +appleir_close (struct input_dev *dev) +{ + struct appleir *appleir = dev->private; + usb_kill_urb (appleir->urb); + del_timer_sync (&appleir->key_up_timer); +} + + + + +static int +appleir_probe (struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *dev = interface_to_usbdev (intf); + struct usb_endpoint_descriptor *endpoint; + struct appleir *appleir = NULL; + struct input_dev *input_dev; + int i; + + appleir = kzalloc (sizeof (struct appleir), GFP_KERNEL); + if (!appleir) + goto fail; + + memset (appleir, 0, sizeof (struct appleir)); + + + appleir->data = + usb_buffer_alloc (dev, URB_SIZE, GFP_KERNEL, &appleir->dma_buf); + if (!appleir->data) + goto fail; + + appleir->urb = usb_alloc_urb (0, GFP_KERNEL); + if (!appleir->urb) + goto fail; + + appleir->usbdev = dev; + + input_dev = input_allocate_device (); + if (!input_dev) + goto fail; + + appleir->dev = input_dev; + + + usb_make_path (dev, appleir->phys, sizeof (appleir->phys)); + strlcpy (appleir->phys, "/input0", sizeof (appleir->phys)); + + input_dev->name = "Apple Mac mini infrared remote control driver"; + input_dev->phys = appleir->phys; + usb_to_input_id (dev, &input_dev->id); + input_dev->cdev.dev = &intf->dev; + input_dev->private = appleir; + + input_dev->evbit[0] = BIT (EV_KEY) | BIT (EV_REP); + input_dev->ledbit[0] = 0; + + for (i = 0; i < MAX_KEYS; i++) + { + set_bit (keymap[i], input_dev->keybit); + } + + clear_bit (0, input_dev->keybit); + + input_dev->open = appleir_open; + input_dev->close = appleir_close; + + endpoint = &intf->cur_altsetting->endpoint[0].desc; + + usb_fill_int_urb (appleir->urb, dev, + usb_rcvintpipe (dev, endpoint->bEndpointAddress), + appleir->data, 8, + appleir_urb, appleir, endpoint->bInterval); + + appleir->urb->transfer_dma = appleir->dma_buf; + appleir->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + usb_set_intfdata (intf, appleir); + + init_timer (&appleir->key_up_timer); + + appleir->key_up_timer.function = key_up_tick; + appleir->key_up_timer.data = (unsigned long) appleir; + + appleir->timer_initted++; + + input_register_device (appleir->dev); + + return 0; + +fail: + + if (appleir) + { + + + if (appleir->data) + usb_buffer_free (dev, URB_SIZE, appleir->data, appleir->dma_buf); + + if (appleir->timer_initted) + del_timer_sync (&appleir->key_up_timer); + + if (appleir->dev) + input_free_device (appleir->dev); + + kfree (appleir); + } + + return -ENOMEM; +} + +static void +appleir_disconnect (struct usb_interface *intf) +{ + struct appleir *appleir = usb_get_intfdata (intf); + + usb_set_intfdata (intf, NULL); + if (appleir) + { + input_unregister_device (appleir->dev); + if (appleir->timer_initted) + del_timer_sync (&appleir->key_up_timer); + usb_kill_urb (appleir->urb); + usb_free_urb (appleir->urb); + usb_buffer_free (interface_to_usbdev (intf), URB_SIZE, appleir->data, + appleir->dma_buf); + kfree (appleir); + } +} + +static struct usb_driver appleir_driver = { + .name = "appleir", + .probe = appleir_probe, + .disconnect = appleir_disconnect, + .id_table = appleir_ids, +}; + +static int __init +appleir_init (void) +{ + int retval; + retval = usb_register (&appleir_driver); + if (retval) + goto out; + info (DRIVER_VERSION ":" DRIVER_DESC); +out: + return retval; +} + +static void __exit +appleir_exit (void) +{ + usb_deregister (&appleir_driver); +} + +module_init (appleir_init); +module_exit (appleir_exit);