Title: [3944] trunk/drivers/input/misc/twi_keypad.c: Fix BUG [#3728] twi_keyboard fails to enter characters in on bf548, Driver restructure/ cleanup, fix other bugs
Revision
3944
Author
hennerich
Date
2007-11-27 07:06:28 -0600 (Tue, 27 Nov 2007)

Log Message

Fix BUG  [#3728] twi_keyboard fails to enter characters in on bf548, Driver restructure/cleanup, fix other bugs

Diffstat

 twi_keypad.c |  456 ++++++++++++++++++++++++++---------------------------------
 1 files changed, 203 insertions(+), 253 deletions(-)

Modified Paths

Diff

Modified: trunk/drivers/input/misc/twi_keypad.c (3943 => 3944)


--- trunk/drivers/input/misc/twi_keypad.c	2007-11-27 08:43:44 UTC (rev 3943)
+++ trunk/drivers/input/misc/twi_keypad.c	2007-11-27 13:06:28 UTC (rev 3944)
@@ -1,23 +1,23 @@
 /************************************************************
 *
-* Copyright (C) 2006, Analog Devices. All Rights Reserved
+* Copyright (C) 2006-2007, Analog Devices. All Rights Reserved
 *
 * FILE twi_keypad.c
 * PROGRAMMER(S): Michael Hennerich (Analog Devices Inc.)
-*				 <[EMAIL PROTECTED]>	
+*				 <[EMAIL PROTECTED]>
 *
-* $Id$
 *
 * DATE OF CREATION: Feb. 24th 2006
 *
 * SYNOPSIS:
 *
-* DESCRIPTION: TWI Driver for an 4x4 Keybaord Matrix connected to 
-*              a PCF8574 I2C IO expander	
-* CAUTION:    
+* DESCRIPTION: TWI Driver for an 4x4 Keybaord Matrix connected to
+*              a PCF8574 I2C IO expander
+* CAUTION:
 **************************************************************
 * MODIFICATION HISTORY:
-* 24.02.2006 11:00  twi_keypad.c Created. (Michael Hennerich)
+* 24.02.2006 twi_keypad.c Created. (Michael Hennerich)
+* 27.11.2007 twi_keypad.c cleanup (Michael Hennerich)
 ************************************************************
 *
 * This program is free software; you can distribute it and/or modify it
@@ -47,83 +47,69 @@
 #include <linux/i2c.h>
 #include <linux/workqueue.h>
 
-MODULE_AUTHOR ("Michael Hennerich <[EMAIL PROTECTED]>");
-MODULE_DESCRIPTION ("TWI Keypad input driver");
-MODULE_LICENSE ("GPL");
+MODULE_AUTHOR("Michael Hennerich <[EMAIL PROTECTED]>");
+MODULE_DESCRIPTION("TWI Keypad input driver");
+MODULE_LICENSE("GPL");
 
 #undef SENDASCII
-#undef	DEBUG
-//#define DEBUG
 
-#ifdef DEBUG
-#define DPRINTK(x...)	printk(x)
-#else
-#define DPRINTK(x...)	do { } while (0)
-#endif
-
 #define BUTTONS 16
 
 #ifdef SENDASCII
 static unsigned char twi_keypad_btncode[BUTTONS + 1] = {
-  [0] =  KEY_RESERVED,
-  [1] =  'd',
-  [2] =  '#',
-  [3] =  '0',
-  [4] =  '*',
-  [5] =  'c',
-  [6] =  '9',
-  [7] =  '8',
-  [8] =  '7',
-  [9] =  'b',
-  [10] =  '6',
-  [11] =  '5',
-  [12] =  '4',
-  [13] =  'a',
-  [14] =  '3',
-  [15] =  '2',
-  [16] =  '1'
+	[0] = KEY_RESERVED,
+	[1] = 'd',
+	[2] = '#',
+	[3] = '0',
+	[4] = '*',
+	[5] = 'c',
+	[6] = '9',
+	[7] = '8',
+	[8] = '7',
+	[9] = 'b',
+	[10] = '6',
+	[11] = '5',
+	[12] = '4',
+	[13] = 'a',
+	[14] = '3',
+	[15] = '2',
+	[16] = '1'
 };
 #else
 static unsigned char twi_keypad_btncode[BUTTONS + 1] = {
-  [0] =  KEY_RESERVED,
-  [1] =  KEY_ENTER,
-  [2] =  KEY_BACKSLASH,
-  [3] =  KEY_0,
-  [4] =  KEY_RIGHTBRACE,
-  [5] =  KEY_C,
-  [6] =  KEY_9,
-  [7] =  KEY_8,
-  [8] =  KEY_7,
-  [9] =  KEY_B,
-  [10] =  KEY_6,
-  [11] =  KEY_5,
-  [12] =  KEY_4,
-  [13] =  KEY_A,
-  [14] =  KEY_3,
-  [15] =  KEY_2,
-  [16] =  KEY_1
+	[0] = KEY_RESERVED,
+	[1] = KEY_ENTER,
+	[2] = KEY_BACKSLASH,
+	[3] = KEY_0,
+	[4] = KEY_RIGHTBRACE,
+	[5] = KEY_C,
+	[6] = KEY_9,
+	[7] = KEY_8,
+	[8] = KEY_7,
+	[9] = KEY_B,
+	[10] = KEY_6,
+	[11] = KEY_5,
+	[12] = KEY_4,
+	[13] = KEY_A,
+	[14] = KEY_3,
+	[15] = KEY_2,
+	[16] = KEY_1
 };
-
 #endif
 
-
-struct TWIKeypad
-{
-
-  unsigned char *btncode;
-  struct input_dev *dev;
-  char name[64];
-  char phys[32];
-  unsigned char laststate;
-  unsigned char statechanged;
-  unsigned long irq_handled;
-  unsigned long events_sended;
-  unsigned long events_processed;
-  struct workqueue_struct *twi_keypad_workqueue;
-  struct work_struct twi_keypad_work;
+struct twikeypad {
+	unsigned char *btncode;
+	struct input_dev *idev;
+	char name[64];
+	char phys[32];
+	unsigned char laststate;
+	unsigned char statechanged;
+	unsigned long irq_handled;
+	unsigned long events_sended;
+	unsigned long events_processed;
+	struct work_struct twi_keypad_work;
 };
 
-
 #define	PCF8574_KP_DRV_NAME		"pcf8574_kp"
 static struct i2c_driver pcf8574_kp_driver;
 static struct i2c_client *pcf8574_kp_client;
@@ -132,249 +118,213 @@
 static unsigned short normal_addr[] = { 0x27, I2C_CLIENT_END };
 
 static struct i2c_client_address_data addr_data = {
-  .normal_i2c = normal_addr,
-  .probe = ignore,
-  .ignore = ignore,
+	.normal_i2c = normal_addr,
+	.probe = ignore,
+	.ignore = ignore,
 };
 
-static irqreturn_t twi_keypad_irq_handler (int irq, void *dev_id);
-static short read_state (struct TWIKeypad *TWIKeypad);
-
-static int
-pcf8574_kp_probe (struct i2c_adapter *adap, int addr, int kind)
+static short read_state(struct twikeypad *lp)
 {
-  struct i2c_client *client;
-  int rc;
+	unsigned char x, y, a, b;
 
-  client = kmalloc (sizeof (struct i2c_client), GFP_KERNEL);
-  if (!client)
-    return -ENOMEM;
+	if (pcf8574_kp_client) {
+		i2c_smbus_write_byte(pcf8574_kp_client, 240);
+		x = 0xF & (~(i2c_smbus_read_byte(pcf8574_kp_client) >> 4));
 
-  memset (client, 0, sizeof (struct i2c_client));
-  strncpy (client->name, PCF8574_KP_DRV_NAME, I2C_NAME_SIZE);
-  client->addr = addr;
-  client->adapter = adap;
-  client->driver = &pcf8574_kp_driver;
+		i2c_smbus_write_byte(pcf8574_kp_client, 15);
+		y = 0xF & (~i2c_smbus_read_byte(pcf8574_kp_client));
 
-  if ((rc = i2c_attach_client (client)) != 0)
-    {
-      kfree (client);
-      printk ("i2c_attach_client fail: %d\n", rc);
-      return rc;
-    }
+		for (a = 0; x > 0; a++)
+			x = x >> 1;
+		for (b = 0; y > 0; b++)
+			y = y >> 1;
 
-  pcf8574_kp_client = client;
+		return (((a - 1) * 4) + b);
+	}
 
-  if(i2c_smbus_write_byte (pcf8574_kp_client, 240)<0) {
-    printk("in keypad probe: write fail\n");
-    return -1;
-  }
-  
-  return 0;
+	return -1;
 }
 
-static int
-pcf8574_kp_attach (struct i2c_adapter *adap)
+static void check_and_notify(struct work_struct *work)
 {
-  if (adap->algo->functionality)
-    return i2c_probe (adap, &addr_data, pcf8574_kp_probe);
-  else
-    return pcf8574_kp_probe (adap, 0x27, 0);
-}
+	struct twikeypad *lp =
+	    container_of(work, struct twikeypad, twi_keypad_work);
+	unsigned char nextstate = read_state(lp);
 
-static int
-pcf8574_kp_detach_client (struct i2c_client *client)
-{
-  int rc;
-  if ((rc = i2c_detach_client (client)) == 0)
-    kfree (i2c_get_clientdata (client));
-  return rc;
-}
+	pr_debug("%s\n", __FUNCTION__);
 
+	lp->statechanged = lp->laststate ^ nextstate;
 
-static struct i2c_driver pcf8574_kp_driver = {
-  .driver = {
-  .name		= PCF8574_KP_DRV_NAME,
-  },
-  .id = 0x65,
-  .attach_adapter = pcf8574_kp_attach,
-  .detach_client = pcf8574_kp_detach_client,
-};
+	if (lp->statechanged) {
+		input_report_key(lp->idev,
+				 nextstate > 17 ? lp->btncode[lp->laststate] :
+				 lp->btncode[nextstate],
+				 nextstate > 17 ? 0 : 1);
 
+		lp->events_sended++;
+	}
+	lp->laststate = nextstate;
+	input_sync(lp->idev);
+	enable_irq(CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
 
-static short
-read_state (struct TWIKeypad *TWIKeypad)
+}
+
+static irqreturn_t twi_keypad_irq_handler(int irq, void *dev_id)
 {
-  unsigned char x, y, a, b;
+	struct twikeypad *lp = dev_id;
 
-  if (pcf8574_kp_client)
-  {
-      i2c_smbus_write_byte (pcf8574_kp_client, 240);
-      x = 0xF & (~(i2c_smbus_read_byte (pcf8574_kp_client) >> 4));
+	pr_debug("%s\n", __FUNCTION__);
+	disable_irq(CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
+	schedule_work(&lp->twi_keypad_work);
 
-      i2c_smbus_write_byte (pcf8574_kp_client, 15);
-      y = 0xF & (~i2c_smbus_read_byte (pcf8574_kp_client));
+	return IRQ_HANDLED;
+}
 
-      for (a = 0; x > 0; a++)
-	x = x >> 1;
-      for (b = 0; y > 0; b++)
-	y = y >> 1;
+static int init_twikeypad(struct i2c_client *client)
+{
+	int i, ret;
+	struct input_dev *idev;
+	struct twikeypad *lp;
 
-      return (((a - 1) * 4) + b);
+	lp = kzalloc(sizeof(struct twikeypad), GFP_KERNEL);
+	idev = input_allocate_device();
 
-    }
+	if (!idev || !lp) {
+		ret = -ENOMEM;
+		goto fail;
+	}
 
-  return -1;
+	if (request_irq(CONFIG_BFIN_TWIKEYPAD_IRQ_PFX, twi_keypad_irq_handler,
+			IRQF_TRIGGER_LOW, PCF8574_KP_DRV_NAME, lp)) {
 
-}
+		printk(KERN_WARNING "twikeypad: IRQ %d is not free.\n",
+		       CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
+		ret = -EBUSY;
+		goto fail;
+	}
 
+	i2c_set_clientdata(client, lp);
 
-static void
-check_and_notify (struct work_struct *work)
-{
-  struct TWIKeypad *TWIKeypad = container_of(work, struct TWIKeypad, twi_keypad_work);
-  unsigned char nextstate = read_state (TWIKeypad);
-  TWIKeypad->statechanged = TWIKeypad->laststate ^ nextstate;
+	lp->idev = idev;
+	lp->btncode = twi_keypad_btncode;
 
-  if (TWIKeypad->statechanged)
-    {
-      input_report_key (TWIKeypad->dev,
-			nextstate >
-			17 ? TWIKeypad->btncode[TWIKeypad->
-						laststate] : TWIKeypad->
-			btncode[nextstate], nextstate > 17 ? 0 : 1);
+	idev->evbit[0] = 0;
 
-      TWIKeypad->events_sended++;
-    }
+	idev->evbit[0] |= BIT(EV_KEY);
+	idev->keycode = lp->btncode;
+	idev->keycodesize = sizeof(twi_keypad_btncode);
+	idev->keycodemax = ARRAY_SIZE(twi_keypad_btncode);
 
-  TWIKeypad->laststate = nextstate;
-  input_sync (TWIKeypad->dev);
+	for (i = 0; i <= BUTTONS; i++)
+		set_bit(lp->btncode[i], idev->keybit);
 
-  enable_irq(CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
 
-}
+	sprintf(lp->name, "BF5xx twikeypad");
+	sprintf(lp->phys, "twikeypad/input0");
 
-static irqreturn_t
-twi_keypad_irq_handler (int irq, void *dev_id)
-{
-  disable_irq(CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
- // queue_work(twi_keypad_workqueue, &twi_keypad_work);
+	idev->name = lp->name;
+	idev->phys = lp->phys;
+	idev->id.bustype = BUS_I2C;
+	idev->id.vendor = 0x0001;
+	idev->id.product = 0x0001;
+	idev->id.version = 0x0100;
 
-  DPRINTK ("twi_keypad_irq_handler \n");
-  return IRQ_HANDLED;
-}
+	input_register_device(lp->idev);
 
-#if 0
-/*
- * sunkbd_event() handles events from the input module.
- */
+	lp->statechanged = 0x0;
 
-static int
-twi_keypad_dev_event (struct input_dev *dev, unsigned int type,
-		      unsigned int code, int value)
-{
-  struct TWIKeypad *TWIKeypad = (struct TWIKeypad *) dev->private;
-  int i;
+	lp->laststate = read_state(lp);
 
+	/* Set up our workqueue. */
+	INIT_WORK(&lp->twi_keypad_work, check_and_notify);
 
-  switch (type)
-    {
+	printk(KERN_INFO "input: %s at %s IRQ %d\n", lp->name, lp->phys,
+				 CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
 
-    case EV_LED:
+	return 0;
 
-    case EV_SND:
+fail:
+	input_free_device(idev);
+	kfree(lp);
+	i2c_set_clientdata(client, NULL);
 
-      break;
-    }
-
-  return 0;
+	return -1;
 }
-#endif
 
-
-static int __init
-twi_keypad_init (void)
+static int pcf8574_kp_probe(struct i2c_adapter *adap, int addr, int kind)
 {
-//  struct TWIKeypad *TWIKeypad = &chip;
-  int i;
+	struct i2c_client *client;
+	int rc;
 
-  struct input_dev *input_dev;
-  struct TWIKeypad *TWIKeypad;
+	client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
+	if (!client)
+		return -ENOMEM;
 
-  i2c_add_driver (&pcf8574_kp_driver);
+	memset(client, 0, sizeof(struct i2c_client));
+	strncpy(client->name, PCF8574_KP_DRV_NAME, I2C_NAME_SIZE);
+	client->addr = addr;
+	client->adapter = adap;
+	client->driver = &pcf8574_kp_driver;
 
-  TWIKeypad = kzalloc(sizeof(struct TWIKeypad), GFP_KERNEL);
+	rc = i2c_attach_client(client);
 
-	input_dev = input_allocate_device();
-	if (!input_dev)
-		goto fail;
-
-	if (request_irq
-	(CONFIG_BFIN_TWIKEYPAD_IRQ_PFX, twi_keypad_irq_handler, IRQF_TRIGGER_LOW, "TWIKeypad",
-	twi_keypad_irq_handler)) {
-		
-		printk (KERN_WARNING "TWIKeypad: IRQ %d is not free.\n", CONFIG_BFIN_TWIKEYPAD_IRQ_PFX);
-	  return -EIO;
+	if (rc != 0) {
+		kfree(client);
+		printk(KERN_WARNING"i2c_attach_client fail: %d\n", rc);
+		return rc;
 	}
-	
-  TWIKeypad->dev = input_dev;
-  TWIKeypad->btncode = twi_keypad_btncode;
 
-  input_dev->evbit[0] = 0;
+	pcf8574_kp_client = client;
 
-  input_dev->evbit[0] |= BIT (EV_KEY);
-  input_dev->keycode = TWIKeypad->btncode;
-  input_dev->keycodesize = sizeof (twi_keypad_btncode);
-  input_dev->keycodemax = ARRAY_SIZE (twi_keypad_btncode);
+	if (i2c_smbus_write_byte(pcf8574_kp_client, 240) < 0) {
+		printk(KERN_WARNING"in keypad probe: write fail\n");
+		return -1;
+	}
 
-  for (i = 0; i <= BUTTONS; i++)
-    {
-      set_bit (TWIKeypad->btncode[i], input_dev->keybit);
-    }
- 
-  sprintf (TWIKeypad->name, "BF5xx TWIKeypad");
-  sprintf (TWIKeypad->phys, "twikeypad/input0");
+	return init_twikeypad(client);
+}
 
-  input_dev->name = TWIKeypad->name;
-  input_dev->phys = TWIKeypad->phys;
-  input_dev->id.bustype = BUS_I2C;
-  input_dev->id.vendor = 0x0001;
-  input_dev->id.product = 0x0001;
-  input_dev->id.version = 0x0100;
+static int pcf8574_kp_attach(struct i2c_adapter *adap)
+{
+	if (adap->algo->functionality)
+		return i2c_probe(adap, &addr_data, pcf8574_kp_probe);
+	else
+		return pcf8574_kp_probe(adap, 0x27, 0);
+}
 
-  input_register_device (TWIKeypad->dev);
+static int pcf8574_kp_detach_client(struct i2c_client *client)
+{
+	struct twikeypad *lp = i2c_get_clientdata(client);
+	int rc;
 
-  printk (KERN_INFO "input: %s at %s\n", TWIKeypad->name,
-	  TWIKeypad->phys);
+	free_irq(CONFIG_BFIN_TWIKEYPAD_IRQ_PFX, lp);
+	input_unregister_device(lp->idev);
+	kfree(lp);
 
-  TWIKeypad->statechanged = 0x0;
+	rc = i2c_detach_client(client);
+	if (rc == 0)
+		kfree(i2c_get_clientdata(client));
+	return rc;
+}
 
-  TWIKeypad->laststate = read_state (TWIKeypad);
-  DPRINTK ("twikeypad: Keypad driver for bf5xx IRQ %d\n", IRQ_PROG_INTA);
+static struct i2c_driver pcf8574_kp_driver = {
+	.driver = {
+		   .name = PCF8574_KP_DRV_NAME,
+		   },
+	.id = 0x65,
+	.attach_adapter = pcf8574_kp_attach,
+	.detach_client = pcf8574_kp_detach_client,
+};
 
-  /* Set up our workqueue. */
-  INIT_WORK(&TWIKeypad->twi_keypad_work, check_and_notify);
-  TWIKeypad->twi_keypad_workqueue = create_singlethread_workqueue("twi_keypad");
-  
-  return 0;
-
-fail:
-  input_free_device(input_dev);
-  i2c_del_driver (&pcf8574_kp_driver);
-  kfree(TWIKeypad);
-
-  return 0;
-
+static int __init twi_keypad_init(void)
+{
+	return i2c_add_driver(&pcf8574_kp_driver);
 }
 
-void __exit
-twi_keypad_exit (void)
+void __exit twi_keypad_exit(void)
 {
-
-  free_irq (CONFIG_BFIN_TWIKEYPAD_IRQ_PFX, twi_keypad_irq_handler);
-  i2c_del_driver (&pcf8574_kp_driver);
-
+	i2c_del_driver(&pcf8574_kp_driver);
 }
 
-module_init (twi_keypad_init);
-module_exit (twi_keypad_exit);
+module_init(twi_keypad_init);
+module_exit(twi_keypad_exit);
_______________________________________________
Linux-kernel-commits mailing list
[email protected]
http://blackfin.uclinux.org/mailman/listinfo/linux-kernel-commits

Reply via email to