From: Narinder Kumar <narinder@kritikalsolutions.com>
To: linux-mtd@lists.infradead.org
Subject: Troubles with JFFS2
Date: Thu, 31 Mar 2005 22:51:25 +0530 [thread overview]
Message-ID: <424C3195.50308@kritikalsolutions.com> (raw)
[-- 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
reply other threads:[~2005-03-31 17:23 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=424C3195.50308@kritikalsolutions.com \
--to=narinder@kritikalsolutions.com \
--cc=linux-mtd@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox