|
|
1.1 root 1: /*
2:
3: * A simple device driver for u:\dev\clock. Reading from this
4:
5: * device produces a single line containing the current time, in the
6:
7: * format:
8:
9: * MM/DD/YY hh:mm:ss\r\n
10:
11: * Writing to it will change the time to the given one.
12:
13: *
14:
15: * This program is written by Eric R. Smith and is hereby placed in
16:
17: * the public domain.
18:
19: *
20:
21: * COMPILER NOTE: I've assumed that you're using a compiler (like gcc
22:
23: * or Lattice) that preserves registers d2 and a2 across function calls.
24:
25: * If your compiler uses these registers as scratch registers (e.g.
26:
27: * MWC, Alcyon) then you'll have to provide assembly language wrapper
28:
29: * functions that the kernel can call.
30:
31: * This code also assumes that sizeof(int) == 2.
32:
33: *
34:
35: * for gcc: compile with gcc -mshort -O clockdev.c -o clockdev.prg
36:
37: * for lcc: compile with -bn -b0 -r0 -v -w -t= clockdev.c -oclockdev.prg
38:
39: */
40:
41:
42:
43: #ifdef __GNUC__
44:
45: #include <minimal.h>
46:
47: #endif
48:
49: #include <osbind.h>
50:
51: #include <basepage.h>
52:
53: #include "mintbind.h"
54:
55: #include "filesys.h"
56:
57: #include "atarierr.h"
58:
59:
60:
61: #ifdef LATTICE
62:
63: #define BP _pbase
64:
65: #else
66:
67: #define BP _base
68:
69: #endif
70:
71:
72:
73: /* the name of the device we're installing */
74:
75: char name[] = "U:\\DEV\\CLOCK";
76:
77:
78:
79: /* kernel information */
80:
81: struct kerinfo *kernel;
82:
83: #define CCONWS (void)(*kernel->dos_tab[0x09])
84:
85: #define RWABS (*kernel->bios_tab[4])
86:
87: #define GETBPB (void *)(*kernel->bios_tab[7])
88:
89: #define TGETTIME (*kernel->dos_tab[0x2c])
90:
91: #define TGETDATE (*kernel->dos_tab[0x2a])
92:
93: #define TSETTIME (*kernel->dos_tab[0x2d])
94:
95: #define TSETDATE (*kernel->dos_tab[0x2b])
96:
97:
98:
99: #define SPRINTF (*kernel->sprintf)
100:
101: #define DEBUG (*kernel->debug)
102:
103: #define ALERT (*kernel->alert)
104:
105: #define TRACE (*kernel->trace)
106:
107: #define FATAL (*kernel->fatal)
108:
109:
110:
111: /* assumption: 16 bit integers */
112:
113: #define word int
114:
115:
116:
117: /* device driver information */
118:
119: static long clock_open P_((FILEPTR *)),
120:
121: clock_write P_((FILEPTR *, char *, long)),
122:
123: clock_read P_((FILEPTR *, char *, long)),
124:
125: clock_lseek P_((FILEPTR *, long, word)),
126:
127: clock_ioctl P_((FILEPTR *, word, void *)),
128:
129: clock_datime P_((FILEPTR *, word *, word)),
130:
131: clock_close P_((FILEPTR *));
132:
133:
134:
135: static long clock_select();
136:
137: static void clock_unselect();
138:
139:
140:
141: DEVDRV clock_device = {
142:
143: clock_open, clock_write, clock_read, clock_lseek, clock_ioctl,
144:
145: clock_datime, clock_close, clock_select, clock_unselect,
146:
147: 0, 0, 0
148:
149: };
150:
151:
152:
153: struct dev_descr devinfo = {
154:
155: &clock_device, 0, 0, (struct tty *)0, 0L, 0L, 0L, 0L
156:
157: };
158:
159:
160:
161: #ifdef LATTICE
162:
163: BASEPAGE *BP;
164:
165:
166:
167: void
168:
169: start(BASEPAGE *bp)
170:
171: {
172:
173: BP = bp;
174:
175:
176:
177: main();
178:
179: }
180:
181: #endif
182:
183:
184:
185: /*
186:
187: * the main program just installs the device, and then does Ptermres
188:
189: * to remain resident
190:
191: */
192:
193:
194:
195: main()
196:
197: {
198:
199: kernel = (struct kerinfo *)Dcntl(DEV_INSTALL, name, &devinfo);
200:
201: if (!kernel || ((long)kernel) == -32) {
202:
203: Cconws("Unable to install clock device\r\n");
204:
205: Pterm(1);
206:
207: }
208:
209: Ptermres(256L + BP->p_tlen + BP->p_dlen + BP->p_blen, 0);
210:
211: }
212:
213:
214:
215: /*
216:
217: * here are the actual device driver functions
218:
219: */
220:
221:
222:
223: /*
224:
225: * utility functions:
226:
227: * getclock(buf): get the current date and time and write it into
228:
229: * the pointed to buffer in the format "MM/DD/YY hh:mm:ss\r\n"
230:
231: *
232:
233: * setclock(buf): set the current date and time from the ASCII
234:
235: * string pointed to by buf, which must have the same format
236:
237: * as that returned by getdate
238:
239: */
240:
241:
242:
243: void
244:
245: getclock(buf)
246:
247: char *buf;
248:
249: {
250:
251: int DD, MM, YY, hh, ss, mm;
252:
253: unsigned date, time;
254:
255:
256:
257: date = TGETDATE();
258:
259: time = TGETTIME();
260:
261:
262:
263: DD = date & 31;
264:
265: MM = (date >> 5) & 15;
266:
267: YY = 80 + ( (date >> 9) & 127 ); if (YY > 99) YY -= 100;
268:
269:
270:
271: ss = (time & 31) << 1;
272:
273: mm = (time >> 5) & 63;
274:
275: hh = (time >> 11) & 31;
276:
277:
278:
279: SPRINTF(buf, "%02d/%02d/%02d %02d:%02d:%02d\r\n", MM, DD, YY,
280:
281: hh, mm, ss);
282:
283: }
284:
285:
286:
287: static int
288:
289: getint(buf)
290:
291: char *buf;
292:
293: {
294:
295: int val = 0;
296:
297:
298:
299: val = *buf++ - '0';
300:
301: val = 10 * val + *buf - '0';
302:
303: return val;
304:
305: }
306:
307:
308:
309: void
310:
311: setclock(buf)
312:
313: char *buf;
314:
315: {
316:
317: int DD, MM, YY, hh, mm, ss;
318:
319: unsigned time, date;
320:
321:
322:
323: MM = getint(buf); buf += 3;
324:
325: if (MM < 1 || MM > 12) return;
326:
327: DD = getint(buf); buf += 3;
328:
329: if (DD < 1 || DD > 31) return;
330:
331: YY = getint(buf); buf += 3;
332:
333: if (YY < 80 || YY > 99) return;
334:
335: hh = getint(buf); buf += 3;
336:
337: if (hh < 0 || hh > 23) return;
338:
339: mm = getint(buf); buf += 3;
340:
341: if (mm < 0 || mm > 59) return;
342:
343: ss = getint(buf);
344:
345: if (ss < 0 || ss > 59) return;
346:
347:
348:
349: time = (hh << 11) | (mm << 5) | (ss >> 1);
350:
351: date = ((YY - 80) << 9) | (MM << 5) | DD;
352:
353: TSETTIME(time);
354:
355: TSETDATE(date);
356:
357: }
358:
359:
360:
361: #define NBYTES 19 /* strlen("DD/MM/YY hh:mm:ss\r\n") */
362:
363:
364:
365: static long
366:
367: clock_open(f)
368:
369: FILEPTR *f;
370:
371: {
372:
373: return 0;
374:
375: }
376:
377:
378:
379: static long
380:
381: clock_write(f, buf, bytes)
382:
383: FILEPTR *f; char *buf; long bytes;
384:
385: {
386:
387: static char writebuf[NBYTES];
388:
389: static int bufptr = 0;
390:
391: long wrote = 0;
392:
393:
394:
395: while (bytes-- > 0 && bufptr < NBYTES) {
396:
397: /* ignore CR/LF at beginning of line */
398:
399: if (bufptr == 0 && (*buf == '\r' || *buf == '\n'))
400:
401: buf++;
402:
403: else
404:
405: writebuf[bufptr++] = *buf++;
406:
407: wrote++;
408:
409: }
410:
411:
412:
413: /* do we have a complete date now? if so, set the clock */
414:
415: if (bufptr == NBYTES) {
416:
417: setclock(writebuf);
418:
419: bufptr = 0;
420:
421: }
422:
423: return wrote;
424:
425: }
426:
427:
428:
429: static long
430:
431: clock_read(f, buf, bytes)
432:
433: FILEPTR *f; char *buf; long bytes;
434:
435: {
436:
437: /* SPRINTF will stuff one too many bytes in here (the \0) */
438:
439: static char readbuf[NBYTES+1];
440:
441: int where;
442:
443: long total = 0;
444:
445:
446:
447: getclock(readbuf);
448:
449: while (f->pos < NBYTES) {
450:
451: *buf++ = readbuf[f->pos++];
452:
453: total++;
454:
455: }
456:
457: return total;
458:
459: }
460:
461:
462:
463: static long
464:
465: clock_lseek(f, where, whence)
466:
467: FILEPTR *f; long where; int whence;
468:
469: {
470:
471: long newplace;
472:
473:
474:
475: switch(whence) {
476:
477: case 0:
478:
479: newplace = where;
480:
481: break;
482:
483: case 1:
484:
485: newplace = f->pos + where;
486:
487: break;
488:
489: case 2:
490:
491: newplace = (NBYTES-1) - where;
492:
493: break;
494:
495: }
496:
497:
498:
499: if (newplace < 0 || newplace >= NBYTES)
500:
501: return ERANGE;
502:
503:
504:
505: f->pos = newplace;
506:
507: return newplace;
508:
509: }
510:
511:
512:
513: static long
514:
515: clock_ioctl(f, mode, buf)
516:
517: FILEPTR *f; int mode; void *buf;
518:
519: {
520:
521: if (mode == FIONREAD || mode == FIONWRITE) {
522:
523: *((long *)buf) = (NBYTES-1) - f->pos;
524:
525: return 0;
526:
527: }
528:
529: else
530:
531: return EINVFN;
532:
533: }
534:
535:
536:
537: static long
538:
539: clock_datime(f, timeptr, rwflag)
540:
541: FILEPTR *f;
542:
543: word *timeptr;
544:
545: int rwflag;
546:
547: {
548:
549: if (rwflag)
550:
551: return EACCDN;
552:
553: *timeptr++ = TGETTIME();
554:
555: *timeptr = TGETDATE();
556:
557: return 0;
558:
559: }
560:
561:
562:
563: static long
564:
565: clock_close(f)
566:
567: FILEPTR *f;
568:
569: {
570:
571: return 0;
572:
573: }
574:
575:
576:
577: static long
578:
579: clock_select()
580:
581: {
582:
583: return 1; /* we're always ready for I/O */
584:
585: }
586:
587:
588:
589: static void
590:
591: clock_unselect()
592:
593: {
594:
595: /* nothing for us to do here */
596:
597: }
598:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.