#include #include #include #include #include #include #include #include static void restore(void); static void __attribute__ ((format (printf, 1, 2))) fatal(const char *msg, ...) { va_list ap; fprintf(stderr, "fatal error: "); va_start(ap, msg); vfprintf (stderr, msg, ap); va_end(ap); restore(); exit(1); } static int port_start = -1; static int verbose = 1; #define PORT(name,len,val) \ static unsigned in_##name() { \ unsigned res = in##len(port_start+(val)); \ if (verbose) printf("*%s -> %x\n", #name, res); \ return res; \ } \ static void out_##name(unsigned v) { \ if (verbose) printf("%x -> *%s\n", v, #name); \ out##len(v,port_start+(val)); \ } PORT(Timer,l,0x48) PORT(IntrMask,w,0x3c) PORT(IntrStatus,w,0x3E) PORT(TimerInt,l,0x54) static void my_sleep(int n) { if (verbose) { printf("sleeping %d seconds...", n); fflush(stdout); } sleep(n); if (verbose) printf("\n\n"); } #define sleep(n) my_sleep(n) static int saved_mask = -1; static int saved_tmr = -1; static void restore(void) { if (saved_mask >= 0) out_IntrMask(saved_mask); if (saved_tmr >= 0) out_TimerInt(saved_tmr); out_Timer(0); } static void stop(int sig) { restore(); printf("bye bye\n"); exit(1); } #define CLK 33000000 int main() { // find port address from lspci command FILE *f = popen("lspci -vn", "r"); if (!f) fatal("executing lspci...\n"); char line[128]; int in_card = 0; while(fgets(line, sizeof(line), f)) { // parse header, select our card if (!isspace(line[0])) { in_card = 0; if (strstr(line, " 10ec:8139 ") != NULL) in_card = 1; continue; } // skip other cards if (!in_card) continue; if (sscanf(line, " I/O ports at %x [size", &port_start) == 1) break; } pclose(f); if (port_start < 0) fatal("port not found!\n"); printf("found card at address %x\n", port_start); // enable direct port access if (iopl(3)) fatal("iopl...\n"); signal(SIGTERM, stop); signal(SIGINT, stop); saved_mask = in_IntrMask(); saved_tmr = in_TimerInt(); const unsigned from = 0.95 * CLK; const unsigned to = 1.6 * CLK; out_IntrMask(0); in_IntrStatus(); in_Timer(); in_Timer(); // Test 1. test counter continue and continue out_TimerInt(0); // disable timer out_IntrStatus(0x4000); out_Timer(12345); // reset timer to 0 unsigned curr = in_Timer(); unsigned cnt; if (curr > 0.1 * CLK) fatal("time too big %u\n", curr); for (cnt=0;;) { sleep(1); unsigned prev = curr; curr = in_Timer(); // test skep is in a specific range unsigned diff = (curr-prev) & 0xffffffffu; if (diff < from || diff > to) fatal("Invalid diff %u (%u-%u)\n", diff, from,to); if (curr < prev && ++cnt == 3) break; } // Test 2. Check we didn't get an interrupt with TimerInt == 0 if (in_IntrStatus() & 0x4000) fatal("got an interrupt\n"); // Test 3. Setting TimerInt to 1 and Timer to 0 get interrupt out_TimerInt(1); out_Timer(0); if ((in_IntrStatus() & 0x4000) == 0) fatal("we should have an interrupt here!\n"); // Test 3. Check acknowledge out_IntrStatus(0x4000); if (in_IntrStatus() & 0x4000) fatal("got an interrupt\n"); // Test. Status set after Timer reset out_Timer(0); out_TimerInt(0); out_IntrStatus(0x4000); curr = in_Timer(); out_TimerInt(curr + 0.5 * CLK); sleep(1); out_Timer(0); if ((in_IntrStatus() & 0x4000) == 0) fatal("we should have an interrupt here!\n"); // Test. Status set after TimerInt reset out_Timer(0); out_TimerInt(0); out_IntrStatus(0x4000); curr = in_Timer(); out_TimerInt(curr + 0.5 * CLK); sleep(1); out_TimerInt(0); if ((in_IntrStatus() & 0x4000) == 0) fatal("we should have an interrupt here!\n"); // Test 4. Increment TimerInt we should see an interrupt curr = in_Timer(); unsigned next = curr + 5.0 * CLK; out_TimerInt(next); for (cnt=0;;) { sleep(1); unsigned prev = curr; curr = in_Timer(); unsigned diff = (curr-prev) & 0xffffffffu; if (diff < from || diff > to) fatal("Invalid diff %u (%u-%u)\n", diff, from,to); if (cnt < 3 && curr > next) { if ((in_IntrStatus() & 0x4000) == 0) fatal("we should have an interrupt here!\n"); out_IntrStatus(0x4000); next = curr + 5.0 * CLK; out_TimerInt(next); if (++cnt == 3) out_TimerInt(1); // Test 5. Second time we pass from 0 should see an interrupt } else if (cnt >= 3 && curr < prev) { // here we should have an interrupt if ((in_IntrStatus() & 0x4000) == 0) fatal("we should have an interrupt here!\n"); out_IntrStatus(0x4000); if (++cnt == 5) break; } } printf("Everythink is ok!\n"); verbose = 0; restore(); return 0; /* irq is set when Timer == TimerInt * TimerInt == 0 disable timer * Timer keep counting always * If you set ANY value to Timer Timer is set to 0 */ } /* test - 0 TimerInt non setta mai irq - settanto a 1 TimerInt e poi resettando Timer subito irq - passando seconda volta setta comunque - scrivo qualsiasi in Timer valore e va a 0 comunque */