Dear User Group:

The problem is attached because my E-Mail program
mangles TABS.

Best Regards,

Paul R.


--
Paul Romero

RCOM Communications Software

Phone/Fax: (510)339-2628
E-Mail: [EMAIL PROTECTED]

Dear User Group:

I am using UC Linux version 2.4.27 on an M5249C3 development board
with the 2.4.x kernel, and am having the following problem. Basically,
quick successive GPIO5 interrupts crash my application program.
Any insight would be greatly appreciated.

The driver, which is a loadable module, is essentially an interrupt
handler. When GPIO5 is pulled low it generates an interrupt.
The driver sends SIGUSR2 to the application program to notify it
that a GPIO5 generated interrupt occurred.  When the driver receives
quick successive interrupts, generated by GPIO5, it appears to cause
the application program to crash due to a SIGILL.

I am not sure if there is something stupid missing in the driver
or if there is some application program problem such as SIGUSR2
occurring during a system call or when its signal handler is
executing. 

NOTES: The application program is called hwxd and has a process
ID of 24. The driver is called TRIGGER. 

The stack crash that occurs is as follows. I have not been
able to find a document that aids me in interpretation and
any advice would be appreciated.

hwxd[24] killed because of sig - 4
STACK DUMP:
0x00769adc: 0000000c 00000294 00769af8 2a7c0076 80047077 4e400000 00000000
0x00769af8: 00000000 00769b1c ffffffff ffffffff 007682e4 00000172 0014001c
0x00769b14: dfdc4294 001cdfdc 00769f48 001cde68 00769fa0 00000000 00769f8c
0x00769b30: 00000001 00000000 00000018 00000000 00000000 00000000 00000000
0x00769b4c: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x00769b68: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x00769b84: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x00769ba0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x00769bbc: 00000000 00000000 00000000 00000000 00000000 00000000 00000000
0x00769bd8: 00000000 00000000 00000000 00000000 00000000 00000000 00000000

Format 04  Vector: 0010  PC: 00769aea  Status: 0010    Not tainted
ORIG_D0: ffffffff  D0: ffffffda  A2: 007682e4  A1: 007683ca
A0: 007682e4  D5: 00768004  D4: 00000000
D3: 0050ffa8  D2: 00769faf  D1: ffffffff
USP: 00769adc

The interrupt handler, initialization, and relevant definitions
in the driver are as follows:

/*
 ********************************************************
 * Generic TRIGGER MCF5249 Driver Definitions.
 ********************************************************
 */
/*
 * NOTE: The vendor Makefile device table must have
 * these major and minor numbers.
 */
#define HWX_TRIG_NAME   "TRIGGER"       /* Device name /dev/TRIGGER */
#define HWX_TRIG_MAJOR  254             /* Major Number */
#define HWX_TRIG_MINOR  0               /* Minor Number */

/*
 ********************************************************
 * MCF5249 Secondary Interrupt Controller GPIO Registers
 ********************************************************
 */
/*
 * Interrupt Base Register:  Contains the interrupt base vector.
 * (i.e. Should be 128.)
 */
#define MCF2_INTBASE    ((volatile UCHAR *) (MCF_MBAR2 + 0x16B))
/*
 * Priority 5 Level Register: Contains levels for all priority 5 interrupts.
 */
#define MCF2_INTPRI5    ((volatile ULONG *) (MCF_MBAR2 + MCFSIM2_INTLEVEL5)) 

/*
 ***************************************
 * MCF5249 GPIO Interrupt Registers.
 ***************************************
 */
/*
 * Interrupt Enable Register.
 */
#define MCF2_GPIOINTENABLE      ((volatile ULONG *) (MCF_MBAR2 + 
MCFSIM2_GPIOINTENABLE))
/*
 * Interrupt Clear Register
 */
#define MCF2_GPIOINTCLEAR       ((volatile ULONG *) (MCF_MBAR2 + 
MCFSIM2_GPIOINTCLEAR))
/*
 * Interrupt Status Register.
 */
#define MCF2_GPIOINTSTAT        ((volatile ULONG *) (MCF_MBAR2 + 
MCFSIM2_GPIOINTSTAT))

