freemyipod r646 - Code Review

Jump to: navigation, search
Repository:freemyipod
Revision:r645‎ | r646 | r647 >
Date:00:33, 24 February 2011
Author:theseven
Status:new
Tags:
Comment:
emCORE: Fix ata_sleep and ata_spin semantics
Modified paths:
  • /emcore/trunk/target/ipodclassic/storage_ata.c (modified) (history)
  • /emcore/trunk/timer.h (modified) (history)
  • /emcore/trunk/util.h (modified) (history)

Diff [purge]

Index: emcore/trunk/util.h
@@ -1,227 +1,227 @@
2 -//
3 -//
4 -// Copyright 2010 TheSeven
5 -//
6 -//
7 -// This file is part of emCORE.
8 -//
9 -// emCORE is free software: you can redistribute it and/or
10 -// modify it under the terms of the GNU General Public License as
11 -// published by the Free Software Foundation, either version 2 of the
12 -// License, or (at your option) any later version.
13 -//
14 -// emCORE is distributed in the hope that it will be useful,
15 -// but WITHOUT ANY WARRANTY; without even the implied warranty of
16 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 -// See the GNU General Public License for more details.
18 -//
19 -// You should have received a copy of the GNU General Public License along
20 -// with emCORE. If not, see <http://www.gnu.org/licenses/>.
21 -//
22 -//
23 -
24 -
25 -#ifndef __UTIL_H__
26 -#define __UTIL_H__
27 -
28 -
29 -#include "global.h"
30 -
31 -
32 -#ifndef NULL
33 -#define NULL ((void*)0)
34 -#endif
35 -
36 -#ifndef MIN
37 -#define MIN(a, b) (((a)<(b))?(a):(b))
38 -#endif
39 -
40 -#ifndef MAX
41 -#define MAX(a, b) (((a)>(b))?(a):(b))
42 -#endif
43 -
44 -/* return number of elements in array a */
45 -#define ARRAYLEN(a) (sizeof(a)/sizeof((a)[0]))
46 -
47 -/* return p incremented by specified number of bytes */
48 -#define SKIPBYTES(p, count) ((typeof (p))((char *)(p) + (count)))
49 -
50 -#define BIT(x) (1 << (x))
51 -#define BITRANGE(x, y) ((0xfffffffful >> (31 + (x) - (y))) << (x))
52 -
53 -#define ERR_RC(val) (BIT(31) | (val))
54 -#define IS_ERR(val) (val & BIT(31))
55 -#define RET_ERR(val) \
56 -{ \
57 - return ERR_RC(val); \
58 -}
59 -#define RET_ERR_MTX(val, mutex) \
60 -{ \
61 - mutex_unlock(mutex); \
62 - return ERR_RC(val); \
63 -}
64 -#define PASS_RC(expr, bits, val) \
65 -{ \
66 - int PASS_RC_rc = (expr); \
67 - if (IS_ERR(PASS_RC_rc)) \
68 - return ERR_RC((PASS_RC_rc << (bits)) | (val)); \
69 -}
70 -#define PASS_RC_MTX(expr, bits, val, mutex) \
71 -{ \
72 - int PASS_RC_MTX_rc = (expr); \
73 - if (IS_ERR(PASS_RC_MTX_rc)) \
74 - { \
75 - mutex_unlock(mutex); \
76 - return ERR_RC((PASS_RC_MTX_rc << (bits)) | (val)); \
77 - } \
78 -}
79 -
80 -#define P2_M1(p2) ((1 << (p2))-1)
81 -
82 -/* align up or down to nearest 2^p2 */
83 -#define ALIGN_DOWN_P2(n, p2) ((n) & ~P2_M1(p2))
84 -#define ALIGN_UP_P2(n, p2) ALIGN_DOWN_P2((n) + P2_M1(p2),p2)
85 -
86 -/* align up or down to nearest integer multiple of a */
87 -#define ALIGN_DOWN(n, a) ((n)/(a)*(a))
88 -#define ALIGN_UP(n, a) ALIGN_DOWN((n)+((a)-1),a)
89 -
90 -/* align start and end of buffer to nearest integer multiple of a */
91 -#define ALIGN_BUFFER(ptr,len,align) \
92 -{\
93 - uintptr_t tmp_ptr1 = (uintptr_t)ptr; \
94 - uintptr_t tmp_ptr2 = tmp_ptr1 + len;\
95 - tmp_ptr1 = ALIGN_UP(tmp_ptr1,align); \
96 - tmp_ptr2 = ALIGN_DOWN(tmp_ptr2,align); \
97 - len = tmp_ptr2 - tmp_ptr1; \
98 - ptr = (typeof(ptr))tmp_ptr1; \
99 -}
100 -
101 -
102 -/* live endianness conversion */
103 -#ifdef LITTLE_ENDIAN
104 -#define letoh16(x) (x)
105 -#define letoh32(x) (x)
106 -#define htole16(x) (x)
107 -#define htole32(x) (x)
108 -#define betoh16(x) swap16(x)
109 -#define betoh32(x) swap32(x)
110 -#define htobe16(x) swap16(x)
111 -#define htobe32(x) swap32(x)
112 -#define swap_odd_even_be32(x) (x)
113 -#define swap_odd_even_le32(x) swap_odd_even32(x)
114 -#else
115 -#define letoh16(x) swap16(x)
116 -#define letoh32(x) swap32(x)
117 -#define htole16(x) swap16(x)
118 -#define htole32(x) swap32(x)
119 -#define betoh16(x) (x)
120 -#define betoh32(x) (x)
121 -#define htobe16(x) (x)
122 -#define htobe32(x) (x)
123 -#define swap_odd_even_be32(x) swap_odd_even32(x)
124 -#define swap_odd_even_le32(x) (x)
125 -#endif
126 -
127 -
128 -/* static endianness conversion */
129 -#define SWAP_16(x) ((typeof(x))(unsigned short)(((unsigned short)(x) >> 8) | \
130 - ((unsigned short)(x) << 8)))
131 -
132 -#define SWAP_32(x) ((typeof(x))(unsigned long)( ((unsigned long)(x) >> 24) | \
133 - (((unsigned long)(x) & 0xff0000ul) >> 8) | \
134 - (((unsigned long)(x) & 0xff00ul) << 8) | \
135 - ((unsigned long)(x) << 24)))
136 -
137 -#ifdef RLITTLE_ENDIAN
138 -#define LE_TO_H16(x) (x)
139 -#define LE_TO_H32(x) (x)
140 -#define H_TO_LE16(x) (x)
141 -#define H_TO_LE32(x) (x)
142 -#define BE_TO_H16(x) SWAP_16(x)
143 -#define BE_TO_H32(x) SWAP_32(x)
144 -#define H_TO_BE16(x) SWAP_16(x)
145 -#define H_TO_BE32(x) SWAP_32(x)
146 -#else
147 -#define LE_TO_H16(x) SWAP_16(x)
148 -#define LE_TO_H32(x) SWAP_32(x)
149 -#define H_TO_LE16(x) SWAP_16(x)
150 -#define H_TO_LE32(x) SWAP_32(x)
151 -#define BE_TO_H16(x) (x)
152 -#define BE_TO_H32(x) (x)
153 -#define H_TO_BE16(x) (x)
154 -#define H_TO_BE32(x) (x)
155 -#endif
156 -
157 -/* Get the byte offset of a type's member */
158 -#define OFFSETOF(type, membername) ((off_t)&((type *)0)->membername)
159 -
160 -/* Get the type pointer from one of its members */
161 -#define TYPE_FROM_MEMBER(type, memberptr, membername) \
162 - ((type *)((intptr_t)(memberptr) - OFFSETOF(type, membername)))
163 -
164 -static inline uint16_t swap16(uint16_t value)
165 - /*
166 - result[15..8] = value[ 7..0];
167 - result[ 7..0] = value[15..8];
168 - */
169 -{
170 - return (value >> 8) | (value << 8);
171 -}
172 -
173 -static inline uint32_t swap32(uint32_t value)
174 - /*
175 - result[31..24] = value[ 7.. 0];
176 - result[23..16] = value[15.. 8];
177 - result[15.. 8] = value[23..16];
178 - result[ 7.. 0] = value[31..24];
179 - */
180 -{
181 - uint32_t hi = swap16(value >> 16);
182 - uint32_t lo = swap16(value & 0xffff);
183 - return (lo << 16) | hi;
184 -}
185 -
186 -static inline uint32_t swap_odd_even32(uint32_t value)
187 -{
188 - /*
189 - result[31..24],[15.. 8] = value[23..16],[ 7.. 0]
190 - result[23..16],[ 7.. 0] = value[31..24],[15.. 8]
191 - */
192 - uint32_t t = value & 0xff00ff00;
193 - return (t >> 8) | ((t ^ value) << 8);
194 -}
195 -
196 -#ifndef BIT_N
197 -#define BIT_N(n) (1U << (n))
198 -#endif
199 -
200 -#ifndef CACHEALIGN_SIZE /* could be elsewhere for a particular reason */
201 -#ifdef CACHEALIGN_BITS
202 -/* 2^CACHEALIGN_BITS = the byte size */
203 -#define CACHEALIGN_SIZE (1u << CACHEALIGN_BITS)
204 -#else
205 -#define CACHEALIGN_SIZE 16 /* FIXME */
206 -#endif
207 -#endif /* CACHEALIGN_SIZE */
208 -
209 -#define CACHEALIGN_ATTR __attribute__((aligned(CACHEALIGN_SIZE)))
210 -/* Aligns x up to a CACHEALIGN_SIZE boundary */
211 -#define CACHEALIGN_UP(x) \
212 - ((typeof (x))ALIGN_UP_P2((uintptr_t)(x), CACHEALIGN_BITS))
213 -/* Aligns x down to a CACHEALIGN_SIZE boundary */
214 -#define CACHEALIGN_DOWN(x) \
215 - ((typeof (x))ALIGN_DOWN_P2((uintptr_t)(x), CACHEALIGN_BITS))
216 -/* Aligns at least to the greater of size x or CACHEALIGN_SIZE */
217 -#define CACHEALIGN_AT_LEAST_ATTR(x) \
218 - __attribute__((aligned(CACHEALIGN_UP(x))))
219 -/* Aligns a buffer pointer and size to proper boundaries */
220 -#define CACHEALIGN_BUFFER(start, size) \
221 - ALIGN_BUFFER((start), (size), CACHEALIGN_SIZE)
222 -
223 -/* Double-cast to avoid 'dereferencing type-punned pointer will
224 - * break strict aliasing rules' B.S. */
225 -#define PUN_PTR(type, p) ((type)(intptr_t)(p))
226 -
227 -
228 -#endif
 2+//
 3+//
 4+// Copyright 2010 TheSeven
 5+//
 6+//
 7+// This file is part of emCORE.
 8+//
 9+// emCORE is free software: you can redistribute it and/or
 10+// modify it under the terms of the GNU General Public License as
 11+// published by the Free Software Foundation, either version 2 of the
 12+// License, or (at your option) any later version.
 13+//
 14+// emCORE is distributed in the hope that it will be useful,
 15+// but WITHOUT ANY WARRANTY; without even the implied warranty of
 16+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 17+// See the GNU General Public License for more details.
 18+//
 19+// You should have received a copy of the GNU General Public License along
 20+// with emCORE. If not, see <http://www.gnu.org/licenses/>.
 21+//
 22+//
 23+
 24+
 25+#ifndef __UTIL_H__
 26+#define __UTIL_H__
 27+
 28+
 29+#include "global.h"
 30+
 31+
 32+#ifndef NULL
 33+#define NULL ((void*)0)
 34+#endif
 35+
 36+#ifndef MIN
 37+#define MIN(a, b) (((a)<(b))?(a):(b))
 38+#endif
 39+
 40+#ifndef MAX
 41+#define MAX(a, b) (((a)>(b))?(a):(b))
 42+#endif
 43+
 44+/* return number of elements in array a */
 45+#define ARRAYLEN(a) (sizeof(a)/sizeof((a)[0]))
 46+
 47+/* return p incremented by specified number of bytes */
 48+#define SKIPBYTES(p, count) ((typeof (p))((char *)(p) + (count)))
 49+
 50+#define BIT(x) (1 << (x))
 51+#define BITRANGE(x, y) ((0xfffffffful >> (31 + (x) - (y))) << (x))
 52+
 53+#define ERR_RC(val) (BIT(31) | (val))
 54+#define IS_ERR(val) (val & BIT(31))
 55+#define RET_ERR(val) \
 56+{ \
 57+ return ERR_RC(val); \
 58+}
 59+#define RET_ERR_MTX(val, mutex) \
 60+{ \
 61+ mutex_unlock(mutex); \
 62+ return ERR_RC(val); \
 63+}
 64+#define PASS_RC(expr, bits, val) \
 65+{ \
 66+ int PASS_RC_rc = (expr); \
 67+ if (IS_ERR(PASS_RC_rc)) \
 68+ return ERR_RC((PASS_RC_rc << (bits)) | (val)); \
 69+}
 70+#define PASS_RC_MTX(expr, bits, val, mutex) \
 71+{ \
 72+ int PASS_RC_MTX_rc = (expr); \
 73+ if (IS_ERR(PASS_RC_MTX_rc)) \
 74+ { \
 75+ mutex_unlock(mutex); \
 76+ return ERR_RC((PASS_RC_MTX_rc << (bits)) | (val)); \
 77+ } \
 78+}
 79+
 80+#define P2_M1(p2) ((1 << (p2))-1)
 81+
 82+/* align up or down to nearest 2^p2 */
 83+#define ALIGN_DOWN_P2(n, p2) ((n) & ~P2_M1(p2))
 84+#define ALIGN_UP_P2(n, p2) ALIGN_DOWN_P2((n) + P2_M1(p2),p2)
 85+
 86+/* align up or down to nearest integer multiple of a */
 87+#define ALIGN_DOWN(n, a) ((n)/(a)*(a))
 88+#define ALIGN_UP(n, a) ALIGN_DOWN((n)+((a)-1),a)
 89+
 90+/* align start and end of buffer to nearest integer multiple of a */
 91+#define ALIGN_BUFFER(ptr,len,align) \
 92+{\
 93+ uintptr_t tmp_ptr1 = (uintptr_t)ptr; \
 94+ uintptr_t tmp_ptr2 = tmp_ptr1 + len;\
 95+ tmp_ptr1 = ALIGN_UP(tmp_ptr1,align); \
 96+ tmp_ptr2 = ALIGN_DOWN(tmp_ptr2,align); \
 97+ len = tmp_ptr2 - tmp_ptr1; \
 98+ ptr = (typeof(ptr))tmp_ptr1; \
 99+}
 100+
 101+
 102+/* live endianness conversion */
 103+#ifdef LITTLE_ENDIAN
 104+#define letoh16(x) (x)
 105+#define letoh32(x) (x)
 106+#define htole16(x) (x)
 107+#define htole32(x) (x)
 108+#define betoh16(x) swap16(x)
 109+#define betoh32(x) swap32(x)
 110+#define htobe16(x) swap16(x)
 111+#define htobe32(x) swap32(x)
 112+#define swap_odd_even_be32(x) (x)
 113+#define swap_odd_even_le32(x) swap_odd_even32(x)
 114+#else
 115+#define letoh16(x) swap16(x)
 116+#define letoh32(x) swap32(x)
 117+#define htole16(x) swap16(x)
 118+#define htole32(x) swap32(x)
 119+#define betoh16(x) (x)
 120+#define betoh32(x) (x)
 121+#define htobe16(x) (x)
 122+#define htobe32(x) (x)
 123+#define swap_odd_even_be32(x) swap_odd_even32(x)
 124+#define swap_odd_even_le32(x) (x)
 125+#endif
 126+
 127+
 128+/* static endianness conversion */
 129+#define SWAP_16(x) ((typeof(x))(unsigned short)(((unsigned short)(x) >> 8) | \
 130+ ((unsigned short)(x) << 8)))
 131+
 132+#define SWAP_32(x) ((typeof(x))(unsigned long)( ((unsigned long)(x) >> 24) | \
 133+ (((unsigned long)(x) & 0xff0000ul) >> 8) | \
 134+ (((unsigned long)(x) & 0xff00ul) << 8) | \
 135+ ((unsigned long)(x) << 24)))
 136+
 137+#ifdef RLITTLE_ENDIAN
 138+#define LE_TO_H16(x) (x)
 139+#define LE_TO_H32(x) (x)
 140+#define H_TO_LE16(x) (x)
 141+#define H_TO_LE32(x) (x)
 142+#define BE_TO_H16(x) SWAP_16(x)
 143+#define BE_TO_H32(x) SWAP_32(x)
 144+#define H_TO_BE16(x) SWAP_16(x)
 145+#define H_TO_BE32(x) SWAP_32(x)
 146+#else
 147+#define LE_TO_H16(x) SWAP_16(x)
 148+#define LE_TO_H32(x) SWAP_32(x)
 149+#define H_TO_LE16(x) SWAP_16(x)
 150+#define H_TO_LE32(x) SWAP_32(x)
 151+#define BE_TO_H16(x) (x)
 152+#define BE_TO_H32(x) (x)
 153+#define H_TO_BE16(x) (x)
 154+#define H_TO_BE32(x) (x)
 155+#endif
 156+
 157+/* Get the byte offset of a type's member */
 158+#define OFFSETOF(type, membername) ((off_t)&((type *)0)->membername)
 159+
 160+/* Get the type pointer from one of its members */
 161+#define TYPE_FROM_MEMBER(type, memberptr, membername) \
 162+ ((type *)((intptr_t)(memberptr) - OFFSETOF(type, membername)))
 163+
 164+static inline uint16_t swap16(uint16_t value)
 165+ /*
 166+ result[15..8] = value[ 7..0];
 167+ result[ 7..0] = value[15..8];
 168+ */
 169+{
 170+ return (value >> 8) | (value << 8);
 171+}
 172+
 173+static inline uint32_t swap32(uint32_t value)
 174+ /*
 175+ result[31..24] = value[ 7.. 0];
 176+ result[23..16] = value[15.. 8];
 177+ result[15.. 8] = value[23..16];
 178+ result[ 7.. 0] = value[31..24];
 179+ */
 180+{
 181+ uint32_t hi = swap16(value >> 16);
 182+ uint32_t lo = swap16(value & 0xffff);
 183+ return (lo << 16) | hi;
 184+}
 185+
 186+static inline uint32_t swap_odd_even32(uint32_t value)
 187+{
 188+ /*
 189+ result[31..24],[15.. 8] = value[23..16],[ 7.. 0]
 190+ result[23..16],[ 7.. 0] = value[31..24],[15.. 8]
 191+ */
 192+ uint32_t t = value & 0xff00ff00;
 193+ return (t >> 8) | ((t ^ value) << 8);
 194+}
 195+
 196+#ifndef BIT_N
 197+#define BIT_N(n) (1U << (n))
 198+#endif
 199+
 200+#ifndef CACHEALIGN_SIZE /* could be elsewhere for a particular reason */
 201+#ifdef CACHEALIGN_BITS
 202+/* 2^CACHEALIGN_BITS = the byte size */
 203+#define CACHEALIGN_SIZE (1u << CACHEALIGN_BITS)
 204+#else
 205+#define CACHEALIGN_SIZE 16 /* FIXME */
 206+#endif
 207+#endif /* CACHEALIGN_SIZE */
 208+
 209+#define CACHEALIGN_ATTR __attribute__((aligned(CACHEALIGN_SIZE)))
 210+/* Aligns x up to a CACHEALIGN_SIZE boundary */
 211+#define CACHEALIGN_UP(x) \
 212+ ((typeof (x))ALIGN_UP_P2((uintptr_t)(x), CACHEALIGN_BITS))
 213+/* Aligns x down to a CACHEALIGN_SIZE boundary */
 214+#define CACHEALIGN_DOWN(x) \
 215+ ((typeof (x))ALIGN_DOWN_P2((uintptr_t)(x), CACHEALIGN_BITS))
 216+/* Aligns at least to the greater of size x or CACHEALIGN_SIZE */
 217+#define CACHEALIGN_AT_LEAST_ATTR(x) \
 218+ __attribute__((aligned(CACHEALIGN_UP(x))))
 219+/* Aligns a buffer pointer and size to proper boundaries */
 220+#define CACHEALIGN_BUFFER(start, size) \
 221+ ALIGN_BUFFER((start), (size), CACHEALIGN_SIZE)
 222+
 223+/* Double-cast to avoid 'dereferencing type-punned pointer will
 224+ * break strict aliasing rules' B.S. */
 225+#define PUN_PTR(type, p) ((type)(intptr_t)(p))
 226+
 227+
 228+#endif
