OSDN Git Service

Added fingerprint reader driver, fixed kernel and config
authorfonix232 <fonix232@gmail.com>
Fri, 22 Apr 2011 10:57:35 +0000 (12:57 +0200)
committerfonix232 <fonix232@gmail.com>
Fri, 22 Apr 2011 10:57:35 +0000 (12:57 +0200)
BoardConfig.mk
README
fingerprint/ChangeLog [new file with mode: 0644]
fingerprint/Makefile [new file with mode: 0644]
fingerprint/aes2501.c [new file with mode: 0644]
fingerprint/aes2501.h [new file with mode: 0644]
fingerprint/aes2501_regs.h [new file with mode: 0644]
fingerprint/usertest.c [new file with mode: 0644]
keylayout/m1400_keyboard.kl
m1400_defconfig
ts.env

index 937e31d..9770d73 100644 (file)
@@ -1,4 +1,4 @@
-TARGET_HAS_THIRD_PARTY_APPS := true
+#TARGET_HAS_THIRD_PARTY_APPS := true
 
 BOARD_WPA_SUPPLICANT_DRIVER:=AWEXT
 
@@ -11,8 +11,8 @@ BOARD_USES_I915C := true
 BOARD_USES_WACOMINPUT := true
 
 #BOARD_USES_GENERIC_AUDIO := false
-#BOARD_USES_ALSA_AUDIO := true
-#BUILD_WITH_ALSA_UTILS := true
+BOARD_USES_ALSA_AUDIO := true
+BUILD_WITH_ALSA_UTILS := true
 
 #USE_CAMERA_STUB := false
 #BOARD_CAMERA_LIBRARIES := libcamera
