Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 20 Apr 96 11:43:58 -0700
From:      grady@XCF.Berkeley.EDU
To:        freebsd-hackers@freebsd.org
Subject:   Coin-reading LKM code dropped in incoming
Message-ID:  <199604201843.LAA02864@scam.XCF.Berkeley.EDU>

next in thread | raw e-mail | index | archive | help
I wrote a little LKM for reading the game port to determine if
coins had been dropped into a coin slot.  I've put the result in
pub/FreeBSD/incoming/coin.lkm-0.2.tgz.  (There's also a coin.lkm.tgz
which I don't have permission to remove.)  Here's the README (which
is almost as long as the code):
========
(The code was adapted from Hellmuth Michaelis' example LED driver;
this code could also be considered as an example, with a driver
that supports read and select rather than write.)

This driver provides a device that can track how many coins have
been dropped into a coin-slot mechanism.  It reads the first button
on the game port, which is a standard interface for coin-doors in
the video game industry.  (Note that some dollar-bill acceptors
generate clicks equivalent to four times the value of the bill,
thus allowing the same coin code to be used.)

A coin-drop is registered as a game-port button bit turned on for
a duration that is within a certain range -- too short and it is
probably a spurious reading, too long and it is probably a slug.
This code has the range hard-coded as being between 20 and 100
milliseconds.  In order to verify that the minimum time spans two
reads, it is necessary to query the port at least 100 times per
second.

This driver supports open(), close(), read(), and select().  Open()
and close() are standard.  Read() always returns a short containing
the number of coins that been dropped in since the last time the
port was read.  Select() operates in a slightly non-standard way
-- it blocks until read() would return a non-zero value (since
read() always returns a value, select()'s normal behavior of blocking
until the device was ready to read doesn't have any use).

An obvious question is: why use an lkm rather than a user program
that reads the /dev/joy device?  There are three reasons.  First,
because the joystick device is not an LKM.  It is a pain to install
a new kernel just to support reading coins.  Secondly, and more
importantly, there is no guarantee that a user-mode program will
read the device in a timely fashion.  During one test of the
user-mode program, a $20 bill (generating 80 clicks) had only about
65 clicks register, due to other process activity on the system.
A kernel driver, while not _guaranteed_ to process every click, is
not nearly as likely to miss a click.  Finally, putting the code
in the kernel causes _much_ less overhead.  The user-level program
(consisting of Tcl plus a device-reading extension) used about 2%
of the CPU, and imposed the additional loads of constant context
switches, and a non-trivial resident set.  In contrast, this device
uses only a few K, and the reading program can now be swapped out
until the select() returns.

This is the minimal driver that supported my requirements.  There
are obvious possible extensions, including:
    handling multiple buttons on a single port
    handling multiple ports
    supporting ioctls to change the currently hard-coded constants
All of these are simple, but I didn't need to do them, so I didn't
bother...

Included in this distribution is a sample program, catcoin.c, that
reads the current value from the /dev/coin device.  With an argument,
it blocks until a coin is dropped in.

Note that "isa.h" is also included.  It is a copy of
/usr/src/sys/i386/isa/isa.h, which is not put under the /usr/include
tree, so may not be available to someone compiling this code.
It is only used to get the game port address.

    Steven Grady
    grady@xcf.berkeley.edu
========

	Steven



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199604201843.LAA02864>