• Keine Ergebnisse gefunden

A Simple Game Port Driver 8-1

Im Dokument INTER ACTIVE (Seite 172-196)

APPENDIX 8

Game Port Driver Example

The Game Port or Game Controller allows one or more joystick or other positional indicating devices to be plugged into a Pc. Game controller boards are available from several manufacturers, and a large base of MS-DOS software (mostly video games) already exists. Since the Game Controller hardware is so simple, it is useful as the basis for an elementary UNIX device driver. A UNIX driver would allow a UNIX process to be driven by joystick position inputs.

Although the I/O Address Map assigns Hex address 200 through 20f to Game Control, the Games Controller peripheral board uses only address 201.

The interface is initialized by a write to address 201 and provides position, inputs on successive reads of address 201. The position readings indicate the position of the joystick as follows:

Bit 7 2 represent the mark and flre buttons.

With such an interface, the driver needs no interrupt entry point (IVN 2 is, however, reserved for the Games Controller and is often referred to as the

"Games Interrupt"). The following UNIX driver is implemented without assigning any interrupt vector to the Controller and simply polls the interface upon a readO call from the Operating System.

The main points to extract from review of this driver are an understanding of basic driver structure and the use of printf and trace driver calls used for driver debugging.

APPENDIX B B-1

• Lines 29-35:

Show a way to assign values to ioctlO cmd fields. By convention, the left shifting of the first letter of the device name and or-ing low-order values helps to randomize ioctlO arguments across device drivers and provides some protection if a user process or program opens the wrong special file. Since the ioctl values must be known by user processes to set and clear debugging or tracing, it would be advisable to put them in a header file (for example, jusrjincludejsysjgame.h) so that both the driver and user programs can access them.

• Line 53:

Shows using the minor() macro in jusrjincludejsysjsysmacros.h to strip off the upper bits of dev to determine the minor device specified by the open() system call.

• Line 54:

Puts a printf on jdevjconsole when jdevjgame is opened if the GAMEDBSET ioctl() call has been made.

• Line 55:

Makes a call to trsave() (line 161), which calls the trace driver (see Appendix C) if the GAMETRSET ioctlO call has been made.

• Lines 82-114

The read() routine. Note the use of the device prefix in the entry point, gamereadO and also the use of outbO, inb(), spl(), and copyout(), as described earlier.

• Lines 154-159:

Implement the conditional use of printf's for debugging.

• Lines 161-189:

Implement the conditional use of the trace driver for debugging. See Appendix C.

B-2 ISDG

2

20 #include "sys/types.h"

21 #include "sys/param.h"

22 #include "sys/dir.h"

23 #include "sys/signal.h"

24 #include "syslerrno.h"

25 #include "syslioctl.h"

26 #include "sysluser.h"

27 #include "sys/sysmacros.h"

28

44 int flag;

45 int delay;

46 } qame_dev;

47

48 gameopen(dev, 1lDde) 49 int dev, 1lDde;

gamedbprt( "gamedev: in open") ; qamesave(port, '0',0 ,0);

gamedbprt( "gamedev: in close");

qamesave(port, 'C',O ,0);

i f (port 1= 0) { retuxn·

,

}

qame_dev.flag &= -OPEN;

82 gameread( dev)

89

gamedbprt ("/dev/gaxre: entered write routine");

ganesave(port, 'W' ,u.u_oount,O);

ganeioctl(dev, aid, arg int dev;

134 switch( aId)

148 galllELdev.flag &.= -TRACE;

149 break;

157 i f (gaIlllLdev.flag&J:B;) 158 printf("%s\n", str);

159 }

if (I (gallIlLdev.flag&.TRACE»

return;

179 180 181 182 183 184 185 186 187 188 189

sps = sp15 () ;

if (gameseqn >= 077777) gameseqn

=

0;

gameent.e_seqn

=

++gameseqn;

gameent. e_type

=

type;

gameent.e_dev

=

port;

gameent.e_~1

=

~1;

gameent.e_~

=

~;

trsave(O, port%16, (char *) &. gameent, sizeof(gameent»;

sp1x(sps);

APPENDIX 8 8·7

C Appendix C

The Trace Driver

C-1

APPENDIXC

The Game Port Driver in Appendix B introduced the basic structure of device drivers, but now let's look at something a bit more practical. The trace driver is a pseudo-device that allows the UNIX Operating System kernel or other device drivers to report debugging information without the use of con-sole printf's. The basic mechanism allows calls to the trace driver via trsaveO to store short bursts of trace data in system character buffers (clists). These data items are retrieved from the clists and are reported to a user process by reading /dev /traceO. This driver uses some additional calls common to other drivers, specifically, sleepO, wakeupO, and the clist handling routines.

In addition to providing the driver source code, other files needed to actu-ally compile and use the trace device are provided:

trace.c - The driver source code trace.h - The driver header file

Space.c - The DSP's memory allocation file

trsav.c - A user program to read the trace device and redirect output to a disk file

trfmt.c - A user program to print the trace information

If you wish to key this source code into your system, you can make use of this trace driver to debug a driver that you are writing.

The following notes help explain some of the driver source (trace. c) code:

• Lines 1-121:

Represent the inclusion of system header files and define the open, close, and ioctl functions. The code is self-explanatory.

• Lines 122-149:

The trace driver read() routine. The driver blocks (waits) until data is available via the sleepO function call. The read will block until the Ker-nel or some other driver issues a call to trsaveO. An example of how another driver does this is given in Appendix B. When a trsaveO call is made, trace data is put into a clist and a wakeupO is issued. The read awakens and transfers the trace data to the user process executing the read and releases the clist. Note the use of the internal trace dnver address as the sleep event (&tr_p->trJcnt).

APPENDIX C C-1

2

Since trsave() calls can be done at interrupt level by other drivers, and since the trsave() function and the trread() function both manipu-late the queue of dists, the read function surrounds its manipulation of thEl dist structures with spl calls.

• lines 150-179:

Data from other drivers is put into dists. Note that trsave() accesses the system time counter (lbolt), which represents time in ticks (1/100th of a second on the 386 System) since the system was booted. This places a time stamp on the trace event.

/* Copyright (e) 1987 AT&T */

26 f* 386unix Trace Driver

*f

41 #include "sysltypes.h"

42 #include "syslsignal.h"

43 #include "sysler:rno.h"

44 #include "sys/param.h"

45 #include "sysldir .h"

46 #include"sys/user .h"

47 #include "syslpage.h"

48 #include "syslsystm.h"

49 #include "sysltty.h"

50 #include "syslsysmacros.h"

51 #include "sysltrace.h"

52

71 }

72 trJ) = &.tr_data[chan];

73 if (tr..Y>tr_state&OPEN)

74 u.u_error

=

EACCES;

tr..Y>tr_chbits 1= (01«(int)arg);

return;

116

tr...,P'"">tr_rcrlt = 0;

while (getc(&.tr...,P'"">tr_outq»=O);

tr...,P'"">tr_state = 0;

122 trread( dev)

tr...,P'"">tr_state 1= 'ltlSLEEP;

while (tr...,P'"">tr_rcnt == 0)

sleep( (caddr_t)&.tr...,P'"">tr_rcrlt, TRPRI);

splO();

while (u.u_COIlXlt &&. tr...,P'"">tr_rcrlt) { i f (tr...,P'"">tr_chno == NIL) {

}

tr...,P'"">tr_elmo = getc(&.tr...,P'"">tr_outq);

tr...,P'"">tr_ct = getc(&.tr...,P'"">tr_outq);

i f (u.u_count < (tr...,P'"">tr_ct + tr...,P'"">tr_elmo = NIL;

tr...,P'"">tr_rcrlt-- ;

161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179

c-s

ISDG

trJ) = &'tr_data[dev];

ct &.= 0377;

i f ((tr..Y>tr_cbbits&.( 1«cbno)) = 0) rebrm;

i f ((tr..Y>tr_CAltq.c_oc + ct + 2 + sizeof(lbolt)) >TlQWC)

rebrm;

pIItc(cbno, &'tr..Y>tr_CAltq);

pIItc(ct + sizeof(lbolt), &.tr..Y>tr_CAltq);

cpt = (char *)&.ll:lolt;

for (n = 0; n < sizeof(lbolt); ++n) putc(*cpt++, &.tr..Y>tr3Utq);

for (n=O;n<ct;n++)

pIItc(blf[n], &'tr..Y>tr_CAltq);

tr..Y>tr_:r:cnt++ ;

i f (tr..Y>tr_state&.'mSLEEP) { tr...,p->tr_state &.= 'lRSLE&:P;

wakeup( (caddr_t)&.tr..Y>tr_:r:cnt);

180 /* Copyright (c) 1985 AT&T

199 #include <stdio.h>

200 #include "sys/types.h"

201 #:include "sys/tty.h"

202 #:include "sys/trace.h"

203

210 fprintf(stderr, "Incorrect IlllIIIber of arguments\n");

211 fprintf (stderr , "Usage: trsav mask device\n");

218 setbuf(stdalt, NULL);

219 sscanf(argv[1], "%60", &chbits);

220 i f «k

=

ioctl(fd, ~, chbits» < 0) { 221 perror( "trsav ioctl:");

222 exit(3);

223

APPENDIX C C-7

224 seqno

=

1;

225 far (;;) {

226 if «n

=

read(fd, ev, 512» < 0) {

227 perro:r:( "trsav read:");

228 exit(4);

229 }

230 if (write(1, ev, n) < 0) {

231 perro:r:( "trsav write:");

232 exit(5);

233 }

234 235

C-8 ISDG

236 1* Copyright (c) 1985 AT&T

276 1*

trfmt < 11:l!p/temp.file or

300 #include <stdio.h>

301

321

time1

=

SS'roL(ev.lbolt2, ev.lbolt1);

printf(" %101u%6d", time1, ev.seq);

switch( (int)ev. typ) {

366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382

383 }

384 }

C-12 ISDG

/*

~

=

"ioctl";

printf(" %-8s %2o%70%7o",~,ev.dev,

ev.wd1, ev.wd2);

break;

case '?':

*

Place custan driver reports here.

*

Drivers or Kernel functions which call

*

trsave() can use any ~ definitions

*

and/or print formats deemed appropriate.

*/

default:

printf(" %-10c%20%70%60", ev.typ, ev.dev, ev.wd1, ev.wd2);

printf( "\n");

D Appendix D

Im Dokument INTER ACTIVE (Seite 172-196)