diff --git a/README b/README
index e69de29..1a9744d 100644 (file)
--- a/README
+++ b/README
@@ -0,0 +1,9 @@
+Device tree for the Motion M1400
+
+Target: Android 2.2 (2.3 next)
+
+Status:
+- Basic device config done
+- Added fingerprint reader driver (needs an app though to work)
+- M1400 keylayout (may not be proper, I'm unable to get some key scancodes)
+- M1400 settings
\ No newline at end of file
diff --git a/fingerprint/ChangeLog b/fingerprint/ChangeLog
new file mode 100644 (file)
index 0000000..1cbd234
--- /dev/null
@@ -0,0 +1,102 @@
+2008-01-14  Cyrille Bagard <nocbos@gmail.com>
+
+       * aes2501.c:
+       Apply a patch made by Herton Ronaldo Krzesinski: if the device is not
+       present, the _dev structure isn't initialized and the system gets an
+       oops on exit.
+
+2007-11-05  Cyrille Bagard <nocbos@gmail.com>
+
+       * aes2501.c:
+       Apply Vasily Khoruzhick's new patch: rewrite image processing functions.
+       Thus, there should be no more significant common points with aes2501-wy.
+
+2007-11-05  Cyrille Bagard <nocbos@gmail.com>
+
+       * aes2501.c:
+       In order to respect the license of aes2501-wy, on which this driver is
+       based, begin to rewrite some functions. Thus, better handle histograms.
+       One more strip is often processed, but that is more logical like this.
+
+       * aes2501_regs.h:
+       Enumerate all used registers for convenience.
+
+2007-11-03  Cyrille Bagard <nocbos@gmail.com>
+
+       * aes2501.c:
+       Clean the code. Take care of signals when processes are awaking.
+       Apply Vasily Khoruzhick's new patch: autodetect picture reversing needs
+       and fix kernel oops in case of module removal.
+
+       * Makefile:
+       Remove hidden files and clean the rules. KERNELDIR has to be overrided
+       from the sheel if needed now.
+
+2007-10-29  Cyrille Bagard <nocbos@gmail.com>
+
+       * aes2501.c:
+       Apply Vasily Khoruzhick's patch and thus increase the resulting pictures
+       quality. Many thanks to him !
+
+       * Makefile:
+       Add two new rules: usertest and clean.
+
+       * usertest.c:
+       Initial commit.
+
+2007-08-27  Cyrille Bagard <nocbos@gmail.com>
+
+       * aes2501.c:
+       Make INIT_WORK macro working with 2.6.20+ kernels. Many thanks to
+       Miguel Gea Milvaques <xerakko> for the patch !
+
+2007-06-13  Cyrille Bagard <nocbos@gmail.com>
+
+       * aes2501.c:
+       * aes2501_regs.h:
+       Complete translation of all binary communications using well documented
+       registers and values (as often as possible).
+
+2007-06-13  Cyrille Bagard <nocbos@gmail.com>
+
+       * aes2501.c:
+       Increase communication speed by buffering bulk out. Output data
+       need to be flushed at the end now.
+
+2007-06-13  Cyrille Bagard <nocbos@gmail.com>
+
+       * aes2501.c:
+       * aes2501_regs.h:
+       Translate binary data used in finger detection. Some register values
+       still need to be understood. Note: some hex values are reserved bits
+       in registers.
+
+2007-06-12  Cyrille Bagard <nocbos@gmail.com>
+
+       * aes2501.c:
+       Begin the binary translation: the "standby" function now uses understood
+       instructions and prints debug status information if needed. CTRL2 register
+       value needs to be checked.
+
+       * aes2501_regs.h:
+       Define the interesting hex values for the following registers:
+       CTRL2, STAT, TREGC and TREGD.
+
+2007-06-12  Cyrille Bagard <nocbos@gmail.com>
+
+       * aes2501.c:
+       Clean the driver a little bit by removing old piece of code to handle
+       a character device in the old way.
+
+2007-06-12  Cyrille Bagard <nocbos@gmail.com>
+
+       * aes2501.c:
+       Use an own work queue. Scanning now starts with the AES2501_IOC_TEST
+       ioctl command. Reading the /dev entry blocks until data is available.
+
+2007-06-12  Cyrille Bagard <nocbos@gmail.com>
+
+       * aes2501.c:
+       * aes2501.h:
+       * Makefile:
+       Initial [crappy] commit.
diff --git a/fingerprint/Makefile b/fingerprint/Makefile
new file mode 100644 (file)
index 0000000..b6fb285
--- /dev/null
@@ -0,0 +1,19 @@
+
+obj-m := aes2501.o
+
+KERNELDIR      ?= /lib/modules/$(shell uname -r)/build
+
+PWD                    := $(shell pwd)
+
+all: usertest
+       $(MAKE) -C $(KERNELDIR) M=$(PWD)
+
+usertest:
+       gcc -I. -o usertest usertest.c
+
+clean:
+       rm -f *.o *~ aes2501.ko aes2501.mod.c Module.symvers usertest
+       rm -rf .tmp_versions
+       rm -f .*.cmd
+
+
diff --git a/fingerprint/aes2501.c b/fingerprint/aes2501.c
new file mode 100644 (file)
index 0000000..798acd6
--- /dev/null
@@ -0,0 +1,1630 @@
+
+/*
+ * aes2501.c -- AuthenTec AES2501 Fingerprint Sensor Driver for Linux
+ *
+ * Maintainer: Cyrille Bagard <nocbos@gmail.com>
+ *
+ * Copyright (C) 2007 Cyrille Bagard
+ *
+ * This file is part of the AES2501 driver.
+ *
+ * the AES2501 driver 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.
+ *
+ * the AES2501 driver 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 the AES2501 driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/usb.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+#include <linux/version.h>
+#include <linux/vmalloc.h>
+#include <asm/uaccess.h>
+
+
+#include "aes2501.h"
+#include "aes2501_regs.h"
+
+
+static int major = 0;
+
+module_param(major, int, 0);
+MODULE_PARM_DESC(major, "major number");
+
+
+//#define DEBUG
+
+
+#define PRINTK_INFO(fmt, arg...) printk(KERN_INFO "aes2501: " fmt, ## arg)
+
+#define PRINTK_CRIT(fmt, arg...) printk(KERN_CRIT "aes2501: " fmt, ## arg)
+
+#define PRINTK_DBG(fmt, arg...) printk(KERN_DEBUG "aes2501: " fmt, ## arg)
+
+
+static struct workqueue_struct *comm_queue;
+
+
+static char *finger_print = NULL;
+static size_t finger_print_len;
+
+
+
+static DECLARE_WAIT_QUEUE_HEAD(wq);
+static int flag = 0;
+
+
+
+struct usb_aes2501 *_dev;
+
+
+
+
+
+
+struct aes2501 {
+
+       struct usb_device *udev;
+
+       int temp;
+
+       unsigned char *int_in_buffer;
+       struct urb *int_in_urb;
+
+};
+
+
+/*
+#define VENDOR_ID   0x08f7
+#define PRODUCT_ID  0x0002
+*/
+
+#define VENDOR_ID   0x08ff
+#define PRODUCT_ID  0x2580
+
+
+/* Table of devices that work with this driver */
+
+static struct usb_device_id id_table [] = {
+    { USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
+    { }
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+
+/* Get a minor range for your devices from the usb maintainer */
+#define USB_AES2501_MINOR_BASE 192
+
+
+
+#define WRITES_IN_FLIGHT       8       /* ??? */
+
+
+
+enum AES2501_Status {
+
+       AESS_INIT_DONE,
+       AESS_IS_SCANNING,
+
+       AESS_COUNT
+
+};
+
+
+#define BULK_OUT_BUFFER_SIZE 32
+
+
+/* Read a register value from a dump sent by the device. */
+static int read_register_value(const uint8_t *, Aes2501Registers);
+
+/* Tells if a finger motion is still detected. */
+static int sum_histogram_values(const uint8_t *, uint8_t);
+
+
+/* Structure to hold all device specific stuff */
+struct usb_aes2501 {
+
+       struct usb_device       *udev;                                  /* the usb device for this device */
+       struct usb_interface    *interface;                             /* the interface for this device */
+       struct semaphore        limit_sem;                              /* limiting the number of writes in progress */
+       unsigned char           *bulk_in_buffer;                        /* the buffer to receive data */
+       size_t                  bulk_in_size;                           /* the size of the receive buffer */
+       __u8                    bulk_in_endpointAddr;                   /* the address of the bulk in endpoint */
+       uint8_t                 bulk_out_buffer[BULK_OUT_BUFFER_SIZE];  /* the buffer to send data (32 / 8 = 4) */
+       size_t                  bulk_out_buffer_used;                   /* the quantity of buffered data to send */
+       __u8                    bulk_out_endpointAddr;                  /* the address of the bulk out endpoint */
+       struct kref             kref;
+       struct mutex            io_mutex;                               /* synchronize I/O with disconnect */
+
+       DECLARE_BITMAP(status, AESS_COUNT);                             /* Information about what has been set / is running */
+
+       struct work_struct scan_work;
+       uint8_t                 stop_scan;                              /* Flag to stop finger detecting during module removal */
+};
+
+
+#define to_aes2501_dev(r) container_of(r, struct usb_aes2501, kref)
+
+static struct usb_driver aes2501_driver;
+
+static void aes2501_delete(struct kref *kref)
+{
+       struct usb_aes2501 *dev;
+
+       dev = to_aes2501_dev(kref);
+
+       usb_put_dev(dev->udev);
+       kfree(dev->bulk_in_buffer);
+       kfree(dev);
+
+}
+
+
+static int aes2501_open(struct inode *inode, struct file *file);
+/*
+struct usb_aes2501 *_dev;
+static int aes2501_open(struct inode *inode, struct file *file)
+{
+       printk(KERN_INFO "Plop !\n");
+
+
+
+       return 0;
+}
+*/
+
+static ssize_t aes2501_read(struct file *file, char *buffer, size_t count, loff_t *ppos)
+{
+       int read_len;
+
+       //printk(KERN_INFO "aes2501_read ! got %d -> need (%d ; %d)\n", finger_print_len, *ppos, count);
+
+       if (flag == 0)
+               printk(KERN_INFO "Process %i (%s) is going to sleep\n", current->pid, current->comm);
+
+       wait_event_interruptible(wq, flag == 1);
+
+       if (signal_pending(current))
+               return -ERESTARTSYS;
+
+       if (finger_print_len == 0)
+               return -ENODATA;
+
+       if (unlikely((*ppos < 0) || (loff_t)(*ppos + count) < 0))
+               return -EINVAL;
+
+       if (*ppos + count > finger_print_len)
+               read_len = finger_print_len - *ppos;
+       else read_len = count;
+
+       if (read_len > 0)
+       {
+               if (!access_ok(VERIFY_WRITE, buffer, read_len))
+                       return -EFAULT;
+
+               read_len -= copy_to_user(buffer, finger_print + *ppos, read_len);
+               *ppos += read_len;
+
+       }
+
+       /* !!!! */
+       else flag = 0;
+
+       return read_len;
+
+}
+
+
+
+static int detect_finger_on_aes2501(struct usb_aes2501 *dev);
+
+static void do_scanning(struct work_struct *work);
+
+
+// ioctl - I/O control
+static int aes2501_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct usb_aes2501 *dev;
+       int retval;
+
+       dev = _dev;
+
+
+       printk(KERN_INFO "Get IOCtl :: cmd = %d vs %d\n", cmd, (AES2501_IOC_TEST));
+
+       switch (cmd) {
+
+               case AES2501_IOC_TEST:
+
+#if defined(_arch_um__) || !(LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20))
+                       INIT_WORK(&dev->scan_work, do_scanning);
+#else
+                       INIT_WORK(&dev->scan_work, do_scanning, NULL);
+#endif
+
+                       retval = queue_work(comm_queue, &dev->scan_work);
+
+
+       }
+
+
+
+       return 0;
+
+
+#if 0
+       int retval = 0;
+       switch ( cmd ) {
+               case CASE1:/* for writing data to arg */
+                       if (copy_from_user(&data, (int *)arg, sizeof(int)))
+                       return -EFAULT;
+                       break;
+               case CASE2:/* for reading data from arg */
+                       if (copy_to_user((int *)arg, &data, sizeof(int)))
+                       return -EFAULT;
+                       break;
+               default:
+                       retval = -EINVAL;
+       }
+       return retval;
+#endif
+}
+
+
+
+static const struct file_operations aes2501_fops = {
+       .owner =        THIS_MODULE,
+       .read =         aes2501_read,/*
+       .write =        aes2501_write,*/
+       .open =         aes2501_open,/*
+       .release =      skel_release,*/
+       .ioctl =        aes2501_ioctl
+};
+
+
+
+/*
+static int send_data_to_aes2501(struct usb_aes2501 *dev, unsigned char *buffer, int len)
+{
+#ifdef DEBUG
+       int i;
+#endif
+       int bytes_written;
+       int ret;
+
+#ifdef DEBUG
+       printk(KERN_INFO "\n:: OUT :: len=%d\n", len);
+
+       for (i = 0; i < len; i++)
+       {
+               if (i > 0 && i % 16 == 0)
+                       printk("\n");
+               if (i % 16 == 0)
+                       printk(KERN_INFO "  %05x: ", i);
+
+               if (i % 8 == 0)
+                       printk(" ");
+
+               printk("%02x ", buffer[i]);
+
+       }
+
+       printk("\n");
+#endif
+
+       ret = usb_bulk_msg(dev->udev,
+                          usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
+                          buffer,
+                          len,
+                          &bytes_written, 4000);
+
+       if (ret < 0)
+               PRINTK_CRIT("error while sending data: %d\n", ret);
+
+       if (bytes_written != len)
+               printk(KERN_INFO "did not write all !  %d vs %d\n", bytes_written, len);
+
+       return ret;
+
+}
+*/
+
+static int flush_aes2501_bulk_out(struct usb_aes2501 *dev)
+{
+       int ret;
+       int bytes_written;
+
+       ret = 0;
+
+       if (dev->bulk_out_buffer_used > 0) {
+
+               ret = usb_bulk_msg(dev->udev,
+                                  usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
+                                  dev->bulk_out_buffer,
+                                  dev->bulk_out_buffer_used,
+                                  &bytes_written, 4000);
+
+               if (ret < 0)
+                       PRINTK_CRIT("error while sending data: %d\n", ret);
+
+               else if (bytes_written != dev->bulk_out_buffer_used)
+               {
+                       printk(KERN_INFO "did not write all !  %d vs %d\n", bytes_written, dev->bulk_out_buffer_used);
+                       /*ret = ... */
+               }
+
+               dev->bulk_out_buffer_used = 0;
+
+       }
+
+       return ret;
+
+}
+
+
+static int write_aes2501_register(struct usb_aes2501 *dev, uint8_t reg, uint8_t data)
+{
+       int ret;
+
+       if (dev->bulk_out_buffer_used == BULK_OUT_BUFFER_SIZE)
+               ret = flush_aes2501_bulk_out(dev);
+       else
+               ret = 0;
+
+       dev->bulk_out_buffer[dev->bulk_out_buffer_used++] = reg;
+       dev->bulk_out_buffer[dev->bulk_out_buffer_used++] = data;
+
+       return ret;
+
+}
+
+
+static int recv_data_to_aes2501(struct usb_aes2501 *dev, unsigned char *buffer, int len)
+{
+       int bytes_read;
+       int ret;
+#ifdef DEBUG
+       int i;
+#endif
+
+       ret = usb_bulk_msg(dev->udev,
+                          usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),
+                          buffer,
+                          len,
+                          &bytes_read, 4000);
+
+       if (ret < 0)
+               PRINTK_CRIT("error while sending data: %d\n", ret);
+
+       if (bytes_read != len)
+               printk(KERN_INFO "did not read all !  %d vs %d\n", bytes_read, len);
+
+#ifdef DEBUG
+       if (ret == 0)
+       {
+               printk(KERN_INFO "\n:: IN :: len=%d\n", len);
+
+               for (i = 0; i < len; i++)
+               {
+                       if (i > 0 && i % 16 == 0)
+                               printk("\n");
+                       if (i % 16 == 0)
+                               printk(KERN_INFO "  %05x: ", i);
+
+                       if (i % 8 == 0)
+                               printk(" ");
+
+                       printk("%02x ", buffer[i]);
+
+               }
+
+               printk("\n");
+
+       }
+#endif
+
+       return ret;
+
+}
+
+
+
+static int standby_aes2501(struct usb_aes2501 *dev)
+{
+
+       //unsigned char cmd[] = "\xac\x01\xad\x1a\x81\x02";
+
+
+       unsigned char buffer[4];
+
+
+
+
+       printk(KERN_INFO ">> Standby aes2501 !\n");
+
+
+       //msleep(800);
+
+       write_aes2501_register(dev, AES2501_REG_TREGC, AES2501_TREGC_ENABLE);
+       write_aes2501_register(dev, AES2501_REG_TREGD, 0x1a);
+
+       flush_aes2501_bulk_out(dev);
+
+       /**
+        * TODO:
+        * - lire ici les deux octets.
+        * - voir pour inverser les commandes.
+        */
+
+       write_aes2501_register(dev, AES2501_REG_CTRL2, 0x02/* AES2501_CTRL2_READ_REGS ??? */);
+       flush_aes2501_bulk_out(dev);
+
+       //send_data_to_aes2501(dev, cmd, 6);
+       recv_data_to_aes2501(dev, buffer, 2);
+
+
+
+       printk(KERN_INFO "  %02x %02x\n", buffer[0], buffer[1]);
+
+
+       if ((buffer[1] & AES2501_STAT_SCAN) == buffer[1])
+       {
+               PRINTK_DBG("scan state: ");
+
+               switch (buffer[1])
+               {
+                       case STATE_WAITING_FOR_FINGER:
+                               printk("'Waiting for finger'\n");
+                               break;
+                       case STATE_FINGER_SETTLING_DELAY:
+                               printk("'In Finger settling delay'\n");
+                               break;
+                       case STATE_POWER_UP_DELAY:
+                               printk("'In power up delay'\n");
+                               break;
+                       case STATE_WAITING_TO_START_SCAN:
+                               printk("'Waiting to start image scan'\n");
+                               break;
+                       case STATE_PRELOADING_SUBARRAY_0:
+                               printk("'Pre-loading subarray 0'\n");
+                               break;
+                       case STATE_SETUP_FOR_ROW_ADVANCE:
+                               printk("'Setup for row advance'\n");
+                               break;
+                       case STATE_WAITING_FOR_ROW_ADVANCE:
+                               printk("'Waiting for row advance'\n");
+                               break;
+                       case STATE_PRELOADING_COL_0:
+                               printk("'Pre-loading column 0'\n");
+                               break;
+                       case STATE_SETUP_FOR_COL_ADVANCE:
+                               printk("'Setup for column advance'\n");
+                               break;
+                       case STATE_WAITING_FOR_COL_ADVANCE:
+                               printk("'Waiting for column advance'\n");
+                               break;
+                       case STATE_WAITING_FOR_SCAN_START:
+                               printk("'Waiting for scan start'\n");
+                               break;
+                       case STATE_WAITING_FOR_SCAN_END:
+                               printk("'Waiting for scan end'\n");
+                               break;
+                       case STATE_WAITING_FOR_ROW_SETUP:
+                               printk("'Waiting for row setup'\n");
+                               break;
+                       case STATE_WAITING_FOR_COL_TIME:
+                               printk("'Waiting for one column time (depends on scan rate)'\n");
+                               break;
+                       case STATE_WAITING_FOR_QUEUED_DATA:
+                               printk("'Waiting for queued data transmission to be completed'\n");
+                               break;
+                       case STATE_WAIT_FOR_128_US:
+                               printk("'Wait for 128 us'\n");
+                               break;
+                       default:
+                               printk("none (?!)\n");
+                               break;
+
+               }
+
+       }
+
+       if (buffer[1] & AES2501_STAT_ERROR)
+               PRINTK_DBG("got serial interface framing error\n");
+
+       if (buffer[1] & AES2501_STAT_PAUSED)
+               PRINTK_DBG("scan was paused due to input buffer full\n");
+
+       if (buffer[1] & AES2501_STAT_RESET)
+               PRINTK_DBG("master reset input has been asserted\n");
+
+
+
+
+       return 0;
+
+
+}
+
+
+
+
+static int setup_aes2501(struct usb_aes2501 *dev)
+{
+       //unsigned char patch_msg[] = "\x80\x01";
+
+
+       //unsigned char cmd[] = "\x80\x01\x81\x02";
+
+       //unsigned char cmd_00[] = "\xb0\x27";
+       //unsigned char cmd_01[] = "\x80\x01\x82\x40";
+       //unsigned char cmd_02[] = "\xff\x00";
+       //unsigned char cmd_03[] = "\x80\x01\x82\x40\x83\x00\x88\x02\x89\x10\x8a\x05\x8c\x00\x8e\x13\x91\x44\x92\x34\x95\x16\x96\x16\x97\x18\xa1\x70\xa2\x02\xa7\x00\xac\x01\xad\x1a\x80\x04\x81\x04\xb4\x00";/*42*/
+       //unsigned char cmd_04[] = "\x80\x01\x82\x40";
+
+       //unsigned char cmd2[] = "\x80\x01\xa8\x41\x82\x42\x83\x53\x80\x04\x81\x02";/*12*/
+
+       //unsigned char cmd3_00[] = "\xff\x00";
+       //unsigned char cmd3_01[] = "\x80\x01\xa8\x41\x82\x42\x83\x53\x80\x04\x81\x02";/*12*/
+
+       //unsigned char cmd4[] = "\x80\x01\x82\x40\xb0\x27\x94\x0a\x80\x04\x83\x45\xa8\x41";/*14*/
+
+       //unsigned char cmd5_00[] = "\xb0\x27";
+       //unsigned char cmd5_01[] = "\x80\x01\x82\x40";
+       //unsigned char cmd5_02[] = "\xff\x00";
+       //unsigned char cmd5_03[] = "\x80\x02";
+       //unsigned char cmd5_04[] = "\x81\x02";
+
+
+       int i;
+
+       unsigned char buffer[128];
+
+
+       /* To be sure the device will respond */
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       //send_data_to_aes2501(dev, patch_msg, 2);
+       flush_aes2501_bulk_out(dev);/* ... */
+
+       printk(KERN_INFO ">> Setting up aes2501 !\n");
+
+       /* Part 1 */
+
+       printk(KERN_INFO " -- part 1 --\n");
+
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_READ_REGS);
+       flush_aes2501_bulk_out(dev);
+
+       //send_data_to_aes2501(dev, cmd, 4);
+       recv_data_to_aes2501(dev, buffer, 126);
+
+
+
+       //send_data_to_aes2501(dev, cmd_00, 2);
+
+       write_aes2501_register(dev, 0xb0, 0x27);/* Reserved */
+
+
+
+       //send_data_to_aes2501(dev, cmd_01, 4);
+
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */
+
+       for (i = 0; i <= 10; i++)
+       {
+               //msleep(200);
+               //send_data_to_aes2501(dev, cmd_02, 2);
+               write_aes2501_register(dev, 0xff, 0x00);/* Reserved */
+       }
+
+       //msleep(100);
+
+
+       //send_data_to_aes2501(dev, cmd_03, 42);
+
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */
+       write_aes2501_register(dev, AES2501_REG_DETCTRL, AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS);
+       write_aes2501_register(dev, AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US);
+       write_aes2501_register(dev, AES2501_REG_MEASDRV, AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE);
+       write_aes2501_register(dev, AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M);
+       write_aes2501_register(dev, AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE);/* Default */
+       write_aes2501_register(dev, AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE);
+       write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X);
+       write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x44);
+       write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x34);
+       write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x16);
+       write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x16);
+       write_aes2501_register(dev, AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08);/* ??? */
+       write_aes2501_register(dev, AES2501_REG_TREG1, 0x70);/* Reserved + 0xXX */
+       write_aes2501_register(dev, 0xa2, 0x02);/* Reserved */
+       write_aes2501_register(dev, 0xa7, 0x00);/* Reserved */
+       write_aes2501_register(dev, AES2501_REG_TREGC, AES2501_TREGC_ENABLE);
+       write_aes2501_register(dev, AES2501_REG_TREGD, 0x1a);
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE);
+       write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT);
+       write_aes2501_register(dev, AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE);
+
+
+       flush_aes2501_bulk_out(dev);
+
+       recv_data_to_aes2501(dev, buffer, 20);
+
+
+
+       //send_data_to_aes2501(dev, cmd_04, 4);
+
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */
+
+       /* Part 2 */
+
+       printk(KERN_INFO " -- part 2 --\n");
+
+       //msleep(100);
+
+       //send_data_to_aes2501(dev, cmd2, 12);
+
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_AUTOCALOFFSET, 0x41);
+       write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x42);/* ??? */
+       write_aes2501_register(dev, AES2501_REG_DETCTRL, 0x53);/* Cumul ??? */
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE);
+       write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_READ_REGS);
+
+
+
+
+       flush_aes2501_bulk_out(dev);
+
+
+       recv_data_to_aes2501(dev, buffer, 126);
+
+       /* Part 3 */
+
+       printk(KERN_INFO " -- part 3 --\n");
+
+       i = 0;
+
+       printk(KERN_INFO " reg 0xaf = 0x%x\n", buffer[0x5f]);
+       while (buffer[0x5f] == 0x6b)
+       {
+               //msleep(200);
+
+       
+               //send_data_to_aes2501(dev, cmd3_00, 2);
+               write_aes2501_register(dev, 0xff, 0x00);/* Reserved */
+
+               //msleep(80);
+
+               //send_data_to_aes2501(dev, cmd3_01, 12);
+
+
+               write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+               write_aes2501_register(dev, AES2501_REG_AUTOCALOFFSET, 0x41);
+               write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x42);/* ??? */
+               write_aes2501_register(dev, AES2501_REG_DETCTRL, 0x53);/* Cumul ??? */
+               write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE);
+               write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_READ_REGS);
+
+               flush_aes2501_bulk_out(dev);
+
+
+
+
+               recv_data_to_aes2501(dev, buffer, 126);
+
+               printk(KERN_INFO " +reg 0xaf = 0x%x\n", buffer[0x5f]);
+
+               if (++i == 13) break;
+
+       }
+
+
+
+
+
+       /* Part 4 */
+
+       printk(KERN_INFO " -- part 4 --\n");
+
+       //send_data_to_aes2501(dev, cmd4, 14);
+
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */
+       write_aes2501_register(dev, 0xb0, 0x27);/* Reserved */
+       write_aes2501_register(dev, AES2501_REG_ENDROW, 0x0a);
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE);
+       write_aes2501_register(dev, AES2501_REG_DETCTRL, 0x45);/* ???? */
+       write_aes2501_register(dev, AES2501_REG_AUTOCALOFFSET, 0x41);
+
+
+
+
+
+
+       /* ... */
+
+
+/*
+       for (i = 0; i < 126; i += 10)
+       {
+               printk(KERN_INFO " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
+                      buffer[i + 0], buffer[i + 1], buffer[i + 2], buffer[i + 3], buffer[i + 4],
+                      buffer[i + 5], buffer[i + 6], buffer[i + 7], buffer[i + 8], buffer[i + 9]);
+
+               if (i % 20 == 0)
+                       printk(KERN_INFO "\n  ");
+
+       }
+
+       printk(KERN_INFO "\n");
+*/
+
+
+
+       /* Part 5 */
+
+       printk(KERN_INFO " -- part 5 --\n");
+
+       //send_data_to_aes2501(dev, cmd5_00, 2);
+
+       write_aes2501_register(dev, 0xb0, 0x27);/* Reserved */
+
+       //send_data_to_aes2501(dev, cmd5_01, 4);
+
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */
+
+       //msleep(200);
+
+
+       //send_data_to_aes2501(dev, cmd5_02, 2);
+       //send_data_to_aes2501(dev, cmd5_01, 4);
+       //send_data_to_aes2501(dev, cmd5_01, 4);
+
+       write_aes2501_register(dev, 0xff, 0x00);/* Reserved */
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */
+
+
+
+       //msleep(50);
+
+       //send_data_to_aes2501(dev, cmd5_01, 4);
+       //send_data_to_aes2501(dev, cmd5_01, 4);
+       //send_data_to_aes2501(dev, cmd5_01, 4);
+       //send_data_to_aes2501(dev, cmd5_03, 2);
+       //send_data_to_aes2501(dev, cmd5_03, 2);
+       //send_data_to_aes2501(dev, cmd5_04, 2);
+
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* ??? */
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET);
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_SCAN_RESET);
+       write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_READ_REGS);
+       flush_aes2501_bulk_out(dev);
+
+
+       recv_data_to_aes2501(dev, buffer, 126);
+
+
+
+
+
+       return 0;
+
+}
+
+static int detect_finger_on_aes2501(struct usb_aes2501 *dev)
+{
+       //uint8_t cmd1[] = "\x80\x01\x82\x40";
+       //uint8_t cmd2[] = "\x80\x01\x82\x40\x83\x00\x88\x02\x89\x10\x8a\x05\x8c\x00\x8e\x13\x91\x44\x92\x34\x95\x16\x96\x16\x97\x18\xa1\x70\xa2\x02\xa7\x00\xac\x01\xad\x1a\x80\x04\x81\x04\xb4\x00";/*42*/
+
+
+       unsigned char buffer[22];
+       unsigned i, sum;
+
+       //send_data_to_aes2501(dev, cmd1, 4);
+
+       //msleep(30);
+
+
+
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* Reserved */
+       write_aes2501_register(dev, AES2501_REG_DETCTRL, AES2501_DETCTRL_DRATE_CONTINUOUS | AES2501_DETCTRL_SDELAY_31_MS);
+       write_aes2501_register(dev, AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US);/* not the faster ??? */
+       write_aes2501_register(dev, AES2501_REG_MEASDRV, AES2501_MEASDRV_MDRIVE_0_325 | AES2501_MEASDRV_MEASURE_SQUARE);
+       write_aes2501_register(dev, AES2501_REG_MEASFREQ, AES2501_MEASFREQ_2M);
+       write_aes2501_register(dev, AES2501_REG_DEMODPHASE1, DEMODPHASE_NONE);/* Default */
+       write_aes2501_register(dev, AES2501_REG_DEMODPHASE2, DEMODPHASE_NONE);
+       write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE2_4X | AES2501_CHANGAIN_STAGE1_16X);
+       write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x44);
+       write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x34);
+       write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x16);
+       write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x16);
+       write_aes2501_register(dev, AES2501_REG_DATFMT, AES2501_DATFMT_BIN_IMG | 0x08);
+       write_aes2501_register(dev, AES2501_REG_TREG1, 0x70);/* Reserved + 0xXX */
+       write_aes2501_register(dev, 0xa2, 0x02);/* Reserved */
+       write_aes2501_register(dev, 0xa7, 0x00);/* Reserved */
+       write_aes2501_register(dev, AES2501_REG_TREGC, AES2501_TREGC_ENABLE);
+       write_aes2501_register(dev, AES2501_REG_TREGD, 0x1a);
+
+       flush_aes2501_bulk_out(dev);
+
+       /**
+        * TODO:
+        * - lire ici les deux octets.
+        * - voir pour inverser les commandes.
+        */
+
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE);
+       write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT);
+       write_aes2501_register(dev, AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE);
+
+       flush_aes2501_bulk_out(dev);
+
+
+       //send_data_to_aes2501(dev, cmd2, 42);
+
+       recv_data_to_aes2501(dev, buffer, 20);
+
+
+       /* One column is returned here but I don't know which one.
+          Maybe an average over the whole sensor area. */
+       sum = 0;
+       for (i = 1; i != 9; i++) {
+               sum += (buffer[i] & 0xf) + (buffer[i] >> 4);
+       }
+
+
+       //printk(KERN_INFO "===finger=== sum = %d vs %d\n", sum, 20);
+
+
+       /*
+         return (sum > aes->fingerTh1);
+       */
+
+       return sum > 20;
+
+}
+
+
+static unsigned read_fingerprint_on_aes2501(struct usb_aes2501 *dev, void *raw_, unsigned maxstrip)
+{
+       //unsigned char patch_msg[] = "\x80\x01";
+
+    /* 8e xx = set gain */
+    //uint8_t cmd1_00[] = "0x80\x01\x82\x40";
+    //uint8_t cmd1_01[] = "0x80\x01\x82\x40\x83\x00\x88\x02\x8c\x7c\x89\x10\x8d\x24\x9b\x00\x9c\x6c\x9d\x09\x9e\x54\x9f\x78\xa2\x02\xa7\x00\xb6\x26\xb7\x1a\x80\x04\x98\x23\x95\x10\x96\x1f\x8e\x00\x91\x70\x92\x20\x81\x04\xb4\x00";/*50*/
+
+    //uint8_t cmd2[] = "\x98\x23\x95\x10\x96\x1f\x8e\x03\x91\x70\x92\x20\x81\x04";/*14*/
+
+    //uint8_t cmd3[] = "\x98\x22\x95\x00\x96\x2f\x8e\x03\x91\x5b\x92\x20\x81\x04";/*14*/
+
+    uint8_t buf[1705];
+    uint8_t *raw = (uint8_t *) raw_;
+    unsigned nstrips;
+
+       int threshold;
+       int sum;
+
+
+       //send_data_to_aes2501(dev, patch_msg, 2);
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       flush_aes2501_bulk_out(dev);
+
+
+
+       //send_data_to_aes2501(dev, cmd1_00, 4);
+
+
+       //send_data_to_aes2501(dev, cmd1_01, 50);
+
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_MASTER_RESET);
+       write_aes2501_register(dev, AES2501_REG_EXCITCTRL, 0x40);/* Reserved */
+       write_aes2501_register(dev, AES2501_REG_DETCTRL, AES2501_DETCTRL_SDELAY_31_MS | AES2501_DETCTRL_DRATE_CONTINUOUS);
+       write_aes2501_register(dev, AES2501_REG_COLSCAN, AES2501_COLSCAN_SRATE_128_US);
+       write_aes2501_register(dev, AES2501_REG_DEMODPHASE2, 0x7c);/* ... */
+       write_aes2501_register(dev, AES2501_REG_MEASDRV, AES2501_MEASDRV_MEASURE_SQUARE | AES2501_MEASDRV_MDRIVE_0_325);
+       write_aes2501_register(dev, AES2501_REG_DEMODPHASE1, 0x24);/* ... */
+       write_aes2501_register(dev, AES2501_REG_CHWORD1, 0x00);/* Challenge Word */
+       write_aes2501_register(dev, AES2501_REG_CHWORD2, 0x6c);/* Challenge Word */
+       write_aes2501_register(dev, AES2501_REG_CHWORD3, 0x09);/* Challenge Word */
+       write_aes2501_register(dev, AES2501_REG_CHWORD4, 0x54);/* Challenge Word */
+       write_aes2501_register(dev, AES2501_REG_CHWORD5, 0x78);/* Challenge Word */
+       write_aes2501_register(dev, 0xa2, 0x02);/* Reserved */
+       write_aes2501_register(dev, 0xa7, 0x00);/* Reserved */
+       write_aes2501_register(dev, 0xb6, 0x26);/* Reserved */
+       write_aes2501_register(dev, 0xb7, 0x1a);/* Reserved */
+       write_aes2501_register(dev, AES2501_REG_CTRL1, AES2501_CTRL1_REG_UPDATE);
+       write_aes2501_register(dev, AES2501_REG_IMAGCTRL, AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE | AES2501_IMAGCTRL_IMG_DATA_DISABLE);
+       write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x10);
+       write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x1f);
+       write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_2X | AES2501_CHANGAIN_STAGE2_2X);
+       write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x70);
+       write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x20);
+       write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT);
+       write_aes2501_register(dev, AES2501_REG_LPONT, AES2501_LPONT_MIN_VALUE);
+
+    ///////recv_data_to_aes2501(dev, buf, 159);
+    /* TODO: calibration e.g setting gain (0x8e xx) */
+
+
+
+
+    //send_data_to_aes2501(dev, cmd2, 14);
+
+
+
+       write_aes2501_register(dev, AES2501_REG_IMAGCTRL, AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE | AES2501_IMAGCTRL_IMG_DATA_DISABLE);
+       write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x10);
+       write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x1f);
+       write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X);
+       write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x70);
+       write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x20);
+       write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT);
+
+       flush_aes2501_bulk_out(dev);
+
+
+    recv_data_to_aes2501(dev, buf, 159);
+
+    nstrips = 0;
+    do {
+           printk(KERN_INFO "-start-\n");
+        /* Timing in this loop is critical. It decides how fast you can move your finger.
+           If one loop takes tl second, the maximum speed is:
+               (16/500 * 25.4) / tl    [mm per sec]
+         */
+       //send_data_to_aes2501(dev, cmd3, 14);
+
+       write_aes2501_register(dev, AES2501_REG_IMAGCTRL, AES2501_IMAGCTRL_TST_REG_ENABLE | AES2501_IMAGCTRL_HISTO_DATA_ENABLE);
+       write_aes2501_register(dev, AES2501_REG_STRTCOL, 0x00);
+       write_aes2501_register(dev, AES2501_REG_ENDCOL, 0x2f);
+       write_aes2501_register(dev, AES2501_REG_CHANGAIN, AES2501_CHANGAIN_STAGE1_16X);
+       write_aes2501_register(dev, AES2501_REG_ADREFHI, 0x5b);
+       write_aes2501_register(dev, AES2501_REG_ADREFLO, 0x20);
+       write_aes2501_register(dev, AES2501_REG_CTRL2, AES2501_CTRL2_SET_ONE_SHOT);
+
+       flush_aes2501_bulk_out(dev);
+
+
+
+       recv_data_to_aes2501(dev, buf, 1705);
+       memcpy(raw, buf+1, 192*8);
+       raw += 192*8;
+
+           printk(KERN_INFO "-end of copy-\n");
+
+
+           threshold = read_register_value((buf + 1 + 192*8 + 1 + 16*2 + 1 + 8), _AES2501_REG_DATFMT);
+           /*if (threshold < 0)
+                   return threshold;*/
+
+           threshold &= 0x0f;
+
+           sum = sum_histogram_values((buf + 1 + 192*8), threshold);
+           /*if (threshold < 0)
+                   return threshold;*/
+
+       nstrips++;
+           printk(KERN_INFO "-end- %d vs %d\n", nstrips, maxstrip);
+    } while (sum > 0 && nstrips < maxstrip);
+    printk(KERN_INFO "nstrips = %u\n", nstrips);
+    if (nstrips == maxstrip)
+       printk(KERN_INFO "nstrips == %u, swiping the finger too slowly?\n", maxstrip);
+    return nstrips;
+}
+
+
+
+/**
+ * Read a register value from a dump sent by the device.
+ * @data: list of couples <register, value>.
+ * @target: index of the register to process.
+ * @return: -EILSEQ,-EINVAL if error, value > 0 if a finger is here.
+ */
+int read_register_value(const uint8_t *data, Aes2501Registers target)
+{
+       int result;
+       uint8_t offset;
+
+       if (*data == FIRST_AES2501_REG)
+       {
+               offset = target;
+
+               if (!(FIRST_AES2501_REG <= offset && offset <= LAST_AES2501_REG))
+                       result = -EINVAL;
+
+               else
+               {
+                       offset -= FIRST_AES2501_REG;
+                       offset *= 2;
+
+                       result = data[++offset];
+
+               }
+
+       }
+       else result = -EILSEQ;
+
+       return result;
+
+}
+
+
+/**
+ * Tells if a finger motion is still detected.
+ * @data: start point of data to handle, preceded by 0xde.
+ * @threshold: index of values set to 1 by the device.
+ * @return: -EILSEQ,-EINVAL if error, value > 0 if a finger is here.
+ *
+ * Histograms always are a 16-uint16_t long message, where
+ * histogram[i] = number of pixels of value i.
+ */
+int sum_histogram_values(const uint8_t *data, uint8_t threshold)
+{
+       int result;
+       uint16_t *histogram;
+       uint8_t i;
+
+       if (*data == 0xde)
+       {
+               if (threshold > 0x0f)
+                       result = -EINVAL;
+
+               else
+               {
+                       result = 0;
+                       histogram = (uint16_t *)(data + 1);
+
+                       for (i = threshold; i < 16; i++)
+                               result += histogram[i];
+
+               }
+
+       }
+       else result = -EILSEQ;
+
+       return result;
+
+}
+
+
+
+/**********************************************************
+ ** Image processing
+ **********************************************************/
+
+/* This function finds overlapping parts of two frames
+ * Based on calculating normalized hamming distance
+ * between two frames
+ */
+
+static unsigned find_overlap(const uint8_t *first_frame,
+                            const uint8_t *second_frame,
+                            uint32_t frame_height,
+                            uint32_t frame_width,
+                            uint32_t *min_error)
+{
+       uint32_t dy, i;
+       uint32_t error, not_overlapped_height = 0;
+       *min_error = 255 * frame_height * frame_width;
+       for (dy = 0; dy < frame_height; dy++) {
+               /* Calculating difference (error) between parts of frames */
+               error = 0;
+               for (i = 0; i < frame_width * (frame_height - dy); i++) {
+                       /* Using ? operator to avoid abs function */
+                       error += first_frame[i] > second_frame[i] ? 
+                                       (first_frame[i] - second_frame[i]) :
+                                       (second_frame[i] - first_frame[i]); 
+               }
+               
+               /* Normalizing error */
+               error *= 15;
+               error /= i;
+               if (error < *min_error) {
+                       *min_error = error;
+                       not_overlapped_height = dy;
+               }
+               first_frame += frame_width;
+       }
+       
+       return not_overlapped_height; 
+}
+
+
+/* This function assembles frames to single image, returns image height
+ * TODO: add Doxygen comments
+ */
+static unsigned assemble(const uint8_t *input, /* Raw data received from device */
+                                                uint8_t *output, /* Output buffer */
+                                                uint32_t frame_height, /* Height of each frame */
+                                                uint32_t frame_width,  /* Width of each frame */
+                                                uint32_t frames_count, /* Frames count */
+                                                /*int overlap, */ 
+                                                uint8_t reversed, 
+                                                uint32_t *errors_sum
+                                               )
+{
+       uint8_t *assembled = output;
+       uint32_t frame, column, row, image_height = frame_height;
+       uint32_t error, not_overlapped; 
+       
+       *errors_sum = 0;
+       
+       if (frames_count < 1) return 0;
+       
+       /* Rotating given data by 90 degrees 
+        * Taken from document describing aes2501 image format
+        * TODO: move reversing detection here */
+       if (reversed) {
+           output += (frames_count - 1) * frame_width * frame_height;
+       }
+       
+       for (frame = 0; frame < frames_count; frame++) {
+           for (column = 0; column < frame_width; column++) {
+               for (row = 0; row < (frame_height / 2); row++) {
+                               output[frame_width * ( 2 * row) + column] = *input & 0x0F;
+                               output[frame_width * ( 2 * row + 1) + column] = *input >> 4;
+                               input++;
+                       }
+               }
+               
+               if (reversed) {
+                   output -= frame_width * frame_height;
+               }
+               else {
+                   output += frame_width * frame_height;
+               }
+       }
+
+       /* Detecting where frames overlaped */
+       output = assembled;
+       for (frame = 1; frame < frames_count; frame++)
+       {
+               output += frame_width * frame_height;
+               not_overlapped = find_overlap(assembled, output, frame_height, frame_width, &error);
+               *errors_sum += error;
+               image_height += not_overlapped;
+               assembled += frame_width * not_overlapped;
+               memcpy(assembled, output, frame_width * frame_height); 
+       } 
+
+       return image_height;
+}
+
+
+
+static void store_new_aes2501_pnm(const uint8_t *data, unsigned int width, unsigned int height)
+{
+       char header[20];
+       __kernel_size_t header_len;
+       int i;
+       char *iter;
+
+       sprintf(header, "P5\n%u %u\n255\n", width, height);
+       header_len = strlen(header);
+
+       finger_print_len = header_len + width * height;
+       finger_print = kzalloc(finger_print_len, GFP_KERNEL);
+
+       memcpy(finger_print, header, header_len);
+
+       for (i = 0, iter = &finger_print[header_len]; i < width * height; i++, iter++)
+               *iter = (data[i] << 4) + 0x0f;
+
+}
+
+
+
+static void do_scanning(struct work_struct *work)
+{
+       struct usb_aes2501 *dev;
+
+       /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+       uint8_t *raw, *cooked;
+       unsigned swidth = 192;
+       unsigned sheight = 16;
+       unsigned maxstrip = 150;
+       unsigned nstrips, height, mindiff_sum, mindiff_sum_r;
+
+       /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+        dev = container_of(work, struct usb_aes2501, scan_work);
+
+
+
+       
+
+
+       setup_aes2501(dev);
+
+       while (!detect_finger_on_aes2501(dev))
+       {
+           if (dev->stop_scan)
+           {
+               PRINTK_INFO("aborting scan due to module removal\n");
+               return;
+           }
+       };
+
+       /* We don't need physical continuity of allocated memory */
+       raw = (uint8_t *)vmalloc((3 * maxstrip * sheight * swidth) / 2);
+       if (raw == NULL)
+       {
+           PRINTK_CRIT("failed to allocate memory\n");
+           return;
+       }
+       
+       cooked = raw + (maxstrip * sheight * swidth)/2;
+
+
+
+       printk(KERN_INFO "Raw is 0x%p\n", raw);
+
+
+       printk(KERN_INFO "Scanning...\n");
+       nstrips = read_fingerprint_on_aes2501(dev, raw, maxstrip);
+
+       printk(KERN_INFO "Assembling...\n");
+
+
+       height = assemble(raw, cooked, 16, 192, nstrips, 0, &mindiff_sum);
+       height = assemble(raw, cooked, 16, 192, nstrips, 1, &mindiff_sum_r);
+       
+       
+       printk(KERN_INFO "Mindiff normal: %d, mindiff reversed: %d\n", mindiff_sum, mindiff_sum_r);
+       
+       if (mindiff_sum_r < mindiff_sum)
+       {
+           PRINTK_INFO("reversed image detected\n");
+       }
+       else
+       {
+           height = assemble(raw, cooked, 16, 192, nstrips, 0, &mindiff_sum);
+       }
+       
+       printk(KERN_INFO "First height :: %d\n", height);
+
+#if 0
+           if (height < 100) {
+                /* It was a "touch", not a finger scan. */
+                   printk(KERN_INFO "Was only a 'touch' ;(   [%d]\n", height);
+                   /*break;*/
+            }
+           else
+
+           {
+                   //store_new_aes2501_pnm(cooked, swidth, height);
+                   height = assemble(raw, cooked, nstrips, 1, sensor_reversed);
+                   printk(KERN_INFO "Second height :: %d\n", height);
+                   store_new_aes2501_pnm(cooked, swidth, height);
+           }
+#endif
+       store_new_aes2501_pnm(cooked, swidth, height);
+       standby_aes2501(dev);
+
+       vfree(raw);
+
+       flag = 1;
+       wake_up_interruptible(&wq);
+
+
+}
+
+
+static int aes2501_open(struct inode *inode, struct file *file)
+{
+       struct usb_aes2501 *dev;
+
+       //return 0;
+
+
+       dev = _dev;
+
+       printk(KERN_INFO "Plop !\n");
+
+
+       return 0;
+}
+
+
+
+
+
+
+/*
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with the driver core
+ */
+static struct usb_class_driver aes2501_class = {
+       .name =         "aes2501%d",
+       .fops =         &aes2501_fops,
+       .minor_base =   USB_AES2501_MINOR_BASE,
+};
+
+static int aes2501_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+       int retval;
+       struct usb_aes2501 *dev;
+       struct usb_host_interface *iface_desc;
+       __u8 i;
+       struct usb_endpoint_descriptor *endpoint;
+       __u16 buffer_size;
+
+
+
+#if 0
+       /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+       uint8_t *raw, *cooked;
+       unsigned swidth = 192;
+       unsigned sheight = 16;
+       unsigned maxstrip = 150;
+       unsigned nstrips, height;
+
+       /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+
+
+       raw = (uint8_t *)__get_free_page(GFP_KERNEL);//kmalloc((3 * maxstrip * sheight * swidth) / 2, GFP_KERNEL);
+       cooked = raw + (maxstrip * sheight * swidth)/2;
+#endif
+
+       printk(KERN_INFO "aes2501 probe !\n");
+
+
+       retval = -ENOMEM;
+
+       /* Allocate memory for our device state and initialize it */
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (dev == NULL)
+       {
+               PRINTK_CRIT("out of memory\n");
+               goto error;
+       }
+
+       _dev = dev;
+       
+       dev->stop_scan = 0;
+
+       kref_init(&dev->kref);
+       sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);
+       mutex_init(&dev->io_mutex);
+
+       dev->udev = usb_get_dev(interface_to_usbdev(interface));
+       dev->interface = interface;
+       
+       printk(KERN_INFO "num_altsetting == %d\n", interface->num_altsetting);
+
+       /**
+        * Set up the endpoint information.
+        * Use only the first bulk-in and bulk-out endpoints.
+        */
+
+       iface_desc = interface->cur_altsetting;
+
+       printk(KERN_INFO "BULK COUNT %d\n", iface_desc->desc.bNumEndpoints);
+
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
+       {
+               endpoint = &iface_desc->endpoint[i].desc;
+
+               if (!dev->bulk_in_endpointAddr && /*usb_endpoint_is_bulk_in(endpoint))*/
+                   ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+                                       == USB_DIR_IN) &&
+                   ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                                       == USB_ENDPOINT_XFER_BULK))
+               {
+                       /* We found a bulk in endpoint */
+                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       dev->bulk_in_size = buffer_size;
+                       dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
+                       dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+
+                       printk(KERN_INFO "BULK IN %d ; size = %d\n", i, buffer_size);
+
+                       if (dev->bulk_in_buffer == NULL)
+                       {
+                               PRINTK_CRIT("could not allocate bulk_in_buffer\n");
+                               goto error;
+                       }
+
+               }
+
+               if (!dev->bulk_out_endpointAddr && /*usb_endpoint_is_bulk_out(endpoint))*/
+                   ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+                                       == USB_DIR_OUT) &&
+                   ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+                                       == USB_ENDPOINT_XFER_BULK))
+               {
+                       printk(KERN_INFO "BULK OUT %d\n", i);
+
+                       /* We found a bulk out endpoint */
+                       dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;
+               }
+
+       }
+
+       if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr))
+       {
+               PRINTK_CRIT("could not find both bulk-in and bulk-out endpoints\n");
+               goto error;
+       }
+
+/*
+       dev->once_tasklet = kzalloc(sizeof(*dev->once_tasklet), GFP_KERNEL);
+       if (dev->once_tasklet == NULL)
+       {
+               PRINTK_CRIT("out of memory\n");
+               goto error;
+       }
+*/
+       /* Save our data pointer in this interface device */
+       usb_set_intfdata(interface, dev);
+
+       /* We can register the device now, as it is ready */
+       retval = usb_register_dev(interface, &aes2501_class);
+       if (retval) {
+               /* something prevented us from registering this driver */
+               PRINTK_CRIT("not able to get a minor for this device\n");
+               usb_set_intfdata(interface, NULL);
+               goto error;
+       }
+
+       /* Let the user know what node this device is now attached to */
+       PRINTK_INFO("device now attached to aes2501-%d\n", interface->minor);
+
+#if 0
+       setup_aes2501(dev);
+
+       while (!detect_finger_on_aes2501(dev));
+
+
+       printk(KERN_INFO "Raw is 0x%p\n", raw);
+
+
+       printk(KERN_INFO "Scanning...\n");
+       nstrips = read_fingerprint_on_aes2501(dev, raw, maxstrip);
+
+       printk(KERN_INFO "Assembling...\n");
+
+           height = assemble(raw, cooked, nstrips, 1);
+           if (height < 100) {
+                /* It was a "touch", not a finger scan. */
+                   printk(KERN_INFO "Was only a 'touch' ;(\n");
+                   /*break;*/
+            }
+           else
+           {
+           store_new_aes2501_pnm(cooked, swidth, height);
+           height = assemble(raw, cooked, nstrips, 0);
+           store_new_aes2501_pnm(cooked, swidth, height);
+           }
+
+       standby_aes2501(dev);
+#endif
+
+       return 0;
+
+error:
+       if (dev != NULL)
+               kref_put(&dev->kref, aes2501_delete);
+
+       return retval;
+
+}
+
+
+static void aes2501_disconnect(struct usb_interface *interface)
+{
+       int minor;
+       struct usb_aes2501 *dev;
+
+       minor = interface->minor;
+
+       /* Prevent aes2501_open() from racing aes2501_disconnect() */
+       lock_kernel();
+
+       dev = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       /* Give back our minor */
+       usb_deregister_dev(interface, &aes2501_class);
+
+       /* Prevent more I/O from starting */
+       mutex_lock(&dev->io_mutex);
+       dev->interface = NULL;
+       mutex_unlock(&dev->io_mutex);
+
+       unlock_kernel();
+
+       /* Decrement our usage count */
+       kref_put(&dev->kref, aes2501_delete);
+
+       PRINTK_INFO("aes2501 device #%d now disconnected\n", minor);
+
+
+
+
+       printk(KERN_INFO "aes2501 disconnect !\n");
+
+
+}
+
+
+static struct usb_driver aes2501_driver = {
+       .name           = "aes2501",
+       .probe          = aes2501_probe,
+       .disconnect     = aes2501_disconnect,
+       .id_table       = id_table,
+};
+
+
+static int __init aes2501_init(void)
+{
+       int retval;
+
+       comm_queue = create_singlethread_workqueue("aes2501");
+       if (comm_queue == NULL) {
+               PRINTK_CRIT("could not create work queue\n");
+               return -ENOMEM;
+       }
+
+       retval = usb_register(&aes2501_driver);
+       if (retval == -EINVAL)
+       {
+               printk(KERN_ERR "usb_register failed. Error number %d\n", retval);
+               destroy_workqueue(comm_queue);
+               return retval;
+       }
+
+       return 0;
+
+}
+
+static void __exit aes2501_exit(void)
+{
+       if (_dev)
+               _dev->stop_scan = 1;
+       destroy_workqueue(comm_queue);
+       usb_deregister(&aes2501_driver);
+}
+
+module_init(aes2501_init);
+module_exit(aes2501_exit);
+
+MODULE_AUTHOR("Cyrille Bagard");
+MODULE_DESCRIPTION("AES 2501 fingerprint scanner driver");
+MODULE_LICENSE("GPL");
diff --git a/fingerprint/aes2501.h b/fingerprint/aes2501.h
new file mode 100644 (file)
index 0000000..0f12fa8
--- /dev/null
@@ -0,0 +1,40 @@
+
+/*
+ * aes2501.h -- AuthenTec AES2501 Fingerprint Sensor Driver for Linux
+ *
+ * Maintainer: Cyrille Bagard <nocbos@gmail.com>
+ *
+ * Copyright (C) 2007 Cyrille Bagard
+ *
+ * This file is part of the AES2501 driver.
+ *
+ * the AES2501 driver 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.
+ *
+ * the AES2501 driver 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 the AES2501 driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+#ifndef __AES2501_H
+#define __AES2501_H
+
+
+#define AES2501_IOC_MAGIC      'N'
+
+
+#define AES2501_IOC_TEST       _IOW(AES2501_IOC_MAGIC, 1, int)
+
+
+
+
+#endif /* __AES2501_H */
diff --git a/fingerprint/aes2501_regs.h b/fingerprint/aes2501_regs.h
new file mode 100644 (file)
index 0000000..a01de16
--- /dev/null
@@ -0,0 +1,464 @@
+
+/*
+ * aes2501_regs.h -- AuthenTec AES2501 Fingerprint Sensor Driver for Linux
+ *
+ * Maintainer: Cyrille Bagard <nocbos@gmail.com>
+ *
+ * Copyright (C) 2007 Cyrille Bagard
+ *
+ * This file is part of the AES2501 driver.
+ *
+ * the AES2501 driver 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.
+ *
+ * the AES2501 driver 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 the AES2501 driver; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+#ifndef __AES2501_REGS_H
+#define __AES2501_REGS_H
+
+
+
+/*
+ * AES2501 Control Register 1 (CTRL1)
+ */
+
+#define AES2501_REG_CTRL1 0x80
+
+#define AES2501_CTRL1_MASTER_RESET     0x01    /* Master reset, same as Power On Reset */
+#define AES2501_CTRL1_SCAN_RESET       0x02    /* Scan reset: stop and restart the scan sequencer */
+#define AES2501_CTRL1_REG_UPDATE       0x04    /* 1 = continuously updated, 0 = updated prior to starting a scan */
+
+
+/*
+ * AES2501 Control Register 2 (CTRL2)
+ */
+
+#define AES2501_REG_CTRL2 0x81
+
+#define AES2501_CTRL2_CONTINUOUS       0x01    /* 1 = continuous scans, 0 = single scans */
+#define AES2501_CTRL2_READ_REGS                0x02    /* Read the current state of the local registers in the Sensor IC */
+#define AES2501_CTRL2_SET_ONE_SHOT     0x04    /* Set the one-shot flip-flop */
+#define AES2501_CTRL2_CLR_ONE_SHOT     0x08    /* Clear the one-shot flip-flop */
+#define AES2501_CTRL2_READ_ID          0x10    /* Read the ID register of the chip */
+
+
+/*
+ * AES2501 Excitation Common Control Register (EXCITCTRL)
+ */
+
+#define AES2501_REG_EXCITCTRL 0x82
+
+#define AES2501_EXCITCTRL_LO_PWR       0x01    /* If set, enable detection in sleep/suspend mode */
+#define AES2501_EXCITCTRL_AUTO_CAL     0x02    /* If set, perform finger detection calibration */
+#define AES2501_EXCITCTRL_SGC_ENABLE   0x04    /* ??? */
+#define AES2501_EXCITCTRL_SGC_RESTART  0x08    /* ??? */
+
+#define AES2501_EXCITCTRL_EXCIT_SQR    0x20    /* Select the (1=square | 0=sine) wave finger drive signal */
+#define AES2501_EXCITCTRL_EXCIT_BOOST  0x10    /* TODO: understand this part */
+
+
+/*
+ * AES2501 Detect Control Register (DETCTRL)
+ */
+
+#define AES2501_REG_DETCTRL 0x83
+
+enum aes2501_detection_rate {
+
+       AES2501_DETCTRL_DRATE_CONTINUOUS        = 0x00, /* Detection cycles occur continuously */
+       AES2501_DETCTRL_DRATE_16_MS             = 0x01, /* Detection cycles occur every 16.62 ms */
+       AES2501_DETCTRL_DRATE_31_MS             = 0x02, /* Detection cycles occur every 31.24 ms */
+       AES2501_DETCTRL_DRATE_62_MS             = 0x03, /* Detection cycles occur every 62.50 ms */
+       AES2501_DETCTRL_DRATE_125_MS            = 0x04, /* Detection cycles occur every 125.0 ms */
+       AES2501_DETCTRL_DRATE_250_MS            = 0x05, /* Detection cycles occur every 250.0 ms */
+       AES2501_DETCTRL_DRATE_500_MS            = 0x06, /* Detection cycles occur every 500.0 ms */
+       AES2501_DETCTRL_DRATE_1_S               = 0x07  /* Detection cycles occur every 1 s */
+
+};
+
+enum aes2501_settling_delay {
+
+       AES2501_DETCTRL_SDELAY_31_MS    = 0x00, /* 31.25 ms */
+       AES2501_DETCTRL_SSDELAY_62_MS   = 0x10, /* 62.5 ms */
+       AES2501_DETCTRL_SSDELAY_125_MS  = 0x20, /* 125 ms */
+       AES2501_DETCTRL_SSDELAY_250_MS  = 0x30  /* 250 ms */
+
+};
+
+
+
+
+
+/*
+ * AES2501 Column Scan Rate Register (COLSCAN)
+ */
+
+#define AES2501_REG_COLSCAN 0x88
+
+enum aes2501_col_scan_rate {
+
+    AES2501_COLSCAN_SRATE_32_US                = 0x00, /* 32 us */
+    AES2501_COLSCAN_SRATE_64_US                = 0x01, /* 64 us */
+    AES2501_COLSCAN_SRATE_128_US       = 0x02, /* 128 us */
+    AES2501_COLSCAN_SRATE_256_US       = 0x03, /* 256 us */
+    AES2501_COLSCAN_SRATE_512_US       = 0x04, /* 512 us */
+    AES2501_COLSCAN_SRATE_1024_US      = 0x05, /* 1024 us */
+    AES2501_COLSCAN_SRATE_2048_US      = 0x06, /* 2048 us */
+
+};
+
+
+/*
+ * AES2501 Measure Drive Register (MEASDRV)
+ */
+
+#define AES2501_REG_MEASDRV 0x89
+
+enum aes2501_mesure_drive {
+
+       AES2501_MEASDRV_MDRIVE_0_325    = 0x00, /* 0.325 Vpp */
+       AES2501_MEASDRV_MDRIVE_0_65     = 0x01, /* 0.65 Vpp */
+       AES2501_MEASDRV_MDRIVE_1_3      = 0x02, /* 1.3 Vpp */
+       AES2501_MEASDRV_MDRIVE_2_6      = 0x03  /* 2.6 Vpp */
+
+};
+
+#define AES2501_MEASDRV_SQUARE         0x20    /* Select (1=square | 0=sine) wave drive during measure */
+#define AES2501_MEASDRV_MEASURE_SQUARE 0x10    /* 0 = use mesure drive setting, 1 = when sine wave is selected */
+
+
+/*
+ * AES2501 Measure Frequency Register (MEASFREQ)
+ */
+
+#define AES2501_REG_MEASFREQ 0x8a
+
+enum aes2501_measure_freq {
+
+       AES2501_MEASFREQ_125K   = 0x01, /* 125 kHz */
+       AES2501_MEASFREQ_250K   = 0x02, /* 250 kHz */
+       AES2501_MEASFREQ_500K   = 0x03, /* 500 kHz */
+       AES2501_MEASFREQ_1M     = 0x04, /* 1 MHz */
+       AES2501_MEASFREQ_2M     = 0x05  /* 2 MHz */
+
+};
+
+
+
+
+/*
+ * AES2501 Demod Phase 2 Register (DEMODPHASE2)
+ */
+
+#define AES2501_REG_DEMODPHASE2 0x8c
+
+#define DEMODPHASE_NONE                0x00
+
+#define DEMODPHASE_180_00      0x40    /* 180 degrees */
+#define DEMODPHASE_2_81                0x01    /* 2.8125 degrees */
+
+
+/*
+ * AES2501 Demod Phase 1 Register (DEMODPHASE1)
+ */
+
+#define AES2501_REG_DEMODPHASE1 0x8d
+
+#define DEMODPHASE_1_40                0x40    /* 1.40625 degrees */
+#define DEMODPHASE_0_02                0x01    /* 0.02197256 degrees */
+
+
+/*
+ * AES2501 Channel Gain Register (CHANGAIN)
+ */
+
+#define AES2501_REG_CHANGAIN 0x8e
+
+enum aes2501_sensor_gain1 {
+
+       AES2501_CHANGAIN_STAGE1_2X      = 0x00, /* 2x */
+       AES2501_CHANGAIN_STAGE1_4X      = 0x01, /* 4x */
+       AES2501_CHANGAIN_STAGE1_8X      = 0x02, /* 8x */
+       AES2501_CHANGAIN_STAGE1_16X     = 0x03  /* 16x */
+
+};
+
+enum aes2501_sensor_gain2 {
+
+       AES2501_CHANGAIN_STAGE2_2X      = 0x00, /* 2x */
+       AES2501_CHANGAIN_STAGE2_4X      = 0x10, /* 4x */
+       AES2501_CHANGAIN_STAGE2_8X      = 0x20, /* 8x */
+       AES2501_CHANGAIN_STAGE2_16X     = 0x30  /* 16x */
+
+};
+
+
+
+/*
+ * AES2501 A/D Reference High Register (ADREFHI)
+ */
+
+#define AES2501_REG_ADREFHI 0x91
+
+
+/*
+ * AES2501 A/D Reference Low Register (ADREFLO)
+ */
+
+#define AES2501_REG_ADREFLO 0x92
+
+
+/*
+ * AES2501 Start Row Register (STRTROW)
+ */
+
+#define AES2501_REG_STRTROW 0x93
+
+
+/*
+ * AES2501 End Row Register (ENDROW)
+ */
+
+#define AES2501_REG_ENDROW 0x94
+
+
+/*
+ * AES2501 Start Column Register (STRTCOL)
+ */
+
+#define AES2501_REG_STRTCOL 0x95
+
+
+/*
+ * AES2501 End Column Register (ENDCOL)
+ */
+
+#define AES2501_REG_ENDCOL 0x96
+
+
+/*
+ * AES2501 Data Format Register (DATFMT)
+ */
+
+#define AES2501_REG_DATFMT 0x97
+
+#define AES2501_DATFMT_EIGHT   0x40    /* 1 = 8-bit data, 0 = 4-bit data */
+#define AES2501_DATFMT_LOW_RES 0x20    /* TODO: understand this part */
+#define AES2501_DATFMT_BIN_IMG 0x10    /* TODO: understand this part */
+
+/* TODO: Threshold */
+
+
+/*
+ * AES2501 Image Data Control Register (IMAGCTRL)
+ */
+
+#define AES2501_REG_IMAGCTRL 0x98
+
+#define AES2501_IMAGCTRL_IMG_DATA_DISABLE      0x01    /* If set, image data message and authentication message are not returned when imaging */
+#define AES2501_IMAGCTRL_HISTO_DATA_ENABLE     0x02    /* if set, send histogram message when imaging */
+#define AES2501_IMAGCTRL_HISTO_EACH_ROW                0x04    /* A histo message is sent at the end of (1=each row | 0 = scanning) */  
+#define AES2501_IMAGCTRL_HISTO_FULL_ARRAY      0x08    /* 1 = full image array, 0 = 64x64 center */  
+#define AES2501_IMAGCTRL_REG_FIRST             0x10    /* Registers are returned (1=before | 0=after) image data */
+#define AES2501_IMAGCTRL_TST_REG_ENABLE                0x20    /* If set, Test Registers are returned with register messages */
+
+
+
+
+
+
+
+
+/*
+ * AES2501 Status Register (STAT)
+ */
+
+#define AES2501_REG_STAT 0x9a
+
+#define AES2501_STAT_SCAN      0x0f    /* Scan state */
+#define AES2501_STAT_ERROR     0x10    /* Framing error */
+#define AES2501_STAT_PAUSED    0x20    /* Scan paused */
+#define AES2501_STAT_RESET     0x40    /* Reset occurred */
+
+enum aes2501_scan_state {
+
+       STATE_WAITING_FOR_FINGER        = 0x00, /* Waiting for finger */
+       STATE_FINGER_SETTLING_DELAY     = 0x01, /* In Finger settling delay */
+       STATE_POWER_UP_DELAY            = 0x02, /* In power up delay */
+       STATE_WAITING_TO_START_SCAN     = 0x03, /* Waiting to start image scan */
+       STATE_PRELOADING_SUBARRAY_0     = 0x04, /* Pre-loading subarray 0 */
+       STATE_SETUP_FOR_ROW_ADVANCE     = 0x05, /* Setup for row advance */
+       STATE_WAITING_FOR_ROW_ADVANCE   = 0x06, /* Waiting for row advance */
+       STATE_PRELOADING_COL_0          = 0x07, /* Pre-loading column 0 */
+       STATE_SETUP_FOR_COL_ADVANCE     = 0x08, /* Setup for column advance */
+       STATE_WAITING_FOR_COL_ADVANCE   = 0x09, /* Waiting for column advance */
+       STATE_WAITING_FOR_SCAN_START    = 0x0a, /* Waiting for scan start */
+       STATE_WAITING_FOR_SCAN_END      = 0x0b, /* Waiting for scan end */
+       STATE_WAITING_FOR_ROW_SETUP     = 0x0c, /* Waiting for row setup */
+       STATE_WAITING_FOR_COL_TIME      = 0x0d, /* Waiting for one column time (depends on scan rate) */
+       STATE_WAITING_FOR_QUEUED_DATA   = 0x0e, /* Waiting for queued data transmission to be completed */
+       STATE_WAIT_FOR_128_US           = 0x0f  /* Wait for 128 us */
+
+};
+
+
+/*
+ * AES2501 Challenge Word 1 Register (CHWORD1)
+ */
+
+#define AES2501_REG_CHWORD1 0x9b
+
+#define AES2501_CHWORD1_IS_FINGER      0x01    /* If set, finger is present */
+
+
+/*
+ * AES2501 Challenge Word 2 Register (CHWORD2)
+ */
+
+#define AES2501_REG_CHWORD2 0x9c
+
+
+/*
+ * AES2501 Challenge Word 3 Register (CHWORD3)
+ */
+
+#define AES2501_REG_CHWORD3 0x9d
+
+
+/*
+ * AES2501 Challenge Word 4 Register (CHWORD4)
+ */
+
+#define AES2501_REG_CHWORD4 0x9e
+
+
+/*
+ * AES2501 Challenge Word 5 Register (CHWORD5)
+ */
+
+#define AES2501_REG_CHWORD5 0x9f
+
+
+
+
+
+/*
+ * AES2501 Test Register 1 (TREG1)
+ */
+
+#define AES2501_REG_TREG1 0xa1
+
+#define AES2501_TREG1_SBIAS_UNLCK      0x10    /* 1 = unlock the controlling of sense amp bias, 0 = sense amp bias changes */
+
+enum aes2501_sense_amp_bias {
+
+       AES2501_TREG1_SAMP_BIAS_2_UA    = 0x00, /* 2.5 uA */
+       AES2501_TREG1_SAMP_BIAS_5_UA    = 0x01, /* 5 uA */
+       AES2501_TREG1_SAMP_BIAS_8_UA    = 0x02, /* 8 uA */
+       AES2501_TREG1_SAMP_BIAS_10_UA   = 0x03  /* 10 uA */
+
+};
+
+
+
+
+/*
+ * AES2501 Auto-Calibration Offset Register (AUTOCALOFFSET)
+ */
+
+#define AES2501_REG_AUTOCALOFFSET 0xa8
+
+
+
+
+
+/*
+ * AES2501 Test Register C (TREGC)
+ */
+
+#define AES2501_REG_TREGC 0xac
+
+#define AES2501_TREGC_ENABLE   0x01    /* Enable the reading of the register in TREGD */
+
+
+/*
+ * AES2501 Test Register D (TREGD)
+ */
+
+#define AES2501_REG_TREGD 0xad
+
+
+
+
+
+/*
+ * AES2501 Low Power Oscillator On Time Register (LPONT)
+ */
+
+#define AES2501_REG_LPONT 0xb4
+
+/*
+ * This register sets the low power oscillator on time.
+ * Units are roughly equivalent to milliseconds.
+ */
+
+#define AES2501_LPONT_MIN_VALUE 0x00   /* 0 ms */
+#define AES2501_LPONT_MAX_VALUE 0x1f   /* About 16 ms */
+
+
+
+#define ENUM_REG(reg) _ ## reg = reg
+
+typedef enum _Aes2501Registers
+{
+       ENUM_REG(AES2501_REG_CTRL1),
+       ENUM_REG(AES2501_REG_CTRL2),
+       ENUM_REG(AES2501_REG_EXCITCTRL),
+       ENUM_REG(AES2501_REG_DETCTRL),
+       ENUM_REG(AES2501_REG_COLSCAN),
+       ENUM_REG(AES2501_REG_MEASDRV),
+       ENUM_REG(AES2501_REG_MEASFREQ),
+       ENUM_REG(AES2501_REG_DEMODPHASE2),
+       ENUM_REG(AES2501_REG_DEMODPHASE1),
+       ENUM_REG(AES2501_REG_CHANGAIN),
+       ENUM_REG(AES2501_REG_ADREFHI),
+       ENUM_REG(AES2501_REG_ADREFLO),
+       ENUM_REG(AES2501_REG_STRTROW),
+       ENUM_REG(AES2501_REG_ENDROW),
+       ENUM_REG(AES2501_REG_STRTCOL),
+       ENUM_REG(AES2501_REG_ENDCOL),
+       ENUM_REG(AES2501_REG_DATFMT),
+       ENUM_REG(AES2501_REG_IMAGCTRL),
+       ENUM_REG(AES2501_REG_STAT),
+       ENUM_REG(AES2501_REG_CHWORD1),
+       ENUM_REG(AES2501_REG_CHWORD2),
+       ENUM_REG(AES2501_REG_CHWORD3),
+       ENUM_REG(AES2501_REG_CHWORD4),
+       ENUM_REG(AES2501_REG_CHWORD5),
+       ENUM_REG(AES2501_REG_TREG1),
+       ENUM_REG(AES2501_REG_AUTOCALOFFSET),
+       ENUM_REG(AES2501_REG_TREGC),
+       ENUM_REG(AES2501_REG_TREGD),
+       ENUM_REG(AES2501_REG_LPONT)
+
+} Aes2501Registers;
+
+
+#define FIRST_AES2501_REG      0x80
+#define LAST_AES2501_REG       0x9f
+
+
+
+#endif /* __AES2501_REGS_H */
diff --git a/fingerprint/usertest.c b/fingerprint/usertest.c
new file mode 100644 (file)
index 0000000..c2dce93
--- /dev/null
@@ -0,0 +1,78 @@
+/**
+ * AES2501 Device Driver
+ * Userspace test program
+ *
+ * Compile with:
+ * gcc -I. -o usertest usertest.c
+ */
+
+
+#include <aes2501.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+
+#define BUFFER_SIZE 256
+
+
+int main(int argc, char *argv[])
+{
+       int fd_in;
+       int fd_out;
+       char buffer[BUFFER_SIZE];
+       size_t len;
+
+       fd_in = -1;
+       fd_out = -1;
+
+
+       int data, rdata;
+
+
+
+       fd_in = open("/dev/aes2501", O_RDONLY);
+       if (fd_in == -1) {
+               perror("open() -- ");
+               goto err;
+       }
+
+       fd_out = open("/root/pic.pnm", O_CREAT | O_WRONLY);
+       if (fd_out == -1) {
+               perror("open() -- ");
+               goto err;
+       }
+
+
+
+       data = 0x55555555;
+       ioctl(fd_in, AES2501_IOC_TEST, data);
+       //ioctl(fd_in, CASE2, &rdata);
+
+       printf("IOCTL test: written: '%x' - received: '%x'\n", data, rdata);
+
+
+
+
+       /* Write the fingerprint */
+       while ((len = read(fd_in, buffer, BUFFER_SIZE)) > 0)
+               write(fd_out, buffer, len);
+
+       close(fd_in);
+       close(fd_out);
+
+       return EXIT_SUCCESS;
+
+ err:
+
+       if (fd_in != -1)
+               close(fd_in);
+
+       if (fd_out != -1)
+               close(fd_out);
+
+       return EXIT_FAILURE;
+
+}
index ffc5fb8..a5c0b3e 100644 (file)
@@ -1,19 +1,10 @@
-key 103        WIFI    WAKE_DROPPED
-key 104        MENU
-key 105        DPAD_CENTER
-key 107        BACK
-key 108        SEARCH
-key 109        VOLUME_UP
-key 110        VOLUME_DOWN
-
-
-key    9       BACK    WAKE_DROPPED
-key    180     HOME    
-key    111     DPAD_UP
-key    113     DPAD_LEFT
-key    36      DPAD_CENTER
-key    114     DPAD_RIGHT
-key    116     DPAD_DOWN
+key    1       BACK    WAKE_DROPPED
+key    172     MENU    
+key    103     DPAD_UP
+key    105     DPAD_LEFT
+key    28      DPAD_CENTER
+key    106     DPAD_RIGHT
+key    108     DPAD_DOWN
 
 
 
index d2f59be..23adc2a 100644 (file)
@@ -62,7 +62,7 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_CROSS_COMPILE=""
-CONFIG_LOCALVERSION="-android-x86-x41t"
+CONFIG_LOCALVERSION="-android-x86-m1400"
 # CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_HAVE_KERNEL_GZIP=y
 CONFIG_HAVE_KERNEL_BZIP2=y
diff --git a/ts.env b/ts.env
index 4bfd0d0..7bc7189 100644 (file)
--- a/ts.env
+++ b/ts.env
@@ -1,5 +1,5 @@
 TSLIB_CONSOLEDEVICE=none
-TSLIB_FBDEVICE=/dev/graphics/fb0
+TSLIB_FBDEVICE=/dev/fb0
 TSLIB_TSDEVICE=/dev/input/event8
 TSLIB_CALIBFILE=/data/system/tslib/pointercal
 TSLIB_CONFFILE=/system/etc/ts.conf