public inbox for linux-mtd@lists.infradead.org
 help / color / mirror / Atom feed
* Troubles with JFFS2
@ 2005-03-31 17:21 Narinder Kumar
  0 siblings, 0 replies; only message in thread
From: Narinder Kumar @ 2005-03-31 17:21 UTC (permalink / raw)
  To: linux-mtd

[-- Attachment #1: Type: text/plain, Size: 2206 bytes --]

Hi all,

I have written a keypad driver which is a memory mapped device which  
works perfectly fine when teh application and drivers are on NFS rather 
than on JFFS2 filesystem.__ I have already spent two months trying to 
debug it. But even a minimal keypad driver has trouble working together
with JFFS2. I never had any problems on NFS.
    I put my drivers and application onto JFFS2 filesystem and then 
mount that partition and run the application and it runs succesfully but 
when i try to unmount the partitioned just mounted it hangs.  I am using 
timer interrupt in my keypad driver which is running on a JFFS2 
filesystem on DataFlash on AT91RM9200DK on linux-2.4.27-vrs1 (using 
20050304 MTD snapshot)
    I think it is some bug in JFFS2, but I am not sure. Is JFFS2 really 
"production stable" ? I am hereby attaching the code of my Keypad 
Driver  and providing some overview of what the code is doing

INSMOD:
when the keypad driver is loaded into the kernel, the timer interrupt is 
initialized but it does nothing till the point the application tries to 
read from the keypad.

SCAN_KBD ( Timer Interrupt function)
After timer expiry this function is called and it checks for the flag, 
whether it should read from memory mapped device or not ( which is set 
when the application tries to read from keypad) and if its false , it 
just adds the timer again and returns. So when application reads , its 
sets the flag SCHEDULE_OR_NOT to 1 and thereafter the timer interrupt 
actually reads from a memory mapped region where keypad is sitting. Once 
it reads from the memory mapped region , it checks which key was being 
pressed and then ignores the key if the same key is pressed till certain 
timeout ( HZ/5 ).

READ:
Sets the flag SCHEDULE_OR_NOT to 1 so that timer interrupt actually 
starts reading from memory mapped location.

RMMOD:
When the driver is removed from the kernel , it sets a flag CLOSE_TIMER 
to 1 , which is checked by the timer interrupt and it never adds itself 
again if this flag is set., and then it calls del_timer just to check if 
timer is still added it will delete it. and thereby unmap the memory 
mapped region that was being used for keypad.


Narinder



[-- Attachment #2: mail_keypad.c --]
[-- Type: text/x-csrc, Size: 10254 bytes --]

#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <asm/uaccess.h>
#include <asm/mach/map.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include <asm/semaphore.h>

#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>

#include <asm/arch/at91rm9200dk.h>
#include <asm/arch/AT91RM9200_SYS.h>
#include <asm/arch/AT91RM9200.h>
#include <asm/arch/hardware.h>
#include <asm/arch/pio.h>

#include <keypad.h>

static wait_queue_head_t keypad_read_queue;
static struct timer_list keypad_scan_timer;
alignedWord *kpd_cookie;
struct resource *kpd_res;
spinlock_t keypad_lock;
struct semaphore keypad_open_sema;

#define SCANHZ 50 
#define SCAN_JIFF_COUNT (HZ/SCANHZ)
#define KEY_TIMEOUT (10*SCAN_JIFF_COUNT)
#define BUFFER_SIZE 256
volatile unsigned char kpd_key_buffer[BUFFER_SIZE];
volatile int keypad_buff_count,keypad_buff_top,keypad_buff_bottom;
volatile int close_timer;
volatile int schedule_or_not;

#define NO_SCAN_LINES 2
#define NO_DEC_LINES 7
#define NO_KEYS 14

#include <asm/hardware.h>
#define AT91C_KEYPAD_PHYS_BASE     	((unsigned int)0x4FFA0000)
#define AT91C_KEYPAD_SIZE          (0x4FFFFFFF - AT91C_KEYPAD_PHYS_BASE + 1)
static unsigned short kpd_key_table[NO_SCAN_LINES][NO_DEC_LINES];
static unsigned char key_map[NO_KEYS];
static int kpd_curr_cycle;

static int init_keytable(){
        int i,j;
        for (i=0;i<NO_SCAN_LINES;i++)
        {
                for (j=0;j<NO_DEC_LINES;j++)
                {
                        kpd_key_table[i][j]=i*NO_DEC_LINES+j;
                }
        }
        return 0;
}

static void init_keymap(){
        key_map[0]=6;
        key_map[1]=5;
        key_map[2]=4;
        key_map[3]=0;
        key_map[4]=1;
        key_map[5]=2;
        key_map[6]=3;
        key_map[7]=10;          //shift
        key_map[8]=12;          // F2
        key_map[9]=11;          // F1
        key_map[10]=7;
        key_map[11]=8;
        key_map[12]=9;
        key_map[13]=13;         // 
}

int init_keypad_memspace(){
        kpd_cookie=(unsigned int *)ioremap(AT91C_KEYPAD_PHYS_BASE,AT91C_KEYPAD_SIZE);
        if(!kpd_cookie) {
                printk("Unable to map the address space \n");
                return -1;
        }
	kpd_cookie+=8;
        return 0;
}

int exit_keypad_memspace(){
        DPRINTK("Exiting from exit_keypad_memspace \n");
        if(kpd_cookie) {
		kpd_cookie-=8;
                iounmap(kpd_cookie);
        } else {
                DPRINTK(KERN_ERR "region not released");
        }
        return 0;
}

static void init_keypad_port(){
        AT91_SYS->EBI_CSA|=AT91C_EBI_CS3A_SMC;
        AT91_SYS->EBI_CFGR = 0;
        AT91_SYS->EBI_SMC2_CSR[3]=0x220037b7;
}

inline unsigned int read_first_row(){
	unsigned int res=0;
	res = kpd_cookie[0] & 0x7F;
	return res;	
}

inline unsigned int read_second_row(){
	unsigned int res=0;
	res = (kpd_cookie[0]>>16) & 0x7F;
	return res;	
}

void scan_kbd(unsigned long ignore){
	static int last_key=0;
        static int kpd_timeout=0;
      	unsigned short var1=0;
        unsigned short var2=0;
        int pos=0;
        int key;
	unsigned long flags=0;
	int wake_up=0;
     
	if(close_timer){
		return;
	}

	if(!schedule_or_not){
		goto out;
	}

        kpd_timeout+=SCAN_JIFF_COUNT;
        var1=read_first_row();
        var2=read_second_row();
	if(var1){
                pos=0;
                kpd_curr_cycle=0;
                while((pos<(NO_DEC_LINES-1)) && (!((var1>>pos)&0x01))){
                        pos++;
                }
                key=key_map[kpd_key_table[kpd_curr_cycle][pos]];
		if ((last_key==key)&&(kpd_timeout<KEY_TIMEOUT))
			goto next_cycle2;
                kpd_timeout=0;
                last_key=key;
		spin_lock_irqsave(&keypad_lock,flags);
                // Put into buffer
                kpd_key_buffer[keypad_buff_top]=key;
                keypad_buff_top++;
                if (keypad_buff_top >= BUFFER_SIZE)
                        keypad_buff_top=0;

                keypad_buff_count++;
                // Since we have exceeded the buffer size 
                if (keypad_buff_count>BUFFER_SIZE){
                        keypad_buff_count=BUFFER_SIZE;
                        keypad_buff_bottom++;
                        if (keypad_buff_bottom>=BUFFER_SIZE)
                                keypad_buff_bottom=0;
                }
		spin_unlock_irqrestore(&keypad_lock,flags);
		wake_up=1;
	}
next_cycle2:
	if(var2){
                pos=0;
                kpd_curr_cycle=1;
                while((pos<(NO_DEC_LINES-1)) && (!((var2>>pos)&0x01)))
                {
                        pos++;
                }
                key=key_map[kpd_key_table[kpd_curr_cycle][pos]];
                if ((last_key==key)&&(kpd_timeout<KEY_TIMEOUT))
                        goto out;
                kpd_timeout=0;
                last_key=key;
		spin_lock_irqsave(&keypad_lock,flags);
                // Put into buffer 
                kpd_key_buffer[keypad_buff_top]=key;
                keypad_buff_top++;
                if (keypad_buff_top >= BUFFER_SIZE)
                        keypad_buff_top=0;

                keypad_buff_count++;
                // Since we have exceeded the buffer size
                if (keypad_buff_count>BUFFER_SIZE)
                {
                        keypad_buff_count=BUFFER_SIZE;
                        keypad_buff_bottom++;
                        if (keypad_buff_bottom>=BUFFER_SIZE)
                                keypad_buff_bottom=0;
                }
		spin_unlock_irqrestore(&keypad_lock,flags);
		wake_up=1;
	}
out:
       if(wake_up){
                wake_up_interruptible(&keypad_read_queue);
        }
        keypad_scan_timer.expires = jiffies + SCAN_JIFF_COUNT;
        keypad_scan_timer.data = 0;
        keypad_scan_timer.function = scan_kbd;
        add_timer(&keypad_scan_timer);
}

static void init_kbd_timer(){
        init_timer(&keypad_scan_timer);
        keypad_scan_timer.data = 0;
        keypad_scan_timer.function = scan_kbd;
        keypad_scan_timer.expires = jiffies + SCAN_JIFF_COUNT;
        add_timer(&keypad_scan_timer);
}

static void init_kbd_buffer(){
       keypad_buff_count=keypad_buff_top=keypad_buff_bottom=0;
}

static int at91rm9200_keypad_open(struct inode *inode, struct file *filp){
	
        if(down_trylock(&keypad_open_sema)){
                return -EBUSY;
        }
	DPRINTK("Keypad open getting called \n");
	schedule_or_not=1;
	init_kbd_buffer();
        init_keytable();
        init_keymap();
	return 0;
}

static ssize_t at91rm9200_keypad_read(struct file *filp,char *buffer, size_t count, loff_t *ppos){
        int i=0;
	unsigned long flags=0;
        unsigned char data[2];
	memset(data,0,2);
	schedule_or_not=1;
        while(i<count)
        {
                spin_lock_irqsave(&keypad_lock, flags);
                if (keypad_buff_count>0)
                {
                        assert(keypad_buff_bottom < BUFFER_SIZE);
                        data[0]=kpd_key_buffer[keypad_buff_bottom];
                        keypad_buff_bottom++;
                        if (keypad_buff_bottom>=BUFFER_SIZE)
                                keypad_buff_bottom=0;
                        keypad_buff_count--;
                        spin_unlock_irqrestore(&keypad_lock, flags);
                        put_user(data[0], buffer);
			printk("read %d \n",data[0]);
                        buffer++;
                        i++;
                }
                else{
                        /* Sleep */
                        spin_unlock_irqrestore(&keypad_lock, flags);
                        interruptible_sleep_on(&keypad_read_queue);
                        if (signal_pending(current)){
				schedule_or_not=0;
                                return -EINTR;
                        }
                }
        }
	schedule_or_not=0;
        return count;
}

unsigned int at91rm9200_keypad_poll(struct file *filp, poll_table *wait)
{
	unsigned int mask=0;
	unsigned long poll_flags=0;
	spin_lock_irqsave(&keypad_lock, poll_flags);
        if(!(keypad_buff_count>0))
        {
                spin_unlock_irqrestore(&keypad_lock, poll_flags);
                poll_wait(filp,&keypad_read_queue,wait);
                spin_lock_irqsave(&keypad_lock, poll_flags);
                if(!(keypad_buff_count>0))
                {
                        mask = 0;
                        goto out;
                }
        }
        mask |= POLLIN | POLLRDNORM;
out:
        spin_unlock_irqrestore(&keypad_lock, poll_flags);
	return mask;
}

static int at91rm9200_keypad_release(struct inode *inode, struct file *filp)
{
	DPRINTK("Keypad release getting called \n");
	up(&keypad_open_sema);
	return 0;
}

static int at91rm9200_keypad_ioctl(struct inode *inode,struct file *filep,
				unsigned int cmd, unsigned long arg)
{
	unsigned long flags=0;
	switch(cmd){
	case KBD_FLUSH_BUFFER:
		break;
	case KBD_SET_KEYMAP:
		break;
	case KBD_BUFFER_KEYS:
		break;
	case KBD_SCAN:
		break;
	default:
		break;
	}
	return 0;
}


static struct file_operations at91rm9200_keypad_fops = {
	owner:  THIS_MODULE,
	open:   at91rm9200_keypad_open,
	read:  at91rm9200_keypad_read,
	poll: at91rm9200_keypad_poll,
	ioctl: at91rm9200_keypad_ioctl,
	release:at91rm9200_keypad_release,
};

static int __init at91rm9200_keypad_init(void)
{
	int ret;
	init_keypad_port();
	close_timer=0;
	if(init_keypad_memspace()<0){
		return -1;
	}
	spin_lock_init(&keypad_lock);
	sema_init(&keypad_open_sema,1);
	init_waitqueue_head(&keypad_read_queue);

	init_kbd_timer();

	ret = register_chrdev(KBD_DEVICE_MAJOR,KBD_DEVICE_NAME,&at91rm9200_keypad_fops);
	if(ret < 0) {
		printk(KBD_DEVICE_NAME "can't get major number\n");
		exit_keypad_memspace();
		return ret;
	}

	DPRINTK("Keypad initialized \n");
	return 0;
}

static void __exit at91rm9200_keypad_exit(void)
{
	close_timer=1;
	mdelay(100);
	printk("del_timer returned %d \n",del_timer(&keypad_scan_timer));
	exit_keypad_memspace();
	unregister_chrdev(KBD_DEVICE_MAJOR, KBD_DEVICE_NAME);
	DPRINTK("Keypad Uninitialized \n");
}

module_init(at91rm9200_keypad_init);
module_exit(at91rm9200_keypad_exit);

[-- Attachment #3: mail_keypad.h --]
[-- Type: text/x-chdr, Size: 1123 bytes --]

#ifndef _KEYPAD_DRIVER_
#define _KEYPAD_DRIVER_


#include <linux/kernel.h>
#include <linux/spinlock.h>
#include <linux/module.h>


#ifdef _DEBUG_
//#define assert(x) { if (!(x)) { BUG();} }
#define DPRINTK(format, args...) \
printk( format, ##args)
#else
//#define assert(x)
#define DPRINTK(format, args...)        
#endif

#define KBD_DEVICE_NAME	"pap-kbd"
#define KBD_DEVICE_MAJOR 	241	

/** Ioctls. */
#define KBD_BUFFER_KEYS  0x0  	/**< Number of keys in buffer */
#define KBD_FLUSH_BUFFER 0x1 	/**< Flush buffer */
#define KBD_SET_KEYMAP 	 0x2   	/**< Set the keymap */
#define KBD_SCAN 	 0x03	/**< Return the key on top of the queue 
				 *  without dequeing it. 
				 */	

#define KBD_MODE_PRIMARY	0x0
#define KBD_MODE_SECONDARY	0x1
#define KBD_MODE_TERTIARY	0x2

#define SCANHZ 50 
#define SCAN_JIFF_COUNT (HZ/SCANHZ)
#define KEY_TIMEOUT (10*SCAN_JIFF_COUNT)
#define KBD_BH_DATA_SIZE	512

typedef volatile unsigned int alignedWord; 
extern alignedWord *kpd_cookie;
extern unsigned int *kbd_bh_data;
extern struct semaphore kbd_monitor_wait;
extern volatile int kbd_bh_head;
extern volatile int kbd_bh_tail;
#endif

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2005-03-31 17:23 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-03-31 17:21 Troubles with JFFS2 Narinder Kumar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox