Search this site


Metadata

Articles

Projects

Presentations

newpsm framework - A new mouse driver framework for FreeBSD 7.x

Abstract

FreeBSD's psm(4) driver is well over 3000 lines long. It supports 12 kinds of mice. moused(8) supports another 15 kinds mice. Between ums(4), psm(4), and moused(8), there is a great deal of redundancy and mess in the source code. Furthermore, moused(8) is a userland utility while psm(4) is a kernel driver. I believe that all mouse support should come primarily from a userland utility, such as moused(8). This will allow the psm(4) driver to provide the bare minimum and allow specific mice support to be written as plugins for moused(8).

Goals

  • Write psm(4) somewhat from scratch to provide moused(8) with a means of accessing in a fairly raw manner.
  • Write a basic moused(8) that provides a useful API for describing mouse actions and supports plugins loadable at run-time (aswell as probing for mice features)

Documentation

If you are interested in reading more in-depth about this project, see the following links:

Test it!

You will need to be building with -CURRENT for this to definitely work. I have not tested this on 5.x or 6.x.

Download this patch: patch-CURRENT-Apr.13.06.newpsm+newpsm

Apply the patch (You need /usr/src checked out already):
patch -p0 < patch-CURRENT-Apr.13.06.newmoused+newpsm
Rebuild world with '-DNEWMOUSE' and recompile your kernel with 'device newpsm' and NOT 'device psm'
make buildworld -DNEWMOUSE
make installworld -DNEWMOUSE
Reboot, and you should be good to go. If you have a ps/2 mouse plugged in, you should see:
psm0: <(new) PS/2 Mouse> irq 12 on atkbdc0
The keyword there is (new).

Assuming everything is OK, you can now try the newmoused. The default device is /dev/psm0. The default driver option is to try all modules and pick the first one that succeeds.
For non-synaptics ps/2 mice:
Run: "moused"
The default mouse device is /dev/psm0
For synaptics ps/2 mice:
Run: "moused -m synaptics"
This will force moused to try the synaptics module
For USB mice:
Run: "moused -d /dev/ums0"
For mse(4) mice:
Run: "moused -d /dev/mse0"

Usage

  • -f : run in foreground
  • -3 : Emulate 3 button
  • -E XXX : emulate 3 button timeout
  • -V : Virtual scrolling
  • -U XXX : virtual scrolling threshold
  • -a X[,Y] : acceleration with x and y (optional) multiplier
  • -d dev : specify mouse device
  • -m module : specify module name
  • -v : increase verbosity (default 0, -ddd means 3)
  • -h : usage

Configuration File

You can now configure mice via a config file. Format is the same as a termcap file. Read this page for specific information about the configuration file. The config file location is "/etc/moused.conf"

Progress

You can check on what I've done through p4web: View my p4 depot on perforce.freebsd.org
  • newpsm driver stubbed out and written. (may be scrapped)
  • the old psm driver needs to be split. It has a part called psmcpnp that needs to become it's own separate driver.
  • Add per-driver configuration

Roadmap

  • new moused module-happy framework
  • strip psm(4) of protocol knowledge
  • 3 basic drivers: synaptics, geneirc ps/2, and sysmouse
  • Have progress committed to -CURRENT and co-exist with existing moused and psm
  • Profit
  • Kill existing moused and psm
  • Kill ums in favor of uhid-userland driver
  • Naptime

Uncompleted Tasks (Todo)

  • Deal with ums(4) - kill it and move it to userland?
  • start newpsm(4) - include extremely basic functionality: probing, attaching, detaching, open, read, etc (might be scrapped)
  • Provide module(s?) for mice handled by old psm(4)
  • Add uhid joystick module?
  • Remove Giant from psm(4)
  • Conform to style(9)
  • Port up lots of serial mice drivers from the old moused(8)
  • Nap time
  • PS/2 and usb test/probe application
  • Bluetooth support
  • Driver example code

Completed Tasks (To... done?!)

  • Driver-writing documentation
  • start moused(8) manpage - basic commandline options (-p, etc) and reading from newpsm.
  • moused - configuration via config files
  • moused - write a synaptics module
  • moused - write a ps/2 generic pass-through plugin
  • moused - write some basic filters (emulate 3 button, etc)
  • moused - write a ums (sysymouse?) module
  • moused - write a plugin interface for loadable userland mouse drivers.