Index: emcore/trunk/target/ipodclassic/storage_ata.c
@@ -977,24 +977,24 @@
978978
979979 void ata_sleep(void)
980980 {
981 - mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
982 - ata_power_down();
983 - mutex_unlock(&ata_mutex);
 981+ ata_last_activity_value = USEC_TIMER - ata_sleep_timeout + 200000;
984982 }
985983
986984 void ata_sleepnow(void)
987985 {
988 - ata_sleep();
 986+ mutex_lock(&ata_mutex, TIMEOUT_BLOCK);
 987+ ata_power_down();
 988+ mutex_unlock(&ata_mutex);
989989 }
990990
991991 void ata_close(void)
992992 {
993 - ata_sleep();
 993+ ata_sleepnow();
994994 }
995995
996996 void ata_spin(void)
997997 {
998 - ata_power_up();
 998+ ata_set_active();
999999 }
10001000
10011001 void ata_get_info(IF_MD2(int drive,) struct storage_info *info)
Index: emcore/trunk/timer.h
@@ -1,54 +1,54 @@
2 -//
3 -//
4 -// Copyright 2010 TheSeven
5 -//
6 -//
7 -// This file is part of emCORE.
8 -//
9 -// emCORE is free software: you can redistribute it and/or
10 -// modify it under the terms of the GNU General Public License as
11 -// published by the Free Software Foundation, either version 2 of the
12 -// License, or (at your option) any later version.
13 -//
14 -// emCORE is distributed in the hope that it will be useful,
15 -// but WITHOUT ANY WARRANTY; without even the implied warranty of
16 -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 -// See the GNU General Public License for more details.
18 -//
19 -// You should have received a copy of the GNU General Public License along
20 -// with emCORE. If not, see <http://www.gnu.org/licenses/>.
21 -//
22 -//
23 -
24 -
25 -#ifndef __TIMER_H__
26 -#define __TIMER_H__
27 -
28 -#include "global.h"
29 -
30 -
31 -#define TIME_AFTER(a,b) ((long)(b) - (long)(a) < 0)
32 -#define TIME_BEFORE(a,b) TIME_AFTER(b,a)
33 -#define TIMEOUT_EXPIRED(a,b) TIME_AFTER(USEC_TIMER,a + b)
34 -
35 -
36 -uint64_t read_native_timer();
37 -#define NATIVE_TIMER (read_native_timer())
38 -uint32_t read_usec_timer();
39 -#define USEC_TIMER (read_usec_timer())
40 -
41 -
42 -#define udelay(duration) \
43 -{ \
44 - long timestamp = USEC_TIMER; \
45 - while (!TIMEOUT_EXPIRED(timestamp, (long)(duration))); \
46 -}
47 -
48 -
49 -void timer_init() INITCODE_ATTR;
50 -void timer_schedule_wakeup(uint32_t usecs) ICODE_ATTR;
51 -void timer_kill_wakeup() ICODE_ATTR;
52 -void INT_TIMERB() ICODE_ATTR;
53 -
54 -
55 -#endif
 2+//
 3+//
 4+// Copyright 2010 TheSeven
 5+//
 6+//
 7+// This file is part of emCORE.
 8+//
 9+// emCORE is free software: you can redistribute it and/or
 10+// modify it under the terms of the GNU General Public License as
 11+// published by the Free Software Foundation, either version 2 of the
 12+// License, or (at your option) any later version.
 13+//
 14+// emCORE is distributed in the hope that it will be useful,
 15+// but WITHOUT ANY WARRANTY; without even the implied warranty of
 16+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 17+// See the GNU General Public License for more details.
 18+//
 19+// You should have received a copy of the GNU General Public License along
 20+// with emCORE. If not, see <http://www.gnu.org/licenses/>.
 21+//
 22+//
 23+
 24+
 25+#ifndef __TIMER_H__
 26+#define __TIMER_H__
 27+
 28+#include "global.h"
 29+
 30+
 31+#define TIME_AFTER(a,b) ((long)(b) - (long)(a) < 0)
 32+#define TIME_BEFORE(a,b) TIME_AFTER(b,a)
 33+#define TIMEOUT_EXPIRED(a,b) TIME_AFTER(USEC_TIMER,a + b)
 34+
 35+
 36+uint64_t read_native_timer();
 37+#define NATIVE_TIMER (read_native_timer())
 38+uint32_t read_usec_timer();
 39+#define USEC_TIMER (read_usec_timer())
 40+
 41+
 42+#define udelay(duration) \
 43+{ \
 44+ long timestamp = USEC_TIMER; \
 45+ while (!TIMEOUT_EXPIRED(timestamp, (long)(duration))); \
 46+}
 47+
 48+
 49+void timer_init() INITCODE_ATTR;
 50+void timer_schedule_wakeup(uint32_t usecs) ICODE_ATTR;
 51+void timer_kill_wakeup() ICODE_ATTR;
 52+void INT_TIMERB() ICODE_ATTR;
 53+
 54+
 55+#endif