diff options
Diffstat (limited to 'drivers/staging/tm6000/tm6000-input.c')
-rw-r--r-- | drivers/staging/tm6000/tm6000-input.c | 287 |
1 files changed, 182 insertions, 105 deletions
diff --git a/drivers/staging/tm6000/tm6000-input.c b/drivers/staging/tm6000/tm6000-input.c index 6022caaa739..21e7da40f04 100644 --- a/drivers/staging/tm6000/tm6000-input.c +++ b/drivers/staging/tm6000/tm6000-input.c @@ -24,8 +24,7 @@ #include <linux/input.h> #include <linux/usb.h> -#include <media/ir-core.h> -#include <media/ir-common.h> +#include <media/rc-core.h> #include "tm6000.h" #include "tm6000-regs.h" @@ -38,6 +37,10 @@ static unsigned int enable_ir = 1; module_param(enable_ir, int, 0644); MODULE_PARM_DESC(enable_ir, "enable ir (default is enable)"); +/* number of 50ms for ON-OFF-ON power led */ +/* show IR activity */ +#define PWLED_OFF 2 + #undef dprintk #define dprintk(fmt, arg...) \ @@ -51,8 +54,7 @@ struct tm6000_ir_poll_result { struct tm6000_IR { struct tm6000_core *dev; - struct ir_input_dev *input; - struct ir_input_state ir; + struct rc_dev *rc; char name[32]; char phys[32]; @@ -61,13 +63,16 @@ struct tm6000_IR { struct delayed_work work; u8 wait:1; u8 key:1; + u8 pwled:1; + u8 pwledcnt; + u16 key_addr; struct urb *int_urb; u8 *urb_data; int (*get_key) (struct tm6000_IR *, struct tm6000_ir_poll_result *); /* IR device properties */ - struct ir_dev_props props; + u64 rc_type; }; @@ -91,26 +96,49 @@ static int tm6000_ir_config(struct tm6000_IR *ir) u8 buf[10]; int rc; - /* hack */ - buf[0] = 0xff; - buf[1] = 0xff; - buf[2] = 0xf2; - buf[3] = 0x2b; - buf[4] = 0x20; - buf[5] = 0x35; - buf[6] = 0x60; - buf[7] = 0x04; - buf[8] = 0xc0; - buf[9] = 0x08; - - rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | - USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a); - msleep(100); - - if (rc < 0) { - printk(KERN_INFO "IR configuration failed"); - return rc; + switch (ir->rc_type) { + case RC_TYPE_NEC: + /* Setup IR decoder for NEC standard 12MHz system clock */ + /* IR_LEADER_CNT = 0.9ms */ + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER1, 0xaa); + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_LEADER0, 0x30); + /* IR_PULSE_CNT = 0.7ms */ + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT1, 0x20); + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_PULSE_CNT0, 0xd0); + /* Remote WAKEUP = enable */ + tm6000_set_reg(dev, TM6010_REQ07_RE5_REMOTE_WAKEUP, 0xfe); + /* IR_WKUP_SEL = Low byte in decoded IR data */ + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_SEL, 0xff); + /* IR_WKU_ADD code */ + tm6000_set_reg(dev, TM6010_REQ07_RD8_IR_WAKEUP_ADD, 0xff); + tm6000_flash_led(dev, 0); + msleep(100); + tm6000_flash_led(dev, 1); + break; + default: + /* hack */ + buf[0] = 0xff; + buf[1] = 0xff; + buf[2] = 0xf2; + buf[3] = 0x2b; + buf[4] = 0x20; + buf[5] = 0x35; + buf[6] = 0x60; + buf[7] = 0x04; + buf[8] = 0xc0; + buf[9] = 0x08; + + rc = tm6000_read_write_usb(dev, USB_DIR_OUT | USB_TYPE_VENDOR | + USB_RECIP_DEVICE, REQ_00_SET_IR_VALUE, 0, 0, buf, 0x0a); + msleep(100); + + if (rc < 0) { + printk(KERN_INFO "IR configuration failed"); + return rc; + } + break; } + return 0; } @@ -145,17 +173,28 @@ static int default_polling_getkey(struct tm6000_IR *ir, return 0; if (&dev->int_in) { - if (ir->ir.ir_type == IR_TYPE_RC5) + switch (ir->rc_type) { + case RC_TYPE_RC5: poll_result->rc_data = ir->urb_data[0]; - else - poll_result->rc_data = ir->urb_data[0] | ir->urb_data[1] << 8; + break; + case RC_TYPE_NEC: + if (ir->urb_data[1] == ((ir->key_addr >> 8) & 0xff)) { + poll_result->rc_data = ir->urb_data[0] + | ir->urb_data[1] << 8; + } + break; + default: + poll_result->rc_data = ir->urb_data[0] + | ir->urb_data[1] << 8; + break; + } } else { tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 0); msleep(10); tm6000_set_reg(dev, REQ_04_EN_DISABLE_MCU_INT, 2, 1); msleep(10); - if (ir->ir.ir_type == IR_TYPE_RC5) { + if (ir->rc_type == RC_TYPE_RC5) { rc = tm6000_read_write_usb(dev, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, REQ_02_GET_IR_CODE, 0, 0, buf, 1); @@ -188,6 +227,7 @@ static int default_polling_getkey(struct tm6000_IR *ir, static void tm6000_ir_handle_key(struct tm6000_IR *ir) { + struct tm6000_core *dev = ir->dev; int result; struct tm6000_ir_poll_result poll_result; @@ -200,12 +240,21 @@ static void tm6000_ir_handle_key(struct tm6000_IR *ir) dprintk("ir->get_key result data=%04x\n", poll_result.rc_data); - if (ir->key) { - ir_input_keydown(ir->input->input_dev, &ir->ir, - (u32)poll_result.rc_data); + if (ir->pwled) { + if (ir->pwledcnt >= PWLED_OFF) { + ir->pwled = 0; + ir->pwledcnt = 0; + tm6000_flash_led(dev, 1); + } else + ir->pwledcnt += 1; + } - ir_input_nokey(ir->input->input_dev, &ir->ir); + if (ir->key) { + rc_keydown(ir->rc, poll_result.rc_data, 0); ir->key = 0; + ir->pwled = 1; + ir->pwledcnt = 0; + tm6000_flash_led(dev, 0); } return; } @@ -218,9 +267,9 @@ static void tm6000_ir_work(struct work_struct *work) schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling)); } -static int tm6000_ir_start(void *priv) +static int tm6000_ir_start(struct rc_dev *rc) { - struct tm6000_IR *ir = priv; + struct tm6000_IR *ir = rc->priv; INIT_DELAYED_WORK(&ir->work, tm6000_ir_work); schedule_delayed_work(&ir->work, 0); @@ -228,30 +277,91 @@ static int tm6000_ir_start(void *priv) return 0; } -static void tm6000_ir_stop(void *priv) +static void tm6000_ir_stop(struct rc_dev *rc) { - struct tm6000_IR *ir = priv; + struct tm6000_IR *ir = rc->priv; cancel_delayed_work_sync(&ir->work); } -int tm6000_ir_change_protocol(void *priv, u64 ir_type) +int tm6000_ir_change_protocol(struct rc_dev *rc, u64 rc_type) { - struct tm6000_IR *ir = priv; + struct tm6000_IR *ir = rc->priv; + + if (!ir) + return 0; + + if ((rc->rc_map.scan) && (rc_type == RC_TYPE_NEC)) + ir->key_addr = ((rc->rc_map.scan[0].scancode >> 8) & 0xffff); ir->get_key = default_polling_getkey; + ir->rc_type = rc_type; tm6000_ir_config(ir); /* TODO */ return 0; } +int tm6000_ir_int_start(struct tm6000_core *dev) +{ + struct tm6000_IR *ir = dev->ir; + int pipe, size; + int err = -ENOMEM; + + + if (!ir) + return -ENODEV; + + ir->int_urb = usb_alloc_urb(0, GFP_KERNEL); + + pipe = usb_rcvintpipe(dev->udev, + dev->int_in.endp->desc.bEndpointAddress + & USB_ENDPOINT_NUMBER_MASK); + + size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe)); + dprintk("IR max size: %d\n", size); + + ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL); + if (ir->int_urb->transfer_buffer == NULL) { + usb_free_urb(ir->int_urb); + return err; + } + dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval); + usb_fill_int_urb(ir->int_urb, dev->udev, pipe, + ir->int_urb->transfer_buffer, size, + tm6000_ir_urb_received, dev, + dev->int_in.endp->desc.bInterval); + err = usb_submit_urb(ir->int_urb, GFP_KERNEL); + if (err) { + kfree(ir->int_urb->transfer_buffer); + usb_free_urb(ir->int_urb); + return err; + } + ir->urb_data = kzalloc(size, GFP_KERNEL); + + return 0; +} + +void tm6000_ir_int_stop(struct tm6000_core *dev) +{ + struct tm6000_IR *ir = dev->ir; + + if (!ir) + return; + + usb_kill_urb(ir->int_urb); + kfree(ir->int_urb->transfer_buffer); + usb_free_urb(ir->int_urb); + ir->int_urb = NULL; + kfree(ir->urb_data); + ir->urb_data = NULL; +} + int tm6000_ir_init(struct tm6000_core *dev) { struct tm6000_IR *ir; - struct ir_input_dev *ir_input_dev; + struct rc_dev *rc; int err = -ENOMEM; - int pipe, size, rc; if (!enable_ir) return -ENODEV; @@ -263,26 +373,27 @@ int tm6000_ir_init(struct tm6000_core *dev) return 0; ir = kzalloc(sizeof(*ir), GFP_KERNEL); - ir_input_dev = kzalloc(sizeof(*ir_input_dev), GFP_KERNEL); - ir_input_dev->input_dev = input_allocate_device(); - if (!ir || !ir_input_dev || !ir_input_dev->input_dev) - goto err_out_free; + rc = rc_allocate_device(); + if (!ir | !rc) + goto out; /* record handles to ourself */ ir->dev = dev; dev->ir = ir; - - ir->input = ir_input_dev; + ir->rc = rc; /* input einrichten */ - ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC; - ir->props.priv = ir; - ir->props.change_protocol = tm6000_ir_change_protocol; - ir->props.open = tm6000_ir_start; - ir->props.close = tm6000_ir_stop; - ir->props.driver_type = RC_DRIVER_SCANCODE; + rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC; + rc->priv = ir; + rc->change_protocol = tm6000_ir_change_protocol; + rc->open = tm6000_ir_start; + rc->close = tm6000_ir_stop; + rc->driver_type = RC_DRIVER_SCANCODE; ir->polling = 50; + ir->pwled = 0; + ir->pwledcnt = 0; + snprintf(ir->name, sizeof(ir->name), "tm5600/60x0 IR (%s)", dev->name); @@ -290,64 +401,37 @@ int tm6000_ir_init(struct tm6000_core *dev) usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); - tm6000_ir_change_protocol(ir, IR_TYPE_UNKNOWN); - err = ir_input_init(ir_input_dev->input_dev, &ir->ir, IR_TYPE_OTHER); - if (err < 0) - goto err_out_free; - - ir_input_dev->input_dev->name = ir->name; - ir_input_dev->input_dev->phys = ir->phys; - ir_input_dev->input_dev->id.bustype = BUS_USB; - ir_input_dev->input_dev->id.version = 1; - ir_input_dev->input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); - ir_input_dev->input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct); + tm6000_ir_change_protocol(rc, RC_TYPE_UNKNOWN); - ir_input_dev->input_dev->dev.parent = &dev->udev->dev; + rc->input_name = ir->name; + rc->input_phys = ir->phys; + rc->input_id.bustype = BUS_USB; + rc->input_id.version = 1; + rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); + rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); + rc->map_name = dev->ir_codes; + rc->driver_name = "tm6000"; + rc->dev.parent = &dev->udev->dev; if (&dev->int_in) { dprintk("IR over int\n"); - ir->int_urb = usb_alloc_urb(0, GFP_KERNEL); + err = tm6000_ir_int_start(dev); - pipe = usb_rcvintpipe(dev->udev, - dev->int_in.endp->desc.bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK); - - size = usb_maxpacket(dev->udev, pipe, usb_pipeout(pipe)); - dprintk("IR max size: %d\n", size); - - ir->int_urb->transfer_buffer = kzalloc(size, GFP_KERNEL); - if (ir->int_urb->transfer_buffer == NULL) { - usb_free_urb(ir->int_urb); - goto err_out_stop; - } - dprintk("int interval: %d\n", dev->int_in.endp->desc.bInterval); - usb_fill_int_urb(ir->int_urb, dev->udev, pipe, - ir->int_urb->transfer_buffer, size, - tm6000_ir_urb_received, dev, - dev->int_in.endp->desc.bInterval); - rc = usb_submit_urb(ir->int_urb, GFP_KERNEL); - if (rc) { - kfree(ir->int_urb->transfer_buffer); - usb_free_urb(ir->int_urb); - err = rc; - goto err_out_stop; - } - ir->urb_data = kzalloc(size, GFP_KERNEL); + if (err) + goto out; } /* ir register */ - err = ir_input_register(ir->input->input_dev, dev->ir_codes, - &ir->props, "tm6000"); + err = rc_register_device(rc); if (err) - goto err_out_stop; + goto out; return 0; -err_out_stop: +out: dev->ir = NULL; -err_out_free: - kfree(ir_input_dev); + rc_free_device(rc); kfree(ir); return err; } @@ -361,19 +445,12 @@ int tm6000_ir_fini(struct tm6000_core *dev) if (!ir) return 0; - ir_input_unregister(ir->input->input_dev); + rc_unregister_device(ir->rc); if (ir->int_urb) { - usb_kill_urb(ir->int_urb); - kfree(ir->int_urb->transfer_buffer); - usb_free_urb(ir->int_urb); - ir->int_urb = NULL; - kfree(ir->urb_data); - ir->urb_data = NULL; + tm6000_ir_int_stop(dev); } - kfree(ir->input); - ir->input = NULL; kfree(ir); dev->ir = NULL; |