Ideas?

newpsm(4) will only provide a more-or-less raw interface with a connected ps/2 mouse. I don't know right now whether or not the X ps/2 mouse driver will still work, but we'll see. If it doesn't, I'll look into having newpsm provide a generic ps/2 interface X will understand with an ioctl that lets you switch between generic ps/2 and raw.

I'm still trying to get my feet wet with both FreeBSD's kernel and talking to hardware, so a lot of my ideas are probably misguided.

I recently bought a new keyboard (IBM USB Travel Keyboard with UltraNav) which has a synaptics touchpad and trackpoint for mice. The trackpoint and touchpad come up as two separate uhid devices . The windows driver probably supports lots of things like pressure sensitivity, touchpad-scrolling, etc. The protocol may or may not be uhid, I don't know.

Known Issues

  • Microsoft Explorer Mouse 4.0A acts very strangely under ums/moused.
  • Synaptics USB (on my thinkpad ultranav travel keyboard) seems to act funny with moused, though I've only used it for 5 minutes so far.
  • atkdbcreg.h defines PSM_MOUSE_ID, PSM_INTELLI_ID, and others. Shouldn't this be in a more mouse-specific place?
  • psm needs GIANT, why? More research is required, or someone should just tell me.

new psm design

The new psm kernel driver only provides the bare minimum features. All of the ioctls have been stripped and replaced with, essentially, MOUSE_COMMAND and MOUSE_SET_SYNCBITS. Every other activity has been moved to the userland in the form of moused's libps2, a ps/2 protocol library. Such actions as the old MOUSE_SET_RESOLUTION are replaced by libps2/s ps2_set_resolution() which in-turn calls MOUSE_COMMAND using an ioctl on /dev/psm0.

This moves all of the real work handling the mouse to the userland and provides a much more flexible model for implementing mice drivers.

new moused design

moused: slimmed down

The new moused(8) will provide a minimum api for the plugin drivers to access. The api should provide means to pass state deltas (x, y, and other changes) with little else. What kinds of data will a mouse driver need to convey? However, deltas may not be the easiest way of transmitting button changes from the driver to moused. I'm not sure yet. At any rate, the delta will be in the form of passing a structure back to moused(8) containing x, y, z1, z2, and button deltas. I'm not sure if this should be of the callback form where moused calls the plugin for data, or if the plugin loops itself. However, seeing as how plugins (drivers) should do the least amount of OS-level work, but instead act as liasons between hardware and the OS, I think the read loop should go in moused itself. This should be the easy part.

plugin structure

The plugin structure will work similiarly to how the freebsd kernel object system works. Plugins will provide functions to probe for mice, read from mice, and reset mice. Probing will be used to detection of mice given the mouse type of "auto" to moused. It will also be used to make sure the right plugin is used if a user specifies what plugin to use. Plugins will be shared objects loaded during runtime with dlopen(3).

Modules will be provided with protocol libraries to aid in the creation of new modules. The ps/2 protocol library has already been created and will help developers write new drivers for ps/2 mice.

filters

Filters may be a good idea, but their lifespan/usefulness may be short, I haven't decided yet. However, the goal behind them is something I consider to be a good idea, so moused(8) may provide these natively instead of using output filters. The premise behind filters would be to manipulate the output of moused before it hits the device (and thus, the OS). Such filters could be to add features interpreted from the deltas. For example, a recent patch I made to moused(8) added "virtual scrolling" - this could be implemented in a filter so that this feature would be accessible regardless of the plugin driver. Another such example is the "emulate 3 button mouse" feature provided again by the current moused(8) using the -3 option. However, I don't know if there are enough delta-reactive features (like virtual scrolling) to be written that would merit a filter framework. This requires further discussion and brainstorming. A short list of some useful features I can come up with are:
  • Emulate 3 button mouse
  • Virtual Scrolling (Vertical/Horizontal)
  • X/Y acceleration
  • Physical to Logical button mapping
  • Z-Axis activity (moused -z option)
  • Jitter correction/smoothing
Many of these have already been written. Check moused/filters.c for what I have done.

newpsm - goals

