Wince-Driven Development Learning

Source: Internet
Author: User

1. Register usage:

1, WinCEInternal access to physical addresses:

There are three possible ways.

1: directly use the virtual address corresponding to the physical address defined by g_oaladdresstable (oemaddrtab_cfg.inc.

For example:

DCD 0x80000000, 0x30000000,128;

The virtual address 0x80000000 is actually the physical address 0x30000000.

 

2: On the oal layer, use the oalpatova function.

For example:

Volatile s3c2410x_ioport_reg * pioctr;

Pioctr = (volatile s3c2410x_ioport_reg *) oalpatova (s3c2410x_base_reg_pa_ioport, false );

Then, when accessing the first address pointed to by pioctr, it is actually the physical address defined by s3c2410x_base_reg_pa_ioport after the access is mapped.

VOID* OALPAtoVA( 
Uint32Pa,Parameter 1: physical address to be mapped
BoolCachedParameter 2: whether to use cache (Uncached must be used in the driver)

)

 

3: Use the mmmapiospace function in the kernel.

For example:

Pbaseaddress = (puchar) mmmapiospace (iophysicalbase, size, false );

Same as above, accessing the point address of pbaseaddress is the physical address defined by iophysicalbase after the access is mapped.

PVOID MmMapIoSpace( 
Physical_addressPhysicaladdress,Parameter 1: physical address to be mapped
Ulong Numberofbytes,Parameter 2: ing address Length
BooleanCacheenableParameter 3: whether to use cache (Uncached must be used in the driver)

);

Unlike oalpatova, mmunmapiospace must be used after mmmapiospace is used.

  VOID MmUnmapIoSpace( 
PvoidBaseaddress,Parameter 1: Virtual Address mapped
Ulong NumberofbytesParameter 2:Ing address Length

);

 

In general NKDriver writing. Do not directly use g_oaladdresstable to standardize the programming style.. Unified use of mmmapiospace, MmunmapiospaceFunction.

 

2, WinCEStandard Register Access

Defines a struct. This structure contains the Register address of a function module.

For example:

Typedef struct {

Uint32 gpacon; // port a-offset 0

Uint32 gpadat; // data

Uint32 pad1 [2];

......

......

Uint32 gstatus0; // external pin status

Uint32 gstatus1; // chip ID

Uint32 gstatus2; // reset status

Uint32 gstatus3; // inform register

Uint32 gstatus4; // inform register

} S3c2410x_ioport_reg, * ps3c2410x_ioport_reg;

 

Volatile s3c2410x_ioport_reg * pioctr;

Pioctr = (volatile s3c2410x_ioport_reg *) oalpatova (s3c2410x_base_reg_pa_ioport, false );

In this way, access to each member of pioctr is the physical offset address defined by the s3c24ing of the access to s3c2410x_base_reg_pa_ioport.

 

To unify and be compatible with the driver code of the platform, we have added the Register operation macro (oal_io.h ):

# Define reg8 (_ register _) (* (volatile unsigned char *) (_ register _))

# Define reg16 (_ register _) (* (volatile unsigned short *) (_ register _))

# Define reg32 (_ register _) (* (volatile unsigned long *) (_ register _))

The function register in the access module is added with an offset address.

# Define usb_reg_faddr_offset (0x0000)

# Define usb_reg_power_offset (0x0001)

Example:

To write a module driver, first use mmmapiospace or oalpatova to establish a physical address ing relationship.

Volatile byte * pusbctrladdr;

Pusbctrladdr = (volatile byte *) oalpatova (ak3224_base_reg_pa_usb, false );

In this way, the first address of the USB Module is the point address of pusbctrladdr. Then, use the regxx macro to access each function register.

Reg8 (pusbctrladdr + usb_reg_power_offset) = usb_power_ensuspend;

Ucintstatusr = reg16 (pusbctrladdr + usb_reg_intrrx1_offset );

Reg32 (pusbctrladdr + usb_dma_count_1_offset) = 256;

Use regxx.

 

Ii. DMAUse

1, Chip DMAUsage tips:

In the dma use of the ak3224 chip, the RAM address must be 4-byte aligned as the target address and Source Address of the DMA transmission. In addition, the RAM address within the DMA Operation length must be consecutive.

However, we found that when the RAM address in the nandflash driver is used as the target address, only two bytes of alignment is required. The RAM address as the source address does not need to be aligned.(Verification is required in other cases)

 

2, WinCEDMA inUsage:

According to the continuous feature of the RAM address for one DMA Operation, when driving DMA, we need to ensure that the physical address mapped to the virtual address is continuous. There are three ways:

 

1: The data zone address is transmitted by the application layer or other processes or threads. the driver does not know whether the physical address corresponding to the virtual address is continuous.

Because the memory application of Wince uses 4 K bytes as a page, the memory application of a piece of data may span multiple pages. Therefore, as long as the length of the data area is greater than 1 byte, it is possible that the physical address is not consecutive. To ensure the DMA Operation, We must query the physical distribution of the data zone on Ram.

 

First, obtain the virtual page of the Data zone.

Virpagestart = (ulong) psourcebuffer & 0xfffff000;

 

Second, get the offset address of the data area on the page.

Offset = (ulong) psourcebuffer & 0x0fff;

 

Whether the computing data area spans the page segment

If (Offset + numberofbytes> 4096)

Pagesize = wce_uniform_size-offset; // the whole data spans this page, the DMA transmission needs to be divided into multiple parts, one page segment at a time

Else

Pagesize = numberofbytes; // The data area does not span pages.

 

Query the mapped physical address from the obtained page address.

If (! Lockpages (lpvoid) virpagestart, 4096, & transaddr, lockflag_read ))

