# Include <ASM/Param. h> # Include <Linux/Timer. h> Void add_timer (struct timer_list * timer ); Int del_timer (struct timer_list * timer ); Inline void init_timer (struct timer_list * timer ); Struct timer_list is defined: Struct timer_list { Struct timer_list * next; Struct timer_list * Prev; Unsigned long expires; Unsigned long data; Void (* function) (unsigned long d ); }; Expires indicates the time when the function is to be executed. The system core has a global variable jiffies Indicates the current time. When add_timer is called, jiffies = jiffies + num indicates that Run the function after the minimum system interval. The minimum system interval is related to the hardware platform used, In the core, constant Hz is defined to indicate the number of minimum time intervals in one second, and num * Hz is used to indicate num. Seconds. The system calls the function at the scheduled time and deletes this subroutine from the scheduled queue, Therefore, if you want to execute the function at intervals, you must call the function again. Use add_timer. Function parameter D is the data item in timer. Sometimes the driver needs a very short delay to synchronize with the hardware. In this case, the jiffies value cannot be used. At this time, we need to use the kernel functions udelay and mdelay. The u table shows the Greek letter "Mu" (m), which represents "micro ". Their prototype is as follows: # Include <Linux/delay. h> Void udelay (unsigned long usecs); // The number of microseconds specified by the software loop latency Void mdelay (unsigned long msecs); // use udelay For Loop This function is compiled as an inline function in most architectures. The bogomips value is used in the udelay function: its loop is based on the integer loops_per_second. This value is obtained when bogomips is calculated in the pilot phase. The udelay function can only be used to obtain a short latency. Because the accuracy of the loops_per_second value is only 8 bits, when calculating a longer latency, a considerable error will be accumulated. Although the maximum latency allowed is nearly 1 S (because the longer latency will overflow), the maximum recommended udelay function parameter is 1000us (1 ms ). The mdelay function can be used when the latency is greater than 11 ms. Many drivers need to delay the task to be processed later, but do not want to interrupt it. Linux provides three methods for this: task queue, tasklet, and kernel timer. Note that udelay is a busy waiting function and cannot run other tasks during the delay period. For the source code, see the header file <ASM/delay. h>. At present, the kernel does not support latency greater than 1 microsecond and less than 1 clock tick, but this is not a problem because the latency is identified by hardware or people. The latency interval of 1% seconds is sufficient for humans, while that of 1 ms is long enough for hardware. If you really need the latency interval, you just need to create a loop that continuously executes the udelay (1000) function. Sample Code of the Linux kernel latency function: 1. # include <Linux/time. h> Void do_gettimeofday (struct timeval * TV) { Unsigned long flags; Unsigned long USEC, SEC; read_lock_irqsave(&xtime_lock, flags); sec = xtime.tv_sec; usec = xtime.tv_usec + do_gettimeoffset(); read_unlock_irqrestore(&xtime_lock, flags); while (usec >= 1000000) { usec -= 1000000; sec++; } tv->tv_sec = sec; tv->tv_usec = usec; } void MyDelay(unsigned long delay) { struct timeval tv; do_gettimeofday(&tv) unsigned long start = tv.tv_usec;//unsigned long start = tv.tv_sec; while(tv.tv_usec - start <delay) do_gettimeofday(&tv) } 2. If the driver uses a waiting queue to wait for an event, and you want to make sure that the driver Extern inline long sleep_on_timeout (wait_queue_head_t * q, signed long timeout) { Signed long early = 0;
Current-> timeout = jiffies + timeout; Sleep_on (Q ); If (current-> timeout> 0 ){ Early = Current-> timeout-jiffies; Current-> timeout = 0; } Return early; } extern inline long interruptible_sleep_on_timeout(wait_queue_head_t *q, signed long timeout) { signed long early = 0; current->timeout = jiffies + timeout; interruptible_sleep_on (q); if (current->timeout > 0) { early = current->timeout - jiffies; current->timeout = 0; } return early; } 3. If you do not need to wait for other events, you can directly wait for a delay. Extern inline void schedule_timeout (INT timeout) { Current-> timeout = jiffies + timeout; Current-> state = task_interruptible; Schedule (); Current-> timeout = 0; } Set_current_state (task_interruptible ); Schedule_timeout (jit_delay * Hz ); 4. We recommend a maximum of us for short latency and hardware synchronization. # Include <Linux/delay. h> void __delay(int loops) { long long dummy; __asm__ __volatile__("gettr " __t0 ", %1/n/t" "_pta 4, " __t0 "/n/t" "addi %0, -1, %0/n/t" "bne %0, r63, " __t0 "/n/t" "ptabs %1, " __t0 "/n/t":"=r"(loops), "=r"(dummy) :"0"(loops)); } void __udelay(unsigned long long usecs, unsigned long lpj) { usecs *= (((unsigned long long) HZ << 32) / 1000000) * lpj; __delay((long long) usecs >> 32); } #ifdef notdef #define mdelay(n) (/ {unsigned long msec=(n); while (msec--) udelay(1000);}) #else #define mdelay(n) (/ (__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : / ({unsigned long msec=(n); while (msec--) udelay(1000);})) #endif
|