Completed Project Goals

  • Design and test new userland mouse driver framework
  • Refactor psm(4) to provide command, packet size, and sync byte ioctls
  • psm and synaptics support under new moused
  • sysmouse (Old mouse) support in new moused
  • Recruit testers and solicit developer advice
  • Fix synaptics startup problems
  • Rework startup procedure to reduce redundant code
  • Write better acceleration algorithm (linear vs exponential)
  • Config file support
  • Bug fix parade
  • Prove workingness by using new psm and moused on my laptop (synaptics, sysmouse, and generic drivers)

Uncompleted Goals

  • USB-in-userland mouse driver
  • Have code committed
  • Port-up serial mice drivers from old moused (especially mousesystems)

Future Goals

  • Conform to style(9)
  • Look into bluetooth mice
  • Remove Giant mutex from psm(4)
  • USB Gamepad mouse module
  • UHID(hopefully?) remote control presentation tools modules

new moused modules guide - Developer guide to writing modules for new moused

Abstract

Mouse modules are simply userland drivers that translate raw data from hardware devices. Modules are standalone, and require little more than knowledge of how to understand the mouse to write.

Includes

First thing, you'll need to include a few header files:
#include <sys/types.h>
#include <sys/mouse.h> /* May not be needed */
#include <moused.h>

/* If you need to use the ps2 library: */
#include <ps2.h>
Those should get you started.

The rodent_t Structure

The rodent_t structure has many members of interest to you:
char *device
The path of the mouse device
int mfd
The file descriptor of the mouse device
char *packet
Buffer for storing packets. Dynamically allocated based on rodent_t.mode.packetsize
int (*update)(struct mouse_info *t)
Function to call when pushing movement updates

Function Overview

For every MOUSE_*_FUNC functin, you can expect to be passed a rodent_t pointer.

The following functions exist:
MOUSED_INIT_FUNC
Used to initialize your mouse module. Perform any necessary configuration and other setup here. Do NOT probe mice.
MOUSED_PROBE_FUNC
Probe the given mouse for functionality. This function should be used to test if the mouse we have opened is somethin we can handle.
MOUSED_HANDLER_INIT_FUNC
Initialization function called before the main loop of moused is entered. Do NOT probe mice. This function should be used to prepare data structures before the main loop is run.
MOUSED_HANDLER_FUNC
This is called every time a packet is available for reading from the mouse. It is up to you to read data from the mouse.

Initialization

The init function is declared like this:
MOUSED_INIT_FUNC {
	/* Initialization code here */
}

Probe

This function should test the mouse for features. That is, you should test the mouse device (however necessary) to check if it is the kind of mouse your module supports.

For instance, the synaptics module tests the ps/2 mouse by attemptig an extended status request. If this fails or otherwise indicates that no synaptics device is present, then it is clearly not a synaptics mouse, and we should fail.

The following return values are expected:
MODULE_PROBE_FAIL
Indicates that mouse type tests failed, and to not use this module
MOUSE_PROBE_SUCCESS
Indicate successful mouse probe. This mouse can be handled by this module

Handler Initialization

Last-minute changes to any data needed before the moused main loop is entered. This includes things such as setting expected packet size (In ps/2 drivers), enabling magic features such as Absolute mode (for synaptics).