{

// Exception Handling

}

Unlockpages (lpvoid) virpagestart, 4096 );

 

After obtaining the ing physical address transaddr, perform further processing based on Whether Ram is the target address or the source address.

 

Assume that a data zone is used as the DMA source address and the size is 9 KB. The offset on the home page of the virtual address is 4 K. Therefore, it must span three page segments.

 

 

 

 

 

 

, We need to break down the DMA Operation three times.

First, query the physical address sent on the first page and 2 k Data on the first page. Then, query the physical address on the second page and send 4 K data. Finally, query the physical address on the third page and send 3 K data.

 

 

2: You can use the allocphysmem function to apply for a data zone.

LPVOID AllocPhysMem( 
DWORDCbsize,Parameter 1: Data Partition size
DWORDFdwprotect,Parameter 2: Protection tag
DWORDDwalignmentmask,Parameter 3: 0 (default system)
DWORDDwflags,Parameter 4: 0 (reserved for ure use)
PulongPphysicaladdressParameter 5: Obtain the physical address of the Data zone.

);

The returned value of the allocphysmem function is the requested virtual address pointer.

For example:

Pserialhead-> rxbufferinfo. rxcharbuffer = // alloc physical memory

Allocphysmem (pserialhead-> rxbufferinfo. Length + 16, page_readwrite, 0, 0, & rx_phyaddr );

Because this function must apply for a consecutive physical address, pserialhead-> rxbufferinfo. rxcharbuffer does not need to be used to query whether multiple page segments are crossed.

 

However, allocphysmemThe physical address requested by the function may span multiple RAM chips.. ThereforeMulti-chip RAMIn the chip system, you still need to query whether the chip.

AllocphysmemFreephysmem must be used after the function is used.Function.

 

 

3: In the system config. bib file, you can pre-define a contiguous, non-Cross-chip RAM space.

As follows, the system retains a segment of RAM with the virtual address starting from 0x80024000.

Ser_dma 80024000 00003000 Reserved

 

When the DMA driver is in use, you no longer need to perform any query operations on the memory. We only need to map in the process space.

Pserialhead-> rxbufferinfo. rxcharbuffer = virtualalloc (0, rx_physize,

Mem_reserve, page_noaccess );

If (pserialhead-> rxbufferinfo. rxcharbuffer = NULL)

{

Debugmsg (zone_error, (text ("com_init: virtualalloc failed! /R/N ")));

Return (null );

}

Else

{

If (! Virtualcopy (pvoid) pserialhead-> rxbufferinfo. rxcharbuffer, (pvoid) (rx_phyaddr ),

Rx_physize, (page_readwrite | page_nocache )))

{

Debugmsg (zone_error, (text ("com_init: virtualcopy failed! /R/N ")));

Return (null );

}

}

In the above section, we first use the virtualalloc function to apply for a reserved virtual address space in the process space. Use virtualcopy to map the physical address space to the applied virtual address.Function is requiredVirtualfreeRelease.

 

Lpvoid Virtualalloc (

  LPVOID lpAddress,                   
  DWORD dwSize,  
  DWORD flAllocationType,  
  DWORD flProtect  

);

 

BOOL VirtualCopy(  
  LPVOID lpvDest,  
  LPVOID lpvSrc,  
  DWORD cbSize,  
  DWORD fdwProtect  

);

 

BOOL VirtualFree( 
  LPVOID lpAddress,  
  DWORD dwSize,  
  DWORD dwFreeType  

);

For more information, see msdn.

 

Iii. interrupted use

1, WinCEBrief Introduction

1: ISR Concept
ISR (interrupt service routine) is a program that processes irqs (interrupt request line. Windows CE uses an ISR to process all IRQ requests. When an interrupt occurs, the kernel exception handler first calls the kernel ISR, the kernel ISR disables all interrupts with the same priority and lower priority, and then calls the registered oal ISR program, ISR has the following features:

1) execute the minimum interrupt processing. The minimum Interrupt Processing refers to the hardware that can test and reply to interrupt, and leave more processing work to the IST (interrupt service thread ).

2) return the interrupt ID when ISR is complete (most of the interrupt IDs are predefined ).

2: interrupted registration steps

