Writing A Mouse Driver
Writing device driver?
Linux Device Drivers DOs and DON Ts A guide to writing Robust Linux Device Drivers.
Colette Baron-Reid is a world-renowned Intuitive Counselor, Psychic Medium, TV Personality, Author and Radio Host. They call her the Oracle.
Windows 7 Drivers for Compaq Presario CQ40 Series OS: Windows 7 32-bit Server: Hewlett Packard. Driver-Audio 2 : IDT High Definition Audio CODEC Version.
Free Solaris device drivers This page contains an assortment of free device drivers, and driver writing tips for Solaris, exclusive to bolthole.com.
Shop Staples for the best computer mouse deals. Enjoy everyday low prices and get everything you need for a home office or business.
Trackball design puts cursor control at your fingertips; Ergonomic mouse shape supports your palm; Compact footprint won t clutter your workspace.
Enable writing to NTFS hard drives for free in Mac OS X including El Capitan.
DriverGuide Windows 8, Windows 7, Windows XP Support Forums. Welcome to the Free Drivers Download Request and Support Forums. If this is your first visit, be.
Logitech creates peripherals and devices especially designed for business use. The Logitech wireless mouse can make working on your company laptop or PC easier.
First we will need the set up functions for our mouse device. To keep
this simple our imaginary mouse device has three I/O ports fixed at I/O
address 0x300 and always lives on interrupt 5. The ports will be the X
position, the Y position and the buttons in that order.
define OURMOUSE_BASE 0x300
static struct miscdevice our_mouse
OURMOUSE_MINOR, ourmouse, our_mouse_fops
;
__init ourmouse_init void
if check_region OURMOUSE_BASE, 3
return -ENODEV;
request_region OURMOUSE_BASE, 3, ourmouse ;
misc_register our_mouse ;
return 0;
The miscdevice is new here. Linux normally
parcels devices out by major number, and each device has 256 units.
For things like mice this is extremely wasteful so a device exists
which is used to accumulate all the odd individual devices that
computers tend to have.
Minor numbers in this space are allocated by a central source, although
you can look in the kernel Documentation/devices.txt
file and pick a free one for development use. This kernel file also
carries instructions for registering a device. This may change over time
so it is a good idea to obtain a current copy of this file first.
Our code then is fairly simple. We check nobody else has taken our
address space. Having done so we reserve it to ensure nobody stamps
on our device while probing for other ISA bus devices. Such a probe
might confuse our device.
Then we tell the misc driver that we wish to own a minor number. We also
hand it our name which is used in
/proc/misc and a set of file
operations that are to be used. The file operations work exactly like the
file operations you would register for a normal character device. The misc
device itself is simply acting as a redirector for requests.
Next, in order to be able to use and test our code we need to add some
module code to support it. This too is fairly simple:
ifdef MODULE
int init_module void
if ourmouse_init 0
return -ENODEV:
void cleanup_module void
misc_deregister our_mouse ;
free_region OURMOUSE_BASE, 3 ;
endif
The module code provides the normal two functions. The
init_module function is called when the module is
loaded. In our case it simply calls the initialising function we wrote
and returns an error if this fails. This ensures the module will only
be loaded if it was successfully set up.
The cleanup_module function is called when the
module is unloaded. We give the miscellaneous device entry back, and
then free our I/O resources. If we didn t free the I/O resources then
the next time the module loaded it would think someone else had its I/O
space.
Once the misc_deregister has been called any
attempts to open the mouse device will fail with the error
ENODEV No such device.
Next we need to fill in our file operations. A mouse doesn t need many
of these. We need to provide open, release, read and poll. That makes
for a nice simple structure:
struct file_operations our_mouse_fops
NULL, / Mice don t seek /
read_mouse, / You can read a mouse /
write_mouse, / This won t do a lot /
NULL, / No readdir - not a directory /
poll_mouse, / Poll /
NULL, / No ioctl calls /
NULL, / No mmap /
open_mouse, / Called on open /
NULL, / Flush - 2.2 only /
close_mouse, / Called on close /
There is nothing particularly special needed here. We provide functions
for all the relevant or required operations and little else. There is
nothing stopping us providing an ioctl function for this mouse. Indeed
if you have a configurable mouse it may be very appropriate to provide
configuration interfaces via ioctl calls.
The open and close routines need to manage enabling and disabling the
interrupts for the mouse as well as stopping the mouse being unloaded
when it is no longer required.
static int mouse_users 0; / User count /
static int mouse_dx 0; / Position changes /
static int mouse_dy 0;
static int mouse_event 0; / Mouse has moved /
static int open_mouse struct inode inode, struct file file
if mouse_users
MOD_INC_USE_COUNT;
if request_irq mouse_intr, OURMOUSE_IRQ, 0, ourmouse, NULL
mouse_users--;
MOD_DEC_USE_COUNT;
return -EBUSY;
mouse_dx 0;
mouse_dy 0;
mouse_event 0;
mouse_buttons 0;
The open function has to do a small amount of housework. We keep a count
of the number of times the mouse is open. This is because we do not want
to request the interrupt multiple times. If the mouse has at least one
user then it is set up and we simply add to the user count and return
0 for success.
Firstly we use MOD_INC_USE_COUNT to ensure that
while the mouse is open nobody will unload it and cause a nasty crash.
We must do this before we sleep - and grabbing the interrupt might sleep.
We grab the interrupt and thus start mouse interrupts. If the interrupt
has been borrowed by some other driver then request_irq
will fail and we will return an error. If we were capable of sharing an
interrupt line we would specify SA_SHIRQ instead of
zero. Provided that everyone claiming an interrupt
sets this flag, they get to share the line. PCI can
share interrupts, ISA normally however cannot.
We do the housekeeping. We make the current mouse position the starting
point for accumulated changes and declare that nothing has happened
since the mouse driver was opened.
The release function needs to unwind all these:
static int close_mouse struct inode inode, struct file file
if --mouse_users
We count off a user and provided that there are still other users need
take no further action. The last person closing the mouse causes us to
free up the interrupt. This stops interrupts from the mouse from using
our CPU time, and lets us use MOD_DEC_USE_COUNT so
that the mouse can now be unloaded.
We can fill in the write handler at this point as the write function for
our mouse simply declines to allow writes:
static ssize_t write_mouse struct file file, const char buffer, size_t
count, loff_t ppos
return -EINVAL;
This is pretty much self-explanatory. Whenever you write you get told
it was an invalid function.
To make the poll and read functions work we have to consider how we
handle the mouse interrupt.
static struct wait_queue mouse_wait;
static spinlock_t mouse_lock SPIN_LOCK_UNLOCKED;
static void ourmouse_interrupt int irq, void dev_id, struct pt_regs regs
char delta_x;
char delta_y;
unsigned char new_buttons;
delta_x inb OURMOUSE_BASE ;
delta_y inb OURMOUSE_BASE 1 ;
new_buttons inb OURMOUSE_BASE 2 ;
if delta_x delta_y new_buttons. mouse_buttons
/ Something happened /
spin_lock mouse_lock ;
mouse_event 1;
mouse_dx delta_x;
mouse_dy delta_y;
mouse_buttons new_buttons;
spin_unlock mouse_lock ;
wake_up_interruptible mouse_wait ;
The interrupt handler reads the mouse status. The next thing we do is
to check whether something has changed. If the mouse was smart it would
only interrupt us if something had changed, but let s assume our mouse
is stupid as most mice actually tend to be.
If the mouse has changed we need to update the status variables. What we
don t want is the mouse functions reading these variables to read them
during a change. We add a spinlock that protects these variables while we
play with them.
If a change has occurred we also need to wake sleeping processes, so we
add a wakeup call and a wait_queue to use when
we wish to await a mouse event.
Now we have the wait queue we can implement the poll function for the
mouse relatively easily:
static unsigned int mouse_poll struct file file, poll_table wait
poll_wait file, mouse_wait, wait ;
if mouse_event
return POLLIN POLLRDNORM;
This is fairly standard poll code. First we add the wait queue to the
list of queues we want to monitor for an event. Secondly we check if an
event has occurred. We only have one kind of event - the
mouse_event flag tells us that something happened.
We know that this something can only be mouse data. We return the flags
indicating input and normal reading will succeed.
You may be wondering what happens if the function returns saying no
event yet. In this case the wake up from the wait queue we added to
the poll table will cause the function to be called again. Eventually
we will be woken up and have an event ready. At this point the
poll call will exit back to the user.
After the poll completes the user will want to read the data. We now
need to think about how our mouse_read function
will work:
static ssize_t mouse_read struct file file, char buffer,
size_t count, loff_t pos
int dx, dy;
unsigned char button;
unsigned long flags;
int n;
if count 3
/
Wait for an event
/
while. mouse_event
if file- f_flags O_NDELAY
return -EAGAIN;
interruptible_sleep_on mouse_wait ;
if signal_pending current
return -ERESTARTSYS;
We start by validating that the user is reading enough data. We could
handle partial reads if we wanted but it isn t terribly useful and the
mouse drivers don t bother to try.
Next we wait for an event to occur. The loop is fairly standard event
waiting in Linux. Having checked that the event has not yet occurred, we
then check if an event is pending and if not we need to sleep.
A user process can set the O_NDELAY flag on a file
to indicate that it wishes to be told immediately if no event is
pending. We check this and give the appropriate error if so.
Next we sleep until the mouse or a signal awakens us. A signal will
awaken us as we have used wakeup_interruptible.
This is important as it means a user can kill processes waiting for
the mouse - clearly a desirable property. If we are interrupted we
exit the call and the kernel will then process signals and maybe
restart the call again - from the beginning.
This code contains a classic Linux bug. All will be revealed later in this
article as well as explanations for how to avoid it.
/ Grab the event /
spinlock_irqsave mouse_lock, flags ;
dx mouse_dx;
dy mouse_dy;
button mouse_buttons;
if dx -127
dx -127;
if dx 127
dx 127;
if dy -127
dy -127;
if dy 127
dy 127;
mouse_dx - dx;
mouse_dy - dy;
if mouse_dx 0 mouse_dy 0
spin_unlock_irqrestore mouse_lock, flags ;
This is the next stage. Having established that there is an event
going, we capture it. To be sure that the event is not being updated
as we capture it we also take the spinlock and thus prevent parallel
updates. Note here we use spinlock_irqsave. We
need to disable interrupts on the local processor otherwise bad things
will happen.
What will occur is that we take the spinlock. While we hold the lock
an interrupt will occur. At this point our interrupt handler will try
and take the spinlock. It will sit in a loop waiting for the read
routine to release the lock. However because we are sitting in a loop
in the interrupt handler we will never release the lock. The machine
hangs and the user gets upset.
By blocking the interrupt on this processor we ensure that the lock
holder will always give the lock back without deadlocking.
There is a little cleverness in the reporting mechanism too. We can
only report a move of 127 per read. We don t however want to lose
information by throwing away further movement. Instead we keep
returning as much information as possible. Each time we return a
report we remove the amount from the pending movement in
mouse_dx and mouse_dy. Eventually
when these counts hit zero we clear the mouse_event
flag as there is nothing else left to report.
if put_user button 0x80, buffer
return -EFAULT;
if put_user char dx, buffer 1
if put_user char dy, buffer 2
for n 3; n count; n
if put_user 0x00, buffer n
return count;
Finally we must put the results in the user supplied buffer. We cannot
do this while holding the lock as a write to user memory may sleep.
For example the user memory may be residing on disk at this instant.
Thus we did our computation beforehand and now copy the data. Each
put_user call is filling in one byte of the buffer.
If it returns an error we inform the program that it passed us an
invalid buffer and abort.
Having written the data we blank the rest of the buffer that was read
and report the read as being successful.
I wonder if I understand correctly
Say, if I want to control how my mouse work, i.e Left Button open window, Right Button send keystroke A etc.
But I am not talking about writting something like follows in an application:
void MouseDown xxxxEventArgs e, sender object
I want to completely controls how the device work, then I will need to write a driver for it. From what I learn in assembly before, controlling a device I should need to know their port to communicate with the device. But say if I buy a Logitech mouse, is it possible to write a mouse driver myself to use it.
Because I saw some project that they buy a usb web cam from store, and they could able to control the web came to rotate, recevie the image from the web cam, I wonder if that s because the web cam has API provided them.
Thanks in advance.
Chapter 2. A simple mouse driver