PS/2 drivers should set the following at this point:
  • sync mask
  • packet size (don't forget to update rodent->mode.packetsize)
  • ps2_enable_stream(), if necessary

Handler Function

The handler function is expected to read one "packet" of data per function call. That is, only process one piece of mouse activity per call.

A typical order of operations is:
  • Read a packet
  • Check for proper byte length (if necessary)
  • Parse the packet for mouse data
  • Set values in a mouse_info_t variable
  • Call rodent->update(&(mouse_info_t variable))

Summary

Modules are meant to be simple to write. All you need to care about is understanding the raw mouse data and push movement deltas up through moused with the update function..

newpsm framework - description - Details and benefits over the Old Ways

The Old Ways

The old ways are dark. They are known to cause birth defects. Or something...

The old design of mouse magic in FreeBSD appears somewhat ad-hoc. psm(4) stands on it's own, as does ums(4), and mse(4). moused(8) can be used, optionally. Independently, all three mouse drivers can be used as input to X. Without moused(8), you don't get a mouse in the console (if you want one). moused(8) can direct multiple mice through the sysmouse(4) device, allowing you to present X (or others) with one single mouse device. This is great, and allows you to hotplug mice and not need to reconfigure or restart X to use it.

A problem with this setup is the fact that protocol handlers are all over the place. psm(4) supports a number of mice, ums(4) has hacks to support different "broken" mice aswell as standard uhid mice. and mouse(8) itself supports a number of other mice magic as well.

Adding new ps/2 mice drivers to psm(4) requires hacking code in 3 or 4 different places (if not more) of psm.c. This may not seem all that bad, except it is further hindered by the fact that you have to reboot every time you want to test your code. Compound that with kernel segfaults result in panics, and you have a very difficult environment in which to write new mouse drivers.

The same goes for ums(4), though uhid is a bit easier to deal with.

Furthermore, moused(8) itself is awkward to hack on. Rather, that has been my experience. Feature magic such as emulate-3-button is intertwined amongst other unrelated logic, making debugging annoying and making it annoying to write new features due to the entangled nature of the code.

I'm not trying to say "this sucks" as an offense to the developers who worked on these projects. I simply believe there is a better way to do it.

To summarize, the problems with the old way are:
  • Protocol magic is handled in many different places
  • Design is not modular and does not lend itself to easy feature additions
  • Kernel-land makes for difficult "trial and error" tweaking

The New Hotness

The new design is based upon a few ideas:
  • All protocol magic should be handled by moused
  • Kernel devices should report raw data only
  • Drivers are implemented in the form of loadable modules
  • Magic features (ie; emulate 3 buttons) should be modular and independent
I'll address these individually.

Protocol Magic

Instead of having ums(4) or psm(4) have a deep understanding of their respective protocols, they should report data, unmodified, from the hardware.

That is, instead of psm(4) providing Synaptics Touchpad support, a userland driver module should provide this support. psm(4) should merely act as a hardware-to-userland interface, and a dumb one at that.

Raw Data

psm: The new psm kernel driver should allow protocol commands to be transmitted from the userland to the hardware via ioctl(2). Such commands include setting packet size, data checksum information, and little else. Movement data is transmitted using read(2) and will report data of instructed packet size. The packet size defaults to 3, the "real" PS/2 protocol's packet size.

ums: ums simply fronts for uhid(4). Therefore, I believe ums(4) should be moved to a userland moused module, which reads from uhid(4) devices.

No protocol understanding is required for the new psm to function, becuase all it does is proxy commands and data between hardware and the userland.

Userland driver modules

Mouse-specific drivers will be implemented in userland loadable modules. A module will provide certain functions such as probing and data handling.

The probe function is responsible for two things:
  • Test if the mouse is a specific kind of mouse by..
  • Enabling extended features of the specified mouse
If the probe succeeds, then we can go about using this module as our mouse driver. If it fails, then return failure to indicate that this module cannot understand this mouse.

The handler function is called whenever new data is available from the mouse device. New data is detected using the select(2) system call. The handler function is expected to read data from the given mouse device and process it as necessary. Updates are conveyed by calling an update function with a structure containing the activity data.

Magic features AKA filters

Features such as emulate-3-button, chordmiddle, acceleration, button remapping, jitter correction, and virtual scrolling, are all what I would consider post-process filters. They are used to modify the activity structure after the driver module has processed a new piece of activity data.

For instance, the button mapping filter would map the reported mouse button to another mapping, such as swapping left and right mouse button actions. That is, the reports "right mouse button held" and this filter would change it to "left mouse button held." This is extremely useful.

Filters in the old moused(8) are not modular. They are grossly intertwined with other unrelated code. In the new moused(8), filters are independent functions. As as result, post processing filters are chained.

This chaining allowed you to have "emulate 3 button" and "virtual scroll" enabled at the same time. "emulate 3 button" will send faked middle-mouse button activity if both left and right buttons are pressed at the same time. "virtual scroll" will change movements into scrolling activity while the middle mouse button is held. "emulate 3 button" is called before "virtual scroll" is called. Therefore, if you have both enabled, you can press left and right buttons together, and scroll up and down by moving the mouse up and down. This is not possible with the old moused(8) implementation.

Per-mouse configuration

The new moused(8) also provides a means to configure each specific mouse. The syntax is that of termcap entries.

For example, on my laptop I have the following configuration:
 synaptics:virtscroll:notouchpad: 
This enables "virtual scrolling" only for synaptics and disables the touchpad. I have a T41 and it has a trackpoint and touchpad, both show up via the same psm(4) device.

Another example (unimplemented) may look like this, if you have a fancy logitech MX100 mouse:
usb:type=MX1000:maptokey:9=F5
Assuming I do this (might be useful), 'maptokey' would map a button press to a keyboard key stroke. Here, mouse button 9 would get mapped to "F5" - Keep in mind that I have not implemented this yet. More research is required :)

