All pastes #345631 Raw Edit

Stuff

public text v1 · immutable
·published 2007-02-08 18:05 UTC
rendered paste body
/*
 *  linux/drivers/mfd/ucb1x00-switches.c
 *
 *  Copyright (C) 2007 Bernhard Guillon.
 *
 * 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.
 *
 *  This driver is for the Switches of Siemens SIMpad (CL4,SL4,SLC), T-Sinus-Pad and
 *  Swisscom WP50 devices.
 *
 *  Six switches are routed to GPIO pins on the UCB1300: S3 -- S8.
 *
 *  This driver is based on the 2.4 ucb1x00-switches, the 2.6 ucb1x00-assabet
 *  and the ucb1x00-ts driver.
 *
 */
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/device.h>

#include <asm/dma.h>

#include "ucb1x00.h"

struct ucb1x00_switches {
	struct input_dev	*idev;
	struct ucb1x00		*ucb;
};

static void ucb1x00_dev_irq(int idx, void *id)
{
	//int i;
	static unsigned short int last;
	unsigned short int this;	
	struct ucb1x00_switches *switches = id;
	struct input_dev *idev = switches->idev;
	ucb1x00_enable(switches->ucb);
	
	this=~ucb1x00_io_read(switches->ucb);
	if (this==last) {
		 return;
	}

	last=this;
	printk(KERN_DEBUG "switches->idev->name in ucb1x00_dev_irq: %s \n", switches->idev->name);
	switch (idx) {

	case 0:

		if ((this & (1<<0)) != 0) {
			
			/*
			for (i=0;i<KEY_MAX;i++) {
				input_report_key(idev, i, 1); 
			}
	*/
			input_report_key(idev, 148, 1); /* release */
			
			printk(KERN_DEBUG "Key press Button: 1 \n");
		}
		else {
			input_report_key(idev, 148, 0); /* release */
			printk(KERN_DEBUG "Key release Button: 1 \n");
		}
		break;

	case 1:

		if ((this & (1<<1)) != 0) {
			input_report_key(idev, 149, 1); /* keypress */
			printk(KERN_DEBUG "Key press Button: 2 \n");
		}
		else {
			input_report_key(idev, 149, 0); /* release */
			printk(KERN_DEBUG "Key release Button: 2 \n");
		}
		break;

	case 2:

		if ((this & (1<<2)) != 0) {
			input_report_key(idev, 103, 1); /* keypress */
			printk(KERN_DEBUG "Key press Button: UP \n");
		}
		else {
			input_report_key(idev, 103, 0); /* release */
			printk(KERN_DEBUG "Key release Button: UP \n");
		}
		break;

	case 3:

		if ((this & (1<<3)) != 0) {
			input_report_key(idev, 108, 1); /* keypress */
			printk(KERN_DEBUG "Key press Button: DOWN \n");
		}
		else {
			input_report_key(idev, 108, 0); /* release */
			printk(KERN_DEBUG "Key release Button: DOWN \n");
		}
		break;

	case 4:

		if ((this & (1<<4)) != 0) {
			input_report_key(idev, 105, 1); /* keypress */
			printk(KERN_DEBUG "Key press Button: LEFT \n");
		}
		else {
			input_report_key(idev, 105, 0); /* release */
			printk(KERN_DEBUG "Key release Button: LEFT \n");
		}
		break;

	case 5:

		if ((this & (1<<5)) != 0) {
			input_report_key(idev, 106, 1); /* keypress */
			printk(KERN_DEBUG "Key press Button: RIGHT \n");
		}
		else {
			input_report_key(idev, 106, 0); /* release */
			printk(KERN_DEBUG "Key release Button: RIGHT \n");
		}
		break;

	default:

		printk(KERN_DEBUG "switches-ucb1x00 is BUGGY!!! \n");

	}

	ucb1x00_disable_irq(switches->ucb, UCB_IRQ_TSPX, UCB_FALLING);
	
}

static int ucb1x00_switches_add(struct ucb1x00_dev *dev)
{
	struct ucb1x00_switches *switches;
	struct input_dev *idev;
	int err,i;
	
	switches = kzalloc(sizeof(struct ucb1x00_switches), GFP_KERNEL);
	idev = input_allocate_device();


	if (!switches || !idev) {
		err = -ENOMEM;
		goto fail;
	}

	switches->ucb = dev->ucb;
	

	idev->private    = switches;
	idev->name       = "SIMpad Switches";
	idev->id.product = switches->ucb->id;
	idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);

/* this should be right but is not	
	set_bit(148,    idev->evbit);
	set_bit(149,    idev->evbit);
	set_bit(103,    idev->evbit);
	set_bit(108,    idev->evbit);
	set_bit(105,    idev->evbit);
	set_bit(106,    idev->evbit);
*/
// this is -32 why the f..k?
	set_bit(180,    idev->evbit);
	set_bit(181,    idev->evbit);
	set_bit(135,    idev->evbit);
	set_bit(140,    idev->evbit);
	set_bit(137,    idev->evbit);
	set_bit(138,    idev->evbit);
	

	err = input_register_device(idev);
	if (err)
		goto fail;
	switches->idev = idev;
	printk(KERN_DEBUG "switches->idev->name: %s \n", switches->idev->name);
	dev->priv = switches;
	
	ucb1x00_enable(switches->ucb);

	ucb1x00_io_set_dir(switches->ucb,
			   UCB_IO_0 | UCB_IO_1 | UCB_IO_2 |
			   UCB_IO_3 | UCB_IO_4 | UCB_IO_5, 
			   UCB_IO_8 | UCB_IO_9);

	ucb1x00_disable(switches->ucb);
	
	for (i = 0; i < 6; ++i) {
		ucb1x00_enable_irq(switches->ucb, i, UCB_RISING | UCB_FALLING);
		if (ucb1x00_hook_irq(switches->ucb, i, ucb1x00_dev_irq, switches) < 0) {
			printk(KERN_ERR "unable to hook IRQ for "
			       "UCB1300 SWITCH_%d\n", i);
			return -EBUSY;
		}
	}
		
	return 0;

fail:
	input_free_device(idev);
	kfree(switches);
	return err;

}

static void ucb1x00_switches_remove(struct ucb1x00_dev *dev)
{
	struct ucb1x00_switches *switches = dev->priv;
	input_unregister_device(switches->idev);
	/*
	TODO IMPLEMENT THIS PART:	
	struct ucb1x00_ts *ts = idev->private;

	if (ts->rtask)
		kthread_stop(ts->rtask);

	ucb1x00_enable(ts->ucb);
	ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
	ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
	ucb1x00_disable(ts->ucb);
	*/
	kfree(switches);
}

static struct ucb1x00_driver ucb1x00_switches_driver = {
	.add	= ucb1x00_switches_add,
	.remove	= ucb1x00_switches_remove,
};

static int __init ucb1x00_switches_init(void)
{
	return ucb1x00_register_driver(&ucb1x00_switches_driver);
}

static void __exit ucb1x00_switches_exit(void)
{
	ucb1x00_unregister_driver(&ucb1x00_switches_driver);
}

module_init(ucb1x00_switches_init);
module_exit(ucb1x00_switches_exit);

MODULE_AUTHOR("Bernhard Guillon <Bernhard.Guillon@opensimpad.org>");
MODULE_DESCRIPTION("UCB1x00 Switches driver for Siemens SIMpad");
MODULE_LICENSE("GPL");