/*
 *************************************
 * Generic MCF2549 GPIO Registers.
 *************************************
 */
/*
 * Function Select Register 0.
 */
#define MCF2_GPIOFUNC   ((volatile ULONG *) (MCF_MBAR2 + MCFSIM2_GPIOFUNC))

/*
 ************************************
 * TRIGGER INPUT Related Bits and Values.
 ***********************************
 */
/*
 * Interrupt vector per table 9-22 of MCF5249UM
 */
#define GPIO5_INTVECTOR                 37
/*
 * GPIO5 interrupt level bit mask for the  MCF2_INTPRI5 register.
 * Bits 20 - 23 contain the level.
 */
#define TRIG_INT_LEVEL_MASK             0x00F00000
/*
 * GPIO5 Bit for function selection and reading--bit 5.
 */
#define TRIG_GPIO                       0x00000020
/*
 * GPIO5 Bit for interrupt operations--bit 13.
 * Specfific to Hi/Lo transition interrupts.
 */
#define TRIG_INT                        0x00002000

/*
 * GPIO5 Interrupt handler.
 * SIGUSR2 is sent to the registered /dev/TRIGGER user.
 */
ROUTINE static void hwx_trigger_handler(int irq, void *dev_id, struct pt_regs 
*regs)
{
        struct hwx_data *hwx_d = (struct hwx_data *) dev_id;

        /*
         * Verify that the device is configured and
         * interrupt processing is not in progress.
         */
        if(!hwx_d)
          {
                printk(KERN_WARNING "HWX: Unknown Device\n");
                return;
          }
        if(hwx_d->interrupt)
          {
                printk(KERN_WARNING "HWX: Nested Interrupt\n");
                return;
          }

        hwx_d->interrupt = TRUE;
        /*
         * Bit 5--0x20--clears the Low/High interrupt of GPIO5.
         * This is just done for safety.
         */
        *MCF2_GPIOINTCLEAR |= (TRIG_INT | 0x20);

        /*
         * Inform the user of the GPIO5 interrupt.
         */
        if(hwx_d->user_pid != -1)
                kill_proc(hwx_d->user_pid, SIGUSR2, 1);

        hwx_d->interrupt = FALSE;
        return;
}


/*
 * Configure GPIO5 and an input and to generate
 * an interrupt when it is pulled low.
 */
ROUTINE static int hwx_config_int( void )
{
        int rval;
        
        /*
         * Configure GPIO5 to be an input that generates an interrupt.
         */
        *MCF2_GPIOFUNC |= TRIG_GPIO;
        /*
         * Set the IRQ for GPIO5.
         */
        hwx_info.irq = *MCF2_INTBASE + GPIO5_INTVECTOR;
        /*
         * Allocate an IRQ to handle GPIO5 interrupts.
         */
        do {
                rval = request_irq(hwx_info.irq, hwx_trigger_handler,
                                   0, HWX_TRIG_NAME, &hwx_info);
        } while ( rval == -EBUSY );

        if(rval == 0)
          {
                /*
                 * Set the GPIO5 interrupt level to 3, and enable it to
                 * generate an interrupt when it is pulled low.
                 */ 
                *MCF2_INTPRI5 |= (ULONG) ((3 << 20) & TRIG_INT_LEVEL_MASK);
                *MCF2_GPIOINTENABLE |= TRIG_INT;
          }
        else
                printk(KERN_WARNING "HWX: IRQ Allocation Failed. %d\n", rval);

        return(rval);
}


The relevant portions of the application program are as follows:

This is the signal handler and its initialization:

ROUTINE PRIVATE void trigger_handler( int sig )
{

        HWX_Data.h_event = TRUE;
        TRIGGER.event = TRUE;
/*
        signal(SIGUSR2, trigger_handler);
*/
        return;
}

        /*
         * Initialize Basic Data.
         */
        TRIGGER.fd = -1;
        TRIGGER.timeout = FALSE;
        TRIGGER.event = FALSE;
        signal(SIGUSR2, trigger_handler);
        /*
         * Store response characteristics.
         */
        TRIGGER.response = prsp->response;
        TRIGGER.suspend = (long) prsp->suspend;
        /*
         * Assume the driver is already loaded.
         * First open it.
         */
        TRIGGER.fd = open("/dev/TRIGGER", O_RDWR);
        if(TRIGGER.fd < 0)
                rval = UI_ERR_SYS_FILE;
        else
          {
                /*
                * Start the TRIGGER.
                */
                TRIGGER.state = DS_UP;
                HWX_Data.h_active |= HWX_DEV_TRIGGER;
                ioctl(TRIGGER.fd, TRREGISTER, 0);
           }

This is the specific code that executes when SIGUSR2 occurs:
Notes: The software is not configured for suspension and
u_trigger_response() always returns FALSE. Also, the
TRIGGER.state is always DS_UP and TRIGGER.suspend is
always FALSE.


PRIVATE ROUTINE void hwx_service_trigger()
{
        switch(TRIGGER.state)
        {
        case DS_UP:
                break;
        case DS_SUSPEND:
                if(TRIGGER.timeout)
                   {
/*
printf("END SUSPENSION\r\n");
*/
                        TRIGGER.timeout = FALSE;
                        TRIGGER.state = DS_DOWN;
                        HWX_Data.h_active &= ~HWX_DEV_TRIGGER;
                        /*
                         * Restart the TRIGGER.
                         */
                        if(hwx_start_trigger())
                          {
                                /*
                                 * Send a message to the Master Process
                                 * indicating the TRIGGER failed.
                                 */
                                hwx_send_event(HWX_D_TRIGGER, UI_PM_HWX_FAULT, 
UI_ERR_HARDWARE, 0);
                          }
                  }
                return;
                break;
        default:
                UI_PUT_BUG("hwx_service_trigger: Bad State %d", TRIGGER.state);
                hwx_exit();
        }

        if(TRIGGER.event != TRUE)
                return;
        TRIGGER.event = FALSE;
        /*
         * Suspend operation of the device if necessary.
         */
        if(TRIGGER.suspend)
          {
/*
printf("START SUSPENSION\r\n");
*/
                ftimer_stop(&TRIGGER.timeout);
                TRIGGER.state = DS_SUSPEND;
                close(TRIGGER.fd);
                TRIGGER.fd = -1;
                ftimer_start(TRIGGER.suspend, &TRIGGER.timeout);
          }
        /*
         * In all cases send a notifcation message
         * to the Master Process.
         */
        if(u_trigger_response(TRIGGER.response) != TRUE)
          {
/*
printf("TRIGGER\n");
*/
                hwx_send_event(HWX_D_TRIGGER, UI_PM_HWX_TRIGGER, 0, 
TRIGGER.response);
          }
        return;
}

/*
 * Send a response message to the peer process.
 */
ROUTINE PRIVATE void hwx_send_event(int dev_id, int type, int data, UCHAR 
action)
{
        msgbuf_t msg;

        msg.mtype = type;

        msg.mdata.u_hwx_evt.h_no = UI_HWX_PEER;
        msg.mdata.u_hwx_evt.h_channel_no = HWX_Data.h_ch_no;
        msg.mdata.u_hwx_evt.h_device_id = dev_id;
        msg.mdata.u_hwx_evt.h_pid = HWX_Data.h_pid;

        msg.mdata.u_hwx_evt.h_data = data;
        msg.mdata.u_hwx_evt.h_response = action;

printf("S1\r\n");
fflush(stdout);
        if(UI_TX_PEER_MSG(HWX_Data.h_parent_rxq, HWX_Data.h_parent_pid,
                           &msg, sizeof(ui_hwx_event_t)) )
                hwx_exit();
printf("S2\r\n");
fflush(stdout);


#ifdef EVDEB
UI_PUT_DEBUG("HWX[%d]: Tx. Peer MSG = %d State = %d\n",
 HWX_Data.h_ch_no, msg.mtype, HWX_Data.h_state);
#endif /* EVDEB */


        return;
}