Framework Comparison

For some flow-chart-ey goodness, see the following:

Old mouse diagram:

New mouse diagram

newpsm framework - A new mouse driver framework for FreeBSD 7.x

Abstract

FreeBSD's psm(4) driver is well over 3000 lines long. It supports 12 kinds of mice. moused(8) supports another 15 kinds mice. Between ums(4), psm(4), and moused(8), there is a great deal of redundancy and mess in the source code. Furthermore, moused(8) is a userland utility while psm(4) is a kernel driver. I believe that all mouse support should come primarily from a userland utility, such as moused(8). This will allow the psm(4) driver to provide the bare minimum and allow specific mice support to be written as plugins for moused(8).

Goals

  • Write psm(4) somewhat from scratch to provide moused(8) with a means of accessing in a fairly raw manner.
  • Write a basic moused(8) that provides a useful API for describing mouse actions and supports plugins loadable at run-time (aswell as probing for mice features)

Test it

You'll need atleast FreeBSD 6.x (or -CURRENT) for this to work.

  • Get the source here: newmoused.tar.gz
  • Unpack: tar -zxf newmoused.tar.gz
  • For -CURRENT users:
    • cd /usr/src
    • patch -p0 < path/to/newmoused/newpsm/psm-current.patch
    • Recompile your kernel WITHOUT psm.
    • cd /usr/src/sys/modules >
    • make -C psmcpnp all load
    • make -C psm all load
  • For 6.x users:
    • Recompile your kernel WITHOUT psm.
    • cd newmoused/newpsm/oldpsm/modules
    • cp ../sys/mouse.h /usr/src/sys/sys/mouse.h (yes, I mean 'sys/sys/')
    • make -C psmcpnp all load
    • make -C psm all load
  • Check dmesg(1) for psm0 showing up, becuase it should.
  • cd path/to/newmoused/moused
  • make all
  • cp ../newpsm/oldpsm/sys/mouse.h /usr/include/sys/mouse.h
  • make -C lib/ps2/ all install
  • make -C modules/synaptics all install
  • make -C modules/sysmouse all install
  • make -C modules/generic all install
Installing libps2 and the moused modules will not overwrite anything already existing in the system. It is safe to install them. Now, try running moused:
  • if you have synaptics: ./moused -m synaptics
  • if you have another ps/2 mouse: ./moused -m generic
  • if you use ums: ./moused -m sysmouse -d /dev/ums0
Build Problems?
Compilation errors with psm(4) regarding 'MOUSE_COMMAND' not being defined:
You didn't properly patch sys/sys/mouse.h.
cp newmoused/newpsm/oldpsm/sys/mouse.h /usr/src/sys/sys/mouse.h
Compilation errors with libps2
Make sure you copied my mouse.h to /usr/include/sys/mouse.h
Patches to bugs:
Synaptics taphold (leftbutton down) always triggers after a tap and a finger-down
Patch: synaptics-tapholdclick.patch.
cd newmoused/moused/modules/synaptics/
patch < synaptics-tapholdclick.patch
Current issues:
  • Synaptics support has a few issues probably due to incomplete porting from the psm(4) implementation and the new module. It still works, however, for me.
  • The X "sysmouse" driver will no longer work on /dev/psm0. This is becuase X expects the 'sysmouse' mouse protocol and it gets whatever the mouse spits out. You MUST use moused from now on.
If you get compilation errors, email me and I'll help you get them fixed.

Progress

You can check on what I've done through p4web: View my p4 depot on perforce.freebsd.org
  • newpsm driver stubbed out and written.
  • the old psm driver needs to be split. It has a part called psmcpnp that needs to become it's own separate driver.

Roadmap

  • start newpsm(4) - include extremely basic functionality: probing, attaching, detaching, open, read, etc
  • start moused(8) - basic commandline options (-p, etc) and reading from newpsm.
  • moused - write a plugin interface for loadable userland mouse drivers.
  • moused - write some basic filters (emulate 3 button, etc)
  • moused - write a ps/2 generic pass-through plugin
  • moused - write a synaptics module
  • moused - write a ums (sysymouse?) module
  • ums(4) - make new mice work well with this

