Go to previous topic
Go to next topic
Last Post 20 Dec 2004 01:39 PM by  scobb
installable ISR
 23 Replies
Author Messages
mpinton
New Member
New Member
Posts:


--
08 Jun 2004 07:16 AM
    Hi,
    I plan on creating a couple IISRs. The BSP supports this correct?
    Thanks,
    /michel
    mikee@logicpd.com
    New Member
    New Member
    Posts:


    --
    15 Jun 2004 02:30 PM
    Michel,

    Yes, the BSP does support installable ISR's. Give her a go and let us know if you need any more help.

    --mikee
    mpinton
    New Member
    New Member
    Posts:


    --
    15 Jun 2004 02:55 PM
    Awesome.
    I plan on using IISRs for uP_IRQA/B/C/D. There should be no issue with these interrupts?
    /michel
    mpinton
    New Member
    New Member
    Posts:


    --
    18 Jun 2004 02:06 PM
    Hi,
    Is IOCTL_CODES.h (\WINCE420\PLATFORM\LoCE_A400_rel_100\inc) the right place to put my IOCTLs I am going to create to support my own IISR and device drivers? You've got 6 IOCTLs defined in there now.
    I am alittle confused by the comment in that file about which numbers I can use:
    /*
    * Note: the kernel uses IOCTL codes starting with 0x01010000 through
    * 0x01012458 (16,842,752 - 16,852,056). Do NOT conflict with them!
    * Put all platform IOCTL's in this file.
    */

    vs what's in winiotl.h (WINCE420\PUBLIC\COMMON\SDK\INC) which talks about :
    //
    // Macro definition for defining IOCTL and FSCTL function control codes. Note
    // that function codes 0-2047 are reserved for Microsoft Corporation, and
    // 2048-4095 are reserved for customers.
    //

    and:
    //
    // Define the various device type values. Note that values used by Microsoft
    // Corporation are in the range 0-32767, and 32768-65535 are reserved for use
    // by customers.
    //

    TIA,
    /michel
    mikee@logicpd.com
    New Member
    New Member
    Posts:


    --
    18 Jun 2004 02:23 PM
    michel,

    In looking at the file IOCTL_CODES.h, I can see where you would be confused. In fact, that is pretty old code right there. The reason it works is probably more than you are interested in right now. However, a more correct way to declare an IOCTL for yourself would be:

    #define MY_IOCTL CTL_CODE(FILE_DEVICE_HAL, (some unique number), METHOD_BUFFERED, FILE_ANY_ACCESS)

    For instance, I have an IOCTL which allows people to query the boot parameter string which is defined as:

    #define IOCTL_LPD_GET_HAL_PARAM_VALUE \
    CTL_CODE(FILE_DEVICE_HAL,('l'+'p'+'d'+0),METHOD_BUFFERED,FILE_ANY_ACCESS)

    I use the addition of the characters 'l', 'p', and 'd' plus a numeric constant to generate what (I feel fairly confident) will be some unique salt for the CTL_CODE macro.

    If you look in WINCE420\PUBLIC\COMMON\SDK\INC\winioctl.h and D:\WINCE420\PUBLIC\COMMON\OAK\INC\pkfuncs.h, you should be able to figure out what is going on.

    Where you declare these IOCTLs is up to you and IOCTL_CODES.h certainly is a central location. I actually prefer to try and keep definitions as local as possible. So if this is an IOCTL for your driver, for instance one used to communicate between a driver dll and its ISR dll, then I would keep the declaration with the driver. But again, it is completely up to you.

    Hope that helps, write back if it didn't.

    --mikee
    mpinton
    New Member
    New Member
    Posts:


    --
    02 Sep 2004 09:27 AM
    Hi,
    For uP_nIRQA/B/C, which GPIO do these match up with in port F? Do I need to do any interrupt setup for these (like ITENS and Port F GPIO registers)? Or are they all ready to go and use (setup in your OAL code)?

    Thanks,
    /michel
    mpinton
    New Member
    New Member
    Posts:


    --
    15 Sep 2004 07:11 AM
    Hi,
    In my IISR can I address the 7A400 registers directly? Or do I have to map them? The IISR DLL is actually loaded by NK, not Device, right?

    Thanks,
    /michel
    mikee@logicpd.com
    New Member
    New Member
    Posts:


    --
    15 Sep 2004 12:01 PM
    m,

    You can address the registers within your ISR, but you need to be somewhat tricky about it. You are on the right track when you say nk loads the ISR instead of device, but your not quite right. I'll try and explain.

    The installable ISR (call it isr.dll) is going to be loaded by device.exe when it loads the rest of the device driver. However, device.exe is going to insert isr.dll into the kernel's address space. This is important for the following reason.

    Typically, when your code runs, it uses virtual addresses. When you want to access a physical address, such as a hardware register, you need to map that physical address into the virtual address space of the running process. This is easily done by a call to the API function; MmMapIoSpace(). That function maps a physical address into the virtual address space of the calling thread.

    However, isr.dll isn't going to be running within the virtual address space of device.exe like the rest of your driver. It is going to be running within the kernel's address space. So, instead of using MmMapIoSpace() you need to use a different function. The magical API call is TransBusAddrToStatic(). This will map a physical address into the kernel's space. You then pass these memory mapped addresses to isr.dll using the I/O control call, KernelLibIoControl(..., IOCTL_GIISR_INFO, ...).

    Within Platform Builder's help file, check the following topics :

      TransBusAddrToStatic
      Installable ISRs with Drivers
      GIISR_INFO
      KernelLibIoControl


    Also, check out Microsoft's example installable ISR code in:

    x:\WINCE420\PUBLIC\COMMON\OAK\DRIVERS\GIISR

    This is the basic code for an installable ISR. Yours won't need to be quite so general as you probably know what size registers you are accessing, etc.

    Also, a couple of MS's drivers within x:\WINCE420\PUBLIC\Common\Oak\Drivers use an installable ISR as well. I forget which ones right now, but if you do a search for a GIISR_INFO structure, you should be able to find it.

    Hope this helps,
    --mikee
    mpinton
    New Member
    New Member
    Posts:


    --
    13 Oct 2004 07:09 AM
    Hi,
    Well I've got my driver installed and working but my IISRs are failing. As device.exe is going through the list of builtins in the registry as it begins the DLLMain call into the first of my IISRs I am getting an exception (a bad address) - this is in the _preamble_ code prior to my DllMain function.
    Is there anything special to build an IISR (compiler and/or linker options, anything in .bib, anything about any .libs in can or can/not reference, can it use DEBUGMSG macros, etc)?
    TIA,
    /michel
    mikee@logicpd.com
    New Member
    New Member
    Posts:


    --
    13 Oct 2004 09:24 AM
    Nothing that wouldn't be expected.

    Make sure that the sources file that builds the IISR sets:

      WINCEOEM=1
      NOLIBC=1
      NOMIPS16CODE=1


    You can read up what those do in the help file. I will tell you that "NOMIPS16CODE" is the worst naming ever for a variable! It actually has nothing to do with a MIPS processor. Instead, it enables the /QRimplicit-import- compiler flag. This prevents the compiler from importing helper functions. You need this because your IISR will be running in kernel space and you won't be able to "thunk" through to the standard libraries.

    Let me know if that helps,
    --mikee
    mpinton
    New Member
    New Member
    Posts:


    --
    13 Oct 2004 12:13 PM
    OK, I didn't have the NOLIBC and NOMIPS16CODE macros, so I'll add those. You are right, I assumed the NOMIPS16CODE macro had something to do with a MIPS processor so never even thought to investigate what it really was. I'll let you know how it goes.

    Thanks,
    /michel
    mpinton
    New Member
    New Member
    Posts:


    --
    14 Oct 2004 01:07 PM
    Does it matter whether the source code for the IISR DLL is in a ".c" or ".cpp" file - e.g. is there anything out of the normal that I would need to account for if my source is in ".cpp" file and thus using the c++ compiler?

    /michel
    mikee@logicpd.com
    New Member
    New Member
    Posts:


    --
    14 Oct 2004 02:00 PM
    Hmmm,

    Good question. It is quite possible that it needs to be a *.c file. I know that sounds kind of crazy, but I've seen the PB compilers do very strange things before.

    Is there any reason that it needs to be a *.cpp file? If not, I would change it and give it a whirl.

    --mikee
    mpinton
    New Member
    New Member
    Posts:


    --
    14 Oct 2004 02:24 PM
    I can try renaming to ".c" and see what happens.

    In regards to the WINCEOEM, NOLIBC, and NOMIPS16CODE macros, how do I set them in the PB IDE so that they affect (and only affect) the IISR DLLs? I have other driver DLLs that are non-IISR that I would not want affected. I have a separate project for each of them (3), under my platform, in the Features tab they are listed under "User features", and under a master workspace.

    I tried setting them as environment variables in the Custom Build Feature Build step, but that didn't do it. NExt I tried to set hen as environment variables in the Environment tab of the settings for each .pbp file. Neither worked.

    TIA,
    /michel
    mikee@logicpd.com
    New Member
    New Member
    Posts:


    --
    14 Oct 2004 02:31 PM
    Don't try to set that stuff up in the IDE, you will only cause yourself heartache. Just set it up in the 'sources' file of the IISR directory. That way it will only affect code being built in that particular section.

    If you actually created those drivers using PB's visual tools, you are, unfortunately, on your own When you do something like that, PB uses a different build scheme. That's why I do everything using *.cec, sources, and dirs files. That way, I know exactly how the code is being built.

    --mikee
    mpinton
    New Member
    New Member
    Posts:


    --
    14 Oct 2004 02:32 PM
    argh! now you tell me! I have been doing everything in the PB IDE.
    mikee@logicpd.com
    New Member
    New Member
    Posts:


    --
    14 Oct 2004 02:50 PM
    Sorry man,

    The build system was one of, if not the, major item Microsoft was trying to fix with CE 5.0. They have always had serious problems with it.

    The fact is, building something using a *.cec file and a sources file is substantially different than building something using a workspace file. It was explained to me once. Something to do with the fact that originally, CE was always built from the command line using dirs and sources files and the nmake program. Then, when they really started to concentrate on the IDE, they based it on Visual C++ which used some other build mechanism. Thus, the two build systems trying to exist side by side.

    It is all suppossed to be fixed in 5.0 now, but I haven't really checked it out yet, so I'll refrain from any rants or raves.

    Typically, I/we build everything from the command line because the IDE is slow and painful to build with. Most of the other WinCE gurus that I know, including MS's own WinCE development team do so as well.

    Theoretically, both should work. However, as I never use PB's project creator, I can't speak for it. I have learned to not expect too much from PB as a tool, thus I don't push it into anything I don't know that it can handle.

    --mikee
    mpinton
    New Member
    New Member
    Posts:


    --
    27 Oct 2004 02:27 PM
    Hi,
    Well, I am not having much luck with my IISRs. I am failing the call to InterruptIntialize (actually it's something in OEMInterruptEnbable() via the DoInterruptEnable() that's in the SC_InterruptInitialize call) and have no clue why.

    Essentially, I have a device driver DLL that Device.exe is loading, calling it's initialization function. In that init function I configure and setup the IISRs for 3 interrupts (IRQA/B/C).

    Essentially for each, I do a LoadIntChainHandler passing in the IRQ #(I use INTC_GPIO1INTR_BIT, INTC_GPIO2INTR_BIT, INTC_GPIO0FIQ_BIT). This works (at least for the first IRQ). After which I call InterruptInitialize passing in the sysintr #(SYSINTR_IRQB, SYSINTR_IRQC, SYSINTR_IRQA).


    // chain our ISR to the IRQ
    *lphISR = ::LoadIntChainHandler(szNameDLL, szNameHndlr, ucIrq);
    if (!(*lphISR))
    {
    DEBUGMSG(ZONE_ERROR,
    (_T("LNG_Init: LoadIntChainHandler('%s', '%s', '%d') failed %u\r\n"),
    szNameDLL, szNameHndlr, ucIrq));
    return(FALSE);
    }

    // initialze the interrupt (CE's standpoint)
    if (!::InterruptInitialize(dwSysIntr, *lphThreadEvent, 0, 0))
    {
    DEBUGMSG(ZONE_ERROR,
    (_T("LNG_Init: InterruptInitialize('%x') failed\r\n"), dwSysIntr));
    return(FALSE);
    }



    I then create the thread for the IISRT and set it's priority (I never get this far). Any ideas??

    TIA,
    /michel
    mikee@logicpd.com
    New Member
    New Member
    Posts:


    --
    27 Oct 2004 02:44 PM
    Are you obtaining the SysIntr value from the OAL via a call to KernelIoControl() with IOCTL_HAL_REQUEST_SYSINTR?

    Something like so:


    DWORD sys_intr, irq;
    BOOL ret_val;

    irq = /*Whatever hardware IRQ you are hooking. */

    ret_val =
    KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,
    (VOID *)(&irq),
    sizeof(irq),
    (VOID *)(&sys_intr),
    sizeof(sys_intr),
    NULL);

    if ( !ret_val )
    {
    DEBUGMSG("ERROR, COULDN'T GET SYSINTR!");
    goto fail;
    }

    /* Now, install the ISR, passing it the value of the SysIntr
    that it is suppossed to return to the OAL if it detects a
    valid interrupt. */

    /* Now, call InterruptInitialize with the value of SysIntr. */
    InterruptInitialize(sys_intr, ....);


    I ask because a call to InterruptInitialize() would definiately fail if given a bad SysIntr value, or one that that OAL didn't know about yet.

    Also, it appears that you are using C++. Is this true? If it is, I don't think you should. I know it sounds kind of crazy and reactionary, but I wouldn't trust MS's compilers to do the right thing in the case of a driver.

    Maybe you should just have our app's team knock this out for you. I'm sure it would be quick and you could learn from them what they did to get it to work.

    --mikee
    mpinton
    New Member
    New Member
    Posts:


    --
    28 Oct 2004 01:12 PM
    Mike,
    Thanks for the info on having to use the IOCTL_HAL_REQUEST_SYSTINR to get a sysintr assigned for the irq. I have that part working now. And using c++ doesn't seem to hurt.

    I also eventually picked out the correct compiler and linker settings to get the IISR DLLs to build properly in the PB IDE though it was a tedious process.

    I still have some issues though. When I looked at oalintr.h I see the SYSINTR_IRQA/B/C macros assigned. When I call KernelIOControl with the IOCTL_HAL_REQUEST_SYSINTR for the 3 sysintr's I need I get value that are quite different, in my case 0x14 (SYSINTR_ETHER), 0x15 (SYSINTR_AUDIO), and 0x16 (SYSINTR_PCMCIA_STATE). This is for a debug version running KITL. What gives? Or does it not matter, and I just need to make sure that whichever values I received from the IOCTL_HAL_REQUEST_SYSINTR are the ones that the IISRs return when they have a valid interrupt?

    Thanks,
    /michel
    mikee@logicpd.com
    New Member
    New Member
    Posts:


    --
    28 Oct 2004 02:26 PM
    The SysIntr values you get from the OAL are in no way related to the actual IRQ value. If they are the same, it's purely by chance.

    The IRQ values you are seeing in the header file correspond to a hardware IRQ line. They make sense within the physical context of the processor. For instance, on the A40x processors, this value corresponds to the bit number within the Interrupt Controller Register.

    The SysIntr values are logical values assigned at random by the OAL. The OAL associates a hardware IRQ with a logical SysIntr internally. The SysIntr value is registered by the kernel as an event that your IST will wait on. So, your ISR should return the SysIntr value you get from the OAL. The kernel will see this SysIntr value and then wake up your IST so your driver can go about the rest of its work.

    I know it sounds confusing at first, but it is a way of logically seperating interrupt handling from the actual hardware that the kernel is running on.

    So, the short answer to your question is to ignore the SYSINTR_XXX values that you see in oalintr.h and use the values returned from IOCTL_HAL_REQUEST_SYSINTR.

    --mikee
    mpinton
    New Member
    New Member
    Posts:


    --
    05 Nov 2004 12:11 PM
    Hi,
    One more question (yeah right). In my IISR ISRHandler function, to access the physical registers I do the following:

    DWORD dwMemSpace = 1; // i/o space
    PVOID lpGpioRegs; // ptr to GPIO base reg
    PHYSICAL_ADDRESS gpioPhysAddr = {GPIO_BASE, 0}; // GPIO physical address

    // map the physical address into the kernel space (where this IISR is located)
    if (!::TransBusAddrToStatic(Internal,
    0,
    gpioPhysAddr,
    sizeof(GPIOREGS),
    &dwMemSpace,
    &lpGpioRegs))
    {
    return(SYSINTR_CHAIN);
    }
    // make sure we are here validly, must be correct instance and the correct interrupt
    if (!dwInstanceIndex ||
    !(((GPIOREGS*)lpGpioRegs)->intstatus & IN_BASE))
    {
    return(SYSINTR_CHAIN);
    }

    // deassert the interrupt
    ((GPIOREGS*)lpGpioRegs)->gpiofeoi |= IN_BASE;
    return(sdwSysIntr);


    Are the parameters for the TransBusAddrToStatic correct (esp for the bus type and bus #)?
    TIA,
    /michel
    mikee@logicpd.com
    New Member
    New Member
    Posts:


    --
    05 Nov 2004 01:24 PM
    Michel,

    Don't use Internal as the bus-type. I know that it sounds right, and theoretically should work, however, I think that the only valid bus-type for our BSP is ISA. Mainly because I wrote the CEDDK back before Microsoft added the Internal bus-type. We may have fixed it during release 1.0, I can't remember right off the top of my head. Either way, Isa will work the exact same way and I know it is implemented correctly.

    Also, you should call TransBusAddrToStatic() from the driver's main DLL. Then, pass in the appropriately mapped addresses to the IISR via a call to KernelIoctl(). The way you have your code set up right now has you calling that function during every interrupt event which would incur quite a bit of unnecessary overhead. Plus, I'm not sure if you will be able to call that function from a kernel-linked library.

    Try something like:

    During the driver's loading process.

    void
    install_ISR(......)
    {
    LoadIntChainHandler(.....);
    TransBusAddrToStatic(.....);

    /* Fill in some sort of information structure. */
    /* Pass the information structure to the IISR. */
    KernelLibIoControl(&info, IOCTL_GIISR_INFO, ...);

    }


    Inside the Installable ISR's code.

    BOOL
    IOControl(......)
    {
    switch ( ioctl_code )
    {
    case IOCTL_GIISR_INFO:
    /* This input/output control is used when the
    * IST is passing us a filled-in GIISR_INFO
    * structure. This structure includes the value
    * of the SysIntr that we should return, the
    * address of of our hardware port, etc. */
    if ( (sizeof(GIISR_INFO) != len_in) || (!buf_in) )
    {
    /* Invalid size of input buffer or bad input
    * buffer pointer. */
    return (FALSE);
    }
    /* The compiler may generate a memcpy call for
    * a structure assignment. Since we are not
    * linking with the CRT, we use our own copy
    * routine. */
    my_mem_copy(......);
    break;

    .......
    }


    static void
    my_mem_copy(GIISR_INFO *dst, const GIISR_INFO *src)
    {
    size_t count = sizeof(GIISR_INFO);

    while ( count-- )
    *((BYTE *)dst)++ = *((BYTE *)src)++;

    return;
    } /* end my_mem_copy() */



    Regards,
    --mikee
    scobb
    New Member
    New Member
    Posts:


    --
    20 Dec 2004 01:39 PM
    I'm trying to do the same thing (have a driver for IRQC) and am trying to build the foo_driver.dll and foo_isr.dll using eVC++ (not PB) so that we can field upgrade the device.

    Are there any other particular things to worry about in this environment?

    Any good book reference suggestions for CE 4.20 - the whole DLL and ISR world. There is a huge transition between handling ISR's in a RTOS and with CE.

    Cheers,
    Steve


    ---