1) Use the setup_interrupt_map macro to associate sysintr and IRQ. Constants prefixed with "sysintr _" are used by the kernel to uniquely identify the interrupted hardware. Some sysintr is pre-defined in the nkintr. h file. OEMs Can Customize sysintr in the oalintr. h file.

2) use the hookinterrupt function to associate the hardware interrupt number and ISR. The hardware interrupt number is the physical interrupt number, not the logical interrupt number IRQ.

 

2, Driving istUse

ISR is the smallest interrupt processing function, so the interrupt processing function of each driver is called ist.

The system retains 16 virtual interrupt numbers. ak3224_intr.h has defined 28 virtual interrupt numbers for each ISR. Therefore, the interrupt processing function in the driver only needs to map to the defined 28 virtual interrupts.

 

Example:

First, create an event

Pgpioinfo-> hgpioevent1 = createevent (0, false, false, null );

 

Next, create a thread for event processing (IST)

Pgpioinfo-> hgpiothread1 = createthread (null, 0, gpiofuncthread1,

Pgpioinfo, 0, null );

Use interruptinitialize to hook the virtual interrupt number pgpioinfo-> dwintid1 with the created event pgpioinfo-> hgpioevent1.

Interruptinitialize (pgpioinfo-> dwintid1, pgpioinfo-> hgpioevent1, null, 0)

 

When the gpio interrupt arrives, the pgpioinfo-> hgpioevent1 event linked to the gpio virtual interrupt will be set to active. Thread pgpioinfo-> hgpiothread1 statement

Waitforsingleobject (pgpioinfo-> hgpioevent1, infinite );

Gpioeventhandler1;

Then, the system is awakened and the next command is executed. The added function gpioeventhandler1 is executed.

 

After the interrupt processing is completed, you must use

Interruptdone (pgpioinfo-> dwintid1 );

The notification system has completed the interrupt processing, so the next interruption will be set to active again after the event pgpioinfo-> hgpioevent1.

 

When the driver is detached, the application events and threads need to be released.

Closehandle (pgpioinfo-> hgpioevent1 );

Closehandle (pgpioinfo-> hgpiothread1 );

 

3Supports ISR installation.Introduction

The OEM associates IRQ and sysintr with the oeminit function. When the hardware device is interrupted, the ISR will disable the same-level and low-level interruptions, and then return the associated sysintr Based on IRQ, the kernel wakes up the corresponding ist Based on sysintr returned by ISR (sysintr is associated with the event created by ist). After the IST process is interrupted, it calls interruptdone to cancel the interruption prohibition. The disadvantage of the association in oeminit is that once the CE kernel is compiled, this association cannot be added, and some hardware devices may be plugged in or out at any time or share interruption, to associate such a hardware device, you can install ISR to handle the interruption caused by a specified hardware device, therefore, if the hardware device needs to install ISR, you must add isrdll and isrhandler to the Registry. Most hardware devices use CE's default installable ISR giisr. dll in the following format:

"Isrdll" = "giisr. dll"
"Isrhandler" = "isrhandler"

 

If a hardware driver needs to be able to install ISR, and developers do not want to write one themselves, they can use giisr. dll. In addition to adding the above in the registry, you also need to call the relevant function registration in the driver to install ISR. As follows:

G_isrhandle = loadintchainhandler (isrdll, isrhandler, (byte) IRQ );
Giisr_info Info;
Info. sysintr = dwsysintr;
Info. checkport = true;
Info. portisio = (dwiospace )? True: false;
Info. usemaskreg = true;
Info. portaddr = physaddr + 0x0c;
Info. portsize = sizeof (DWORD );
Info. maskaddr = physaddr + 0x10;
Kernellibiocontrol (g_isrhandle, ioctl_giisr_info, & info, sizeof (Info), null, 0, null );

 

The loadintchainhandler function registers the installable ISR. Parameter 1 is the DLL name, parameter 2 is the ISR function name, and parameter 3 is IRQ.

If you want to use giisr. dll as the installable ISR, you must first fill in the giisr_info structure. checkport = true indicates that giisr needs to check the specified register to determine whether the current interrupt is the device.

Portisio indicates the address space where the Register address belongs, false indicates the inner space, and true indicates the IO space.

Usemaskreg = true indicates that the device has a mask register dedicated to specifying whether the current device is an interrupt source, that is, sending an interrupt

Maskaddr indicates the address of the mask register.

For info. if the mask value is assigned, portaddr indicates a special register address. If the value of this register is true with the value of mask & the result of the operation, it indicates that the current device is the interrupt source, otherwise, the system returns sysintr_chain (indicating that the current ISR is not interrupted and the kernel will call the next ISR In the ISR chain). If usemaskreg is set to true, if the value of the maskreg register and the value of the Register specified by portaddr are true, the current device is the source of interruption.

 

It can be seen that it is very convenient to install ISR to handle the interruptions with the re-decomposition.However, a virtual interrupt number must be used. The virtual interrupt Number of the entire system is only64.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.