Ideas?

newpsm(4) will only provide a more-or-less raw interface with a connected ps/2 mouse. I don't know right now whether or not the X ps/2 mouse driver will still work, but we'll see. If it doesn't, I'll look into having newpsm provide a generic ps/2 interface X will understand with an ioctl that lets you switch between generic ps/2 and raw.

I'm still trying to get my feet wet with both FreeBSD's kernel and talking to hardware, so a lot of my ideas are probably misguided.

I recently bought a new keyboard (IBM USB Travel Keyboard with UltraNav) which has a synaptics touchpad and trackpoint for mice. The trackpoint and touchpad come up as two separate uhid devices . The windows driver probably supports lots of things like pressure sensitivity, touchpad-scrolling, etc. The protocol may or may not be uhid, I don't know.

Known Issues

  • Microsoft Explorer Mouse 4.0A acts very strangely under ums/moused.
  • Synaptics USB (on my thinkpad ultranav travel keyboard) seems to act funny with moused, though I've only used it for 5 minutes so far.
  • atkdbcreg.h defines PSM_MOUSE_ID, PSM_INTELLI_ID, and others. Shouldn't this be in a more mouse-specific place?
  • psm needs GIANT, why? More research is required, or someone should just tell me.

new psm design

The new psm kernel driver only provides the bare minimum features. All of the ioctls have been stripped and replaced with, essentially, MOUSE_COMMAND and MOUSE_SET_SYNCBITS. Every other activity has been moved to the userland in the form of moused's libps2, a ps/2 protocol library. Such actions as the old MOUSE_SET_RESOLUTION are replaced by libps2/s ps2_set_resolution() which in-turn calls MOUSE_COMMAND using an ioctl on /dev/psm0.

This moves all of the real work handling the mouse to the userland and provides a much more flexible model for implementing mice drivers.

new moused design

moused: slimmed down

The new moused(8) will provide a minimum api for the plugin drivers to access. The api should provide means to pass state deltas (x, y, and other changes) with little else. What kinds of data will a mouse driver need to convey? However, deltas may not be the easiest way of transmitting button changes from the driver to moused. I'm not sure yet. At any rate, the delta will be in the form of passing a structure back to moused(8) containing x, y, z1, z2, and button deltas. I'm not sure if this should be of the callback form where moused calls the plugin for data, or if the plugin loops itself. However, seeing as how plugins (drivers) should do the least amount of OS-level work, but instead act as liasons between hardware and the OS, I think the read loop should go in moused itself. This should be the easy part.

plugin structure

The plugin structure will work similiarly to how the freebsd kernel object system works. Plugins will provide functions to probe for mice, read from mice, and reset mice. Probing will be used to detection of mice given the mouse type of "auto" to moused. It will also be used to make sure the right plugin is used if a user specifies what plugin to use. Plugins will be shared objects loaded during runtime with dlopen(3).

Modules will be provided with protocol libraries to aid in the creation of new modules. The ps/2 protocol library has already been created and will help developers write new drivers for ps/2 mice.

filters

Filters may be a good idea, but their lifespan/usefulness may be short, I haven't decided yet. However, the goal behind them is something I consider to be a good idea, so moused(8) may provide these natively instead of using output filters. The premise behind filters would be to manipulate the output of moused before it hits the device (and thus, the OS). Such filters could be to add features interpreted from the deltas. For example, a recent patch I made to moused(8) added "virtual scrolling" - this could be implemented in a filter so that this feature would be accessible regardless of the plugin driver. Another such example is the "emulate 3 button mouse" feature provided again by the current moused(8) using the -3 option. However, I don't know if there are enough delta-reactive features (like virtual scrolling) to be written that would merit a filter framework. This requires further discussion and brainstorming. A short list of some useful features I can come up with are:
  • Emulate 3 button mouse
  • Virtual Scrolling (Vertical/Horizontal)
  • X/Y acceleration
  • Physical to Logical button mapping
  • Z-Axis activity (moused -z option)
  • Jitter correction/smoothing
Many of these have already been written. Check moused/filters.c for what I have done.