? drivers/misc/.Makefile.swp ? drivers/misc/.built-in.o.cmd ? drivers/misc/.fsi_drv.c.swp ? drivers/misc/.fsi_drv.ko.cmd ? drivers/misc/.fsi_drv.mod.o.cmd ? drivers/misc/.fsi_drv.o.cmd ? drivers/misc/.ipaq-sleeve.ko.cmd ? drivers/misc/.ipaq-sleeve.mod.o.cmd ? drivers/misc/.ipaq-sleeve.o.cmd ? drivers/misc/.ipaq_samcop_fsi.ko.cmd ? drivers/misc/.ipaq_samcop_fsi.mod.o.cmd ? drivers/misc/.ipaq_samcop_fsi.o.cmd ? drivers/misc/.samcop_fsi.c.swp ? drivers/misc/.samcop_fsi.h.swp ? drivers/misc/.samcop_fsi.ko.cmd ? drivers/misc/.samcop_fsi.mod.o.cmd ? drivers/misc/.samcop_fsi.o.cmd ? drivers/misc/.samcop_sleeve.ko.cmd ? drivers/misc/.samcop_sleeve.mod.o.cmd ? drivers/misc/.samcop_sleeve.o.cmd ? drivers/misc/fsi_drv.ko ? drivers/misc/fsi_drv.mod.c ? drivers/misc/ipaq-sleeve.ko ? drivers/misc/ipaq-sleeve.mod.c ? drivers/misc/ipaq_samcop_fsi.ko ? drivers/misc/ipaq_samcop_fsi.mod.c ? drivers/misc/samcop_fsi.ko ? drivers/misc/samcop_fsi.mod.c ? drivers/misc/samcop_sleeve.ko ? drivers/misc/samcop_sleeve.mod.c ? drivers/misc/adc/.adc.o.cmd ? drivers/misc/adc/.built-in.o.cmd ? drivers/misc/adc/.samcop_adc.o.cmd ? arch/arm/mach-pxa/h5400/.built-in.o.cmd ? arch/arm/mach-pxa/h5400/.h5400.c.swp ? arch/arm/mach-pxa/h5400/.h5400.o.cmd ? arch/arm/mach-pxa/h5400/.h5400_bl.o.cmd ? arch/arm/mach-pxa/h5400/.h5400_bt.ko.cmd ? arch/arm/mach-pxa/h5400/.h5400_bt.mod.o.cmd ? arch/arm/mach-pxa/h5400/.h5400_bt.o.cmd ? arch/arm/mach-pxa/h5400/.h5400_lcd.o.cmd ? arch/arm/mach-pxa/h5400/h5000_buttons.c ? arch/arm/mach-pxa/h5400/h5400_bt.ko ? arch/arm/mach-pxa/h5400/h5400_bt.mod.c Index: include/asm/arch/h5400-gpio.h =================================================================== RCS file: /cvs/linux/kernel26/include/asm-arm/arch-pxa/h5400-gpio.h,v retrieving revision 1.7 diff -a -u -r1.7 h5400-gpio.h --- include/asm/arch/h5400-gpio.h 15 Nov 2006 22:18:21 -0000 1.7 +++ include/asm/arch/h5400-gpio.h 14 Aug 2007 20:12:38 -0000 @@ -88,7 +88,7 @@ #define GPIO_NR_H5400_IRDA_SD 58 /* to hsdl3002 sd */ /* 59 not connected */ #define GPIO_NR_H5400_POWER_SD_N 60 /* controls power to SD */ -#define GPIO_NR_H5400_POWER_RS232_N 61 /* inverted FORCEON to rs232 transceiver */ +#define GPIO_NR_H5400_POWER_RS232_N_OR_FS 61 /* inverted FORCEON to rs232 transceiver or FCD*/ #define GPIO_NR_H5400_POWER_ACCEL_N 62 /* controls power to accel */ /* 63 is not connected */ #define GPIO_NR_H5400_OPT_NVRAM 64 /* controls power to expansion pack */ Index: drivers/misc/Kconfig =================================================================== RCS file: /cvs/linux/kernel26/drivers/misc/Kconfig,v retrieving revision 1.27 diff -a -u -r1.27 Kconfig --- drivers/misc/Kconfig 27 Jul 2007 21:42:05 -0000 1.27 +++ drivers/misc/Kconfig 14 Aug 2007 20:12:38 -0000 @@ -163,13 +163,13 @@ # tristate "HTC ASIC2 sleeve driver" # depends on HTC_ASIC2 && IPAQ_SLEEVE -#config IPAQ_SAMCOP_FSI -# tristate "HP iPAQ SAMCOP FSI driver" -# depends on SOC_SAMCOP -# help -# Provides access to the samcop portion of the fingerprint scanner -# on the h5[5,4]xx. It also provides the /dev/misc/fsi0 device to -# userspace users of the scanner. +config IPAQ_SAMCOP_FSI + tristate "HP iPAQ SAMCOP FSI driver" + depends on SOC_SAMCOP + help + Provides access to the samcop portion of the fingerprint scanner + on the h5[5,4]xx. It also provides the /dev/misc/fsi0 device to + userspace users of the scanner. config IPAQ_SAMCOP_SLEEVE tristate "HP iPAQ SAMCOP Sleeve driver" Index: drivers/misc/Makefile =================================================================== RCS file: /cvs/linux/kernel26/drivers/misc/Makefile,v retrieving revision 1.23 diff -a -u -r1.23 Makefile --- drivers/misc/Makefile 27 Jul 2007 21:42:05 -0000 1.23 +++ drivers/misc/Makefile 14 Aug 2007 20:12:38 -0000 @@ -26,6 +26,8 @@ #obj-$(CONFIG_IPAQ_ASIC2_SLEEVE) += asic2_sleeve.o #obj-$(CONFIG_IPAQ_ASIC2_OWM) += asic2_owm.o -#obj-$(CONFIG_IPAQ_SAMCOP_FSI) += samcop_fsi.o fsi_drv.o +obj-$(CONFIG_IPAQ_SAMCOP_FSI) += ipaq_samcop_fsi.o +ipaq_samcop_fsi-objs = samcop_fsi.o fsi_drv.o + obj-$(CONFIG_IPAQ_SAMCOP_SLEEVE) += samcop_sleeve.o Index: drivers/misc/fsi_drv.c =================================================================== RCS file: /cvs/linux/kernel26/drivers/misc/fsi_drv.c,v retrieving revision 1.3 diff -a -u -r1.3 fsi_drv.c --- drivers/misc/fsi_drv.c 23 Aug 2006 18:24:04 -0000 1.3 +++ drivers/misc/fsi_drv.c 14 Aug 2007 20:12:38 -0000 @@ -26,24 +26,26 @@ #include #include +#include +#include #include "samcop_fsi.h" -atomic_t fsi_in_use; -DECLARE_WAIT_QUEUE_HEAD(fsi_rqueue); -struct timer_list fsi_temp_timer; - -unsigned int fsi_prescale = 19; -unsigned int fsi_dmi = 1124; -unsigned int fsi_treshold_on = 20; -unsigned int fsi_treshold_off = 4; -unsigned int fsi_buffer_size = FSI_FRAME_SIZE * (sizeof(unsigned long)) * 3; +static atomic_t fsi_in_use; +static DECLARE_WAIT_QUEUE_HEAD(fsi_rqueue); +static struct timer_list fsi_temp_timer; + +static unsigned int fsi_prescale = 19; +static unsigned int fsi_dmi = 1124; +static unsigned int fsi_treshold_on = 20; +static unsigned int fsi_treshold_off = 4; +static unsigned int fsi_buffer_size = FSI_FRAME_SIZE * (sizeof(unsigned long)) * 3; volatile unsigned char fsi_lfrm = 0; static struct samcop_fsi *fsi_ = NULL; -void fsi_set_mode(unsigned int cmd) +static void fsi_set_mode(unsigned int cmd) { static unsigned int current_mode = 0; static unsigned long control_register = 0; @@ -107,14 +109,14 @@ } } -void fsi_timer_temp_callback(unsigned long input) +static void fsi_timer_temp_callback(unsigned long input) { printk(KERN_DEBUG "%s: stopping temperature increase (status=%d)\n", __FUNCTION__, samcop_fsi_get_control(fsi_) & FSI_CONTROL_TEMP); fsi_set_mode(FSI_CMD_STOP_TEMP); } -inline int fsi_analyze_column(struct fsi_read_state *read_state, unsigned int data) +static inline int fsi_analyze_column(struct fsi_read_state *read_state, unsigned int data) { if ((data & 0xEFEF) == 0xE0E0) { /* sync column */ read_state->frame_number++; @@ -158,7 +160,7 @@ return 0; } -void fsi_run_tasklet(unsigned long state_ptr) +static void fsi_run_tasklet(unsigned long state_ptr) { unsigned int i; unsigned long data; @@ -202,14 +204,14 @@ DECLARE_TASKLET_DISABLED(fsi_tasklet,fsi_run_tasklet,0); -int fsi_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t fsi_irq_handler(int irq, void *dev_id) { unsigned int fifo_status; fifo_status = samcop_fsi_get_status(fsi_); - if (fifo_status & 1) { + if (fifo_status & 1) { /* FIFO trigger */ fsi_set_mode(FSI_CMD_STOP_ACQ_INT); tasklet_schedule(&fsi_tasklet); } @@ -226,10 +228,10 @@ fsi_lfrm = 1; tasklet_schedule(&fsi_tasklet); } - return 0; + return IRQ_HANDLED; } -int fsi_copy_to_user(struct fsi_read_state *read_state, char *buf) +static int fsi_copy_to_user(struct fsi_read_state *read_state, char *buf) { unsigned int avail_words; @@ -240,7 +242,14 @@ else avail_words = read_state->write_pos - read_state->read_pos; - if (copy_to_user(buf+read_state->word_count*4,read_state->buffer+read_state->read_pos,avail_words*4)) + /* 'buf' is 'char*', but word_count denotes count in array of 'unsigned + * long'. To get proper destination address, we need to multiple it by + * sizeof(unsigned long). + */ + + if (copy_to_user(buf+read_state->word_count*sizeof(unsigned long), + read_state->buffer+read_state->read_pos, + avail_words*sizeof(unsigned long))) return -EFAULT; read_state->word_count += avail_words; @@ -284,10 +293,13 @@ filp->private_data = read_state; -#if 0 +#if 1 /* GPIO61 turns out to be serial power, not fingerchip power. Any other guesses? */ - SET_GPIO(POWER_FP_N, 0); /* power on */ + /* it _IS_ this GPIO. No idea what else it powers, but without it, ATMEL + * chip returns zeroes. */ + //SET_GPIO(POWER_FP_N, 0); /* power on */ + SET_H5400_GPIO(POWER_RS232_N_OR_FS, 0); #endif /* init hardware */ samcop_fsi_up(fsi_); @@ -295,18 +307,19 @@ return 0; } -int fsi_release(struct inode *inode, struct file *filp) +static int fsi_release(struct inode *inode, struct file *filp) { /* put scanner to sleep before we exit */ samcop_fsi_down(fsi_); kfree(filp->private_data); atomic_inc(&fsi_in_use); + SET_H5400_GPIO(POWER_RS232_N_OR_FS, 1); return 0; } -ssize_t fsi_read(struct file *filp, char *buf, size_t count, loff_t *offp) +static ssize_t fsi_read(struct file *filp, char *buf, size_t count, loff_t *offp) { int errval = 0; struct fsi_read_state *read_state; @@ -321,6 +334,7 @@ /* allocate buffer and initialize state */ read_state->buffer_size = fsi_buffer_size; read_state->buffer = kmalloc(read_state->buffer_size,GFP_KERNEL); + read_state->buffer_size = fsi_buffer_size/sizeof(unsigned long); if (read_state->buffer == NULL) return -ENOMEM; @@ -347,6 +361,7 @@ /* gather data */ while (read_state->word_count < read_state->word_dest) { + //printk (KERN_INFO "word_count: %d, word_dest: %d\n", read_state->word_count, read_state->word_dest); interruptible_sleep_on(&fsi_rqueue); if (signal_pending(current)) { errval = -ERESTARTSYS; @@ -380,7 +395,7 @@ return count; } -int fsi_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) +static int fsi_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { struct fsi_read_state *read_state; @@ -474,15 +489,20 @@ return 0; } -void +int fsi_detach(void) { + if (atomic_dec_and_test(&fsi_in_use)) { + atomic_inc(&fsi_in_use); + /* someone is using FSI at the moment, we can't quit */ + return -EBUSY; + } fsi_set_mode(FSI_CMD_STOP_TEMP); del_timer(&fsi_temp_timer); - samcop_fsi_down(fsi_); /* Stop h/w */ free_irq(fsi_->irq, NULL); fsi_ = NULL; misc_deregister(&fsi_miscdev); + return 0; } MODULE_AUTHOR("J°rgen Andreas Michaelsen "); Index: drivers/misc/samcop_fsi.c =================================================================== RCS file: /cvs/linux/kernel26/drivers/misc/samcop_fsi.c,v retrieving revision 1.9 diff -a -u -r1.9 samcop_fsi.c --- drivers/misc/samcop_fsi.c 10 Apr 2006 22:45:16 -0000 1.9 +++ drivers/misc/samcop_fsi.c 14 Aug 2007 20:12:39 -0000 @@ -9,6 +9,7 @@ * */ + #include #include #include @@ -18,24 +19,24 @@ #include #include #include -#include #include -#include +#include #include #include "samcop_fsi.h" static inline void -samcop_fsi_write_register (struct samcop_fsi *fsi, u32 reg, u16 val) +samcop_fsi_write_register (struct samcop_fsi *fsi, u32 reg, u32 val) { - __raw_writew (val, reg + fsi->map); + fsi->fsi_data->write_reg (fsi->me, reg, val); } -static inline u16 +static inline u32 samcop_fsi_read_register (struct samcop_fsi *fsi, u32 reg) { - return __raw_readw (reg + fsi->map); + return fsi->fsi_data->read_reg (fsi->me, reg); } + /* * Helper functions that provide samcop access to the fcd and fsi parts of the * fingerprint scanner @@ -44,6 +45,7 @@ void samcop_fsi_set_control (struct samcop_fsi *fsi, u32 val) { + val &= 0xff; samcop_fsi_write_register (fsi, _SAMCOP_FSI_Control, val); } @@ -100,7 +102,7 @@ /* tell scanner to sleep */ u32 control_register = 0; control_register = samcop_fsi_get_control(fsi); - control_register |= ~SAMCOP_FSI_CONTROL_TEMP_PWR_ON; + control_register &= ~SAMCOP_FSI_CONTROL_TEMP_PWR_ON; // |= was here originally samcop_fsi_set_control(fsi, control_register); /* disable PCLK */ @@ -110,40 +112,69 @@ void samcop_fsi_set_status (struct samcop_fsi *fsi, u32 val) { - samcop_fsi_write_register (fsi, SAMCOP_FSI_STA, val); + samcop_fsi_write_register (fsi, _SAMCOP_FSI_STA, val); } u32 samcop_fsi_get_status (struct samcop_fsi *fsi) { - return samcop_fsi_read_register (fsi, SAMCOP_FSI_STA); + return samcop_fsi_read_register (fsi, _SAMCOP_FSI_STA); } u32 samcop_fsi_read_data (struct samcop_fsi *fsi) { - return samcop_fsi_read_register (fsi, SAMCOP_FSI_DAT); + return samcop_fsi_read_register (fsi, _SAMCOP_FSI_DAT); } static int -samcop_fsi_probe (struct device *dev) +samcop_fsi_probe (struct platform_device *pdev) { int result = 0; struct samcop_fsi *fsi; - struct platform_device *sdev = to_platform_device (dev); fsi = kmalloc (sizeof (*fsi), GFP_KERNEL); if (!fsi) return -ENOMEM; memset (fsi, 0, sizeof (*fsi)); - fsi->parent = dev->parent; - dev->driver_data = fsi; + fsi->parent = pdev->dev.parent; + platform_set_drvdata(pdev, fsi); - fsi->map = (void *)sdev->resource[1].start; - fsi->irq = sdev->resource[2].start; + /* Is this really correct? Some other drivers use this approach, but + * this was already once ioremapped by samcop_base, so we could possibly + * use that mapping and not create new one (approach similar to + * samcop_sdi). + */ + + fsi->map = ioremap(pdev->resource[0].start, + pdev->resource[0].end - pdev->resource[0].start + 1); + fsi->irq = pdev->resource[1].start; + pr_debug("FSI at 0x%p, IRQ %d\n", fsi->map, fsi->irq); + + fsi->clk = clk_get(&pdev->dev, "fsi"); + if (!fsi->clk) { + printk(KERN_ERR "samcop_fsi: Could not get fsi clock"); + iounmap(fsi->map); + kfree(fsi); + result = -EBUSY; + }; + + fsi->fsi_data = pdev->dev.platform_data; + fsi->me = &pdev->dev; +/* + fsi->set_control = samcop_fsi_set_control; + fsi->get_control = samcop_fsi_get_control; + fsi->set_status = samcop_fsi_set_status; + fsi->get_status = samcop_fsi_get_status; + fsi->read_data = samcop_fsi_read_data; + fsi->up = samcop_fsi_up; + fsi->down = samcop_fsi_down; + fsi->set_fifo_control = samcop_fsi_set_fifo_control; + fsi->set_prescaler = samcop_fsi_set_prescaler; + fsi->set_dmc = samcop_fsi_set_dmc; +*/ - fsi->clk = clk_get(dev, "fsi"); if (IS_ERR(fsi->clk)) { printk(KERN_ERR "failed to get fsi clock\n"); kfree (fsi); @@ -154,33 +185,40 @@ printk("couldn't attach fsi driver: error %d\n", result); kfree (fsi); } + return result; } static int -samcop_fsi_remove (struct device *dev) +samcop_fsi_remove (struct platform_device *dev) { - struct samcop_fsi *fsi = dev->driver_data; - fsi_detach(); + struct samcop_fsi *fsi = platform_get_drvdata(dev); + int result = 0; + result = fsi_detach(); + if (result != 0) + return result; + iounmap(fsi->map); kfree (fsi); - return 0; + return result; } static int -samcop_fsi_suspend (struct device *dev, pm_message_t state) +samcop_fsi_suspend (struct platform_device *dev, pm_message_t state) { return 0; } static int -samcop_fsi_resume (struct device *dev) +samcop_fsi_resume (struct platform_device *dev) { return 0; } -struct device_driver samcop_fsi_device_driver = { - .name = "samcop fsi", +struct platform_driver samcop_fsi_device_driver = { + .driver = { + .name = "samcop fsi", + }, .probe = samcop_fsi_probe, .remove = samcop_fsi_remove, .suspend = samcop_fsi_suspend, @@ -189,12 +227,12 @@ static int samcop_fsi_init (void) { - return driver_register (&samcop_fsi_device_driver); + return platform_driver_register (&samcop_fsi_device_driver); } static void samcop_fsi_cleanup (void) { - driver_unregister (&samcop_fsi_device_driver); + platform_driver_unregister (&samcop_fsi_device_driver); } module_init(samcop_fsi_init); Index: drivers/misc/samcop_fsi.h =================================================================== RCS file: /cvs/linux/kernel26/drivers/misc/samcop_fsi.h,v retrieving revision 1.2 diff -a -u -r1.2 samcop_fsi.h --- drivers/misc/samcop_fsi.h 5 Nov 2005 01:09:35 -0000 1.2 +++ drivers/misc/samcop_fsi.h 14 Aug 2007 20:12:39 -0000 @@ -10,14 +10,26 @@ #ifndef _SAMCOP_FSI_H_ #define _SAMCOP_FSI_H_ + +struct samcop_fsi_data { + u32 (*read_reg)(struct device *dev, u32 reg); + void (*write_reg)(struct device *dev, u32 reg, u32 val); +}; + + struct samcop_fsi { struct device *parent; // parent struct for access to // samcop registers + struct device *me; void *map; // fsi register map int irq; // data ready irq struct clk *clk; // samcop fsi clk + + struct samcop_fsi_data *fsi_data; }; + + extern void samcop_fsi_set_control (struct samcop_fsi *fsi, u32 val); extern u32 samcop_fsi_get_control (struct samcop_fsi *fsi); extern void samcop_fsi_set_status (struct samcop_fsi *fsi, u32 val); @@ -29,7 +41,8 @@ extern void samcop_fsi_set_prescaler (struct samcop_fsi *fsi, u32 val); extern void samcop_fsi_set_dmc (struct samcop_fsi *fsi, u32 val); + extern int fsi_attach (struct samcop_fsi *fsi); -extern void fsi_detach (void); +extern int fsi_detach (void); #endif /* _SAMCOP_FSI_H_ */