/*
 * Description: UI_TX_PEER_MSG() sends
 * an IPC message to a peer process in blocking mode.
 *
 * Arguments:
 *
 *      q: The IPC input queue of the target process.
 *
 *      pid: The Unix/Linux style PID of the target process.
 *
 *
 *      msg: Points to an allocated structure containing
 *      the formatted message.
 *
 *      data_size: The size of the data part of the message.
 *
 * Return Value:
 *
 *      0 is returned upon success and -1 otherwise.
 *
 * External Data.
 *
 *      None.
 *
 * Notes:
 *
 *      The caller can be suspended from execution for
 *      a substantial period when using this routine.
 *
 *      Using the SYSV IPC message exchange mechanism
 *      and routines such as msgget() is Unix/Linux
 *      specific and requires a system that incoporates
 *      ATT SYSV extensions.
 */
ROUTINE int UI_TX_PEER_MSG(int q, pid_t pid, msgbuf_t *pmsg, int data_size)
{
        int rval = 0;

        int k = 0;
        for(;;)
          {
                if(msgsnd(q, (void *) pmsg, data_size, 0) != 0)
                   {
        
                        if(errno == EINTR)
                          {
                                if(k++ < 3)
                                        continue;
                          }
        
                        UI_PUT_ERROR("Can't send IPC message. Errno = %d", 
errno);
                        rval = -1;
                        break;
                   }
                else
                  {
                        /*
                         * UNIX STYLE: Wake up peer process.
                         */
                        kill(pid, SIGIO);
                        break;
                  }
          }

        return(rval);
}

This is the code in the path to the SIGUSR2 specific code:

/*
 * The arguments passed to the process are as follows:
 *
 * 0) The process name - unused.
 *
 * 1) Unix style process ID of the "master" UI process.
 *
 * 2) The message input queue of the "master" UI process.
 *
 * 3) The message input queue of this process.
 */
main(int argc, char *argv[])
{
        msgbuf_t msg;
        char *name;
        int r;

        /*
         * Protect against spurious SIGILL signals.
         * This KLUDGE is necessary for the MC 5249
         * implementation of UC Linux.
         */
        signal(SIGILL, SIG_IGN);
#define NO_STDERR
#ifdef NO_STDERR
        /*
         * KLUDGE: Disable stderr to avoid unexpected
         * diagnostics during normal operation.
         */
        freopen("/dev/null", "w+", stderr);
#endif /* NO_STDERR */

        /*
         * Initialize the process.
         */
        hwx_init();
        /*
         * Validate the arguments and save them.
         */
        if(argc != 4)
          {
                UI_PUT_BUG("HWX: Bad Arguments");
                hwx_exit();
          }

        name = argv[0];
        HWX_Data.h_parent_pid = atoi(argv[1]);
        HWX_Data.h_parent_rxq = atoi(argv[2]);
        HWX_Data.h_rxq = atoi(argv[3]);

        UI_PUT_DEBUG("%s Starting PID = %d", name, getpid());

        /*
         * Initialize the process ID and state.
         */
        HWX_Data.h_pid = getpid();
        HWX_Data.h_state = HWX_PI_UP;
        /*
         * Send the "master" UI process a message to inform it that
         * this process has begun executing.
         */
        msg.mtype = UI_PM_UP;
        msg.mdata.u_peer_proto.p_no = UI_HWX_PEER;
        msg.mdata.u_peer_proto.p_pid = HWX_Data.h_pid;
        r = UI_TX_PEER_MSG(HWX_Data.h_parent_rxq, HWX_Data.h_parent_pid,
                           &msg, sizeof(ui_peer_proto_t));
        if(r < 0)
          {
                hwx_exit();
          }
        /*
         * Do the handshake protocol exchange with the "master" UI process.
         */
        if(hwx_parent_ready(HWX_Data.h_parent_rxq, HWX_Data.h_rxq) != TRUE)
          {
                UI_PUT_BUG("HWX: Invalid Parent Ack");
                hwx_exit();
          }
        /*
         * Ready for normal execution: Put all channels in ready state.
         *
         * There are 3 possible sources of input events.
         *
         * 1) IPC message from main peer.
         * 2) On board Coldfire ADC
         * 3) Coldfire TRIGGER input.
         *
         * In addition the Coldfire STATE inputs can be monitored.
         *
         * Also, initialize the timers now that the handshake is complete.
         */
        HWX_Data.h_state = HWX_PI_READY;
        HWX_Data.h_ch_state = HWX_CH_READY;
        /*
         * Initialize the event waiting mechanism.
         */
        ftimer_init();
        HWX_INIT_WAIT_EVENT();
        for(;;)
          {
                /*
                 * Wait for an event.
                 */
                HWX_WAIT_EVENT();

                /*
                 * Service hardware events.
                 */
                hwx_device_events();
                /*
                 * Service  IPC messages
                 */
                hwx_peer_events();
          }

}

/*
 * Description: HWX_WAIT_EVENT() causes this process to be suspended
 * from execution until either an IPC message reception
 * event occurs.
 *
 * Arguments:
 *
 *      None.
 *
 * Return Value:
 *
 *      None.
 *
 * External Data.
 *
 *      HWX_Data. The system wide process descriptor for this process.
 *
 * Notes:
 *
 * The pause() is purely for minimizing CPU usage.
 * The h_event flag is set to TRUE when any of the following signals
 * are received, and their significance is as follows:
 *
 * SIGIO: Arrival of an IPC message.
 * SIGALRM: Timer expiration.
 * SIGUSR1: ADC sample.
 * SIGUSR2: TRIGGER event.
 */
ROUTINE void HWX_WAIT_EVENT()
{
        int monitor;
        /*
         * The pause() is purely for minimizing CPU usage.
         * It is not necessesarily portable. It causes
         * this process to be suspended from execution
         * until one of the aforementioned signals is
         * received by this process. If a STATE input is
         * being monitored the pause() does not occur
         * because they don't generate signals.
         */
        monitor =  HWX_Data.h_active & (HWX_DEV_STATE1 | HWX_DEV_STATE2);
#ifdef CONSERVE_CPU
        if(monitor)
          {
                /*
                 * At least one STATE input is active.
                 * If it is suspended or the scheduling timer is running,
                 * wait for a timer expiration.
                 */
                if(HWX_Data.h_monitor_wait)
                        monitor = FALSE;
          }
#endif /* CONSERVE_CPU*/

        if( !(HWX_Data.h_event | monitor) )
                pause();

        HWX_Data.h_event = FALSE;

        return;
}

PRIVATE ROUTINE void hwx_device_events()
{
        if(HWX_Data.h_active & HWX_DEV_TRIGGER)
                hwx_service_trigger();

        if(HWX_Data.h_active & HWX_DEV_ADC)
                hwx_service_adc();

#ifdef CONSERVE_CPU
        /*
         * Manage the STATE input scheduling timer.
         */
        if(HWX_Data.h_monitor_wait & M_SCHEDULE)
          {
                HWX_Data.h_monitor_wait &= ~M_SCHEDULE;
                ftimer_stop(&HWX_Data.h_monitor_timeout);
          }
        HWX_Data.h_monitor_timeout = FALSE;
#endif /* CONSERVE_CPU*/

        if(HWX_Data.h_active & HWX_DEV_STATE1)
                hwx_service_state(HWX_D_STATE1);

        if(HWX_Data.h_active & HWX_DEV_STATE2)
                hwx_service_state(HWX_D_STATE2);
}

This is the boot information displayed when UC Linux comes up:

üüLinux version 2.4.27-uc1 ([EMAIL PROTECTED]) (gcc version 2.95.3 20010315 
(release)(ColdFire patches - 20010318 from http://fiddes.net/coldfire/)(uClinux 
XIP and shared lib patches from http://www.snapgear.com/)) #1848 Wed May 28 
15:50:09 PDT 2008
uClinux/COLDFIRE(m5249)
COLDFIRE port done by Greg Ungerer, [EMAIL PROTECTED]
Flat model support (C) 1998,1999 Kenneth Albanowski, D. Jeff Dionne
On node 0 totalpages: 2048
zone(0): 0 pages.
zone(1): 2048 pages.
zone(2): 0 pages.
Kernel command line: mtdparts=physmap:1344k(flash1),704k(flash2)
Bad boy: ColdFire Timer (at 0x00022f50) called request_irq without a dev_id!
Calibrating delay loop... 92.36 BogoMIPS
Memory available: 4792k/8192k RAM, 0k/0k ROM (970k kernel code, 229k data)
kmem_create: Forcing size word alignment - vm_area_struct
kmem_create: Forcing size word alignment - mm_struct
kmem_create: Forcing size word alignment - filp
Dentry cache hash table entries: 1024 (order: 1, 8192 bytes)
Inode cache hash table entries: 512 (order: 0, 4096 bytes)
kmem_create: Forcing size word alignment - inode_cache
Mount cache hash table entries: 512 (order: 0, 4096 bytes)
kmem_create: Forcing size word alignment - bdev_cache
kmem_create: Forcing size word alignment - cdev_cache
kmem_create: Forcing size word alignment - kiobuf
Buffer cache hash table entries: 1024 (order: 0, 4096 bytes)
Page-cache hash table entries: 2048 (order: 1, 8192 bytes)
POSIX conformance testing by UNIFIX
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
kmem_create: Forcing size word alignment - sock
Initializing RT netlink socket
Starting kswapd
kmem_create: Forcing size word alignment - file_lock_cache
kmem_create: Forcing size word alignment - nfs_read_data
kmem_create: Forcing size word alignment - nfs_write_data
JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.
ColdFire internal UART serial driver version 1.00
ttyS0 at 0x100001c0 (irq = 73) is a builtin ColdFire UART
ttyS1 at 0x10000200 (irq = 74) is a builtin ColdFire UART
kmem_create: Forcing size word alignment - blkdev_requests
SLIP: version 0.8.4-NET3.019-NEWTTY (dynamic channels, max=256).
CSLIP: code copyright 1989 Regents of the University of California.
Blkmem copyright 1998,1999 D. Jeff Dionne
Blkmem copyright 1998 Kenneth Albanowski
Blkmem 1 disk images:
0: 14C12C-33712B [VIRTUAL 14C12C-33712B] (RO)
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
PPP generic driver version 2.4.2
PPP MPPE compression module registered
physmap flash device: 200000 at ffe00000
 Amd/Fujitsu Extended Query Table v1.0 at 0x0040
number of CFI chips: 1
cfi_cmdset_0002: Disabling fast programming due to code brokenness.
mtd: Giving out device 0 to Physically mapped flash
DEBUG-CMDLINE-PART: parts=0x37d920 *num_parts=0x2
DEBUG-CMDLINE-PART: ext. name
DEBUG-CMDLINE-PART: partition 1: name <flash2>, offset 0, size b0000, mask 
flags 0
DEBUG-CMDLINE-PART: ext. name
DEBUG-CMDLINE-PART: partition 0: name <flash1>, offset 0, size 150000, mask 
flags 0
DEBUG-CMDLINE-PART: mtdid=<physmap> num_parts=<2>
physmap: Using Command Line partition definition
Creating 2 MTD partitions on "Physically mapped flash":
0x00000000-0x00150000 : "flash1"
mtd: Giving out device 1 to flash1
0x00150000-0x00200000 : "flash2"
mtd: Giving out device 2 to flash2
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP
kmem_create: Forcing size word alignment - ip_dst_cache
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 512 bind 512)
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
VFS: Mounted root (romfs filesystem) readonly.
Freeing unused kernel memory: 24k freed (0x130000 - 0x135000)
mtdblock_open
ok

mui: STDERR UP
*** ACTUATE INITIALIZED ****
* PEERNAME = hwxd

Using /lib/modules/2.4.27-uc1/kernel/trigger/trigger.o
Using /lib/modules/2.4.27-uc1/kernel/adc/adc.o
* hwxd Starting PID = 24

Note: hwxd is the application program and the process ID is 24.

_______________________________________________
uClinux-dev mailing list
uClinux-dev@uclinux.org
http://mailman.uclinux.org/mailman/listinfo/uclinux-dev
This message was resent by uclinux-dev@uclinux.org
To unsubscribe see:
http://mailman.uclinux.org/mailman/options/uclinux-dev

Reply via email to