is there a way that I can write my own driver for it?
Yes, of course. Many drivers get written that way.
How difficult of a task is this, for someone who has plenty of C and C-like language development experience, and some embedded development experience, but not any experience developing something like this?
Should be manageable, though you'll have to work your way through how the kernel and the relevant subsystems work. Reading code from existing touchpad drivers should help.
What kind of proper documentation/information would I need from Lenovo's side of things?
Register-level documentation of the touchpad. Which is the hard part, because you are probably not going to get any information from Lenovo.
The alternative is reverse engineering, e.g. an existing Windows driver. This can be very time consuming.
Can anyone suggest links to follow to help with the development process?
Google for something like "linux kernel module tutorial beginner", and variations.
To my understanding, this is developing a driver and not necessarily modifying Linux / the kernel, so should this theoretically be compatible with any distro of Linux OS?
You'll be writing a kernel module ("driver") for a specific Linux kernel version. So this will be compatible with all versions of Linux that have the same API you are using, but we'll have to be changed if the API changes (or won't work for past kernels with a different API).
So, nothing about the touch pad is in there,
The touchpad likely won't be a PCI device. It might connect via USB, via some internal serial port, or even via I2C/SMBUS. Or it might use some proprietary communication method via the EC. You may or may not find hints in the BIOS ACPI tables.
As touchpad connection interfaces are so different, they are one of the most difficult devices to write drivers for, unless you have proper documentation.
How it works (Gnu/Linux + X11)
Overview
It looks something like this (not draws to scale)
┌───────────────────────────────────────────────┐
│ User │
│ ┌─────────────────────────────────────────┤
│ │ Application │
│ │ ┌──────────┬─────┬─────┬─────┤
│ │ │ ... │ SDL │ GTK │ QT │
│ │ ├──────────┴─────┴─────┴─────┤
│ │ │ xLib │
│ │ ├────────────────────────────┤
├─────┴───┬────────┴──┐ X11 │
│ Gnu │ Libraries │ Server │
│ Tools │ │ │
├─────────┘ │ │
├─────────────────────┤ │
│ Linux (kernel) │ │
├─────────────────────┴─────────────────────────┤
│ Hardware │
└───────────────────────────────────────────────┘
We see from the diagram that X11 talks mostly with the hardware. However it needs to talk via the kernel, to initially get access to this hardware.
I am a bit hazy on the detail (and I think it changed since I last looked into it). There is a device /dev/mem
that gives access to the whole of memory (I think physical memory), as most of the graphics hardware is memory mapped, this file (see everything is a file) can be used to access it. X11 would open the file (kernel uses file permissions to see if it can do this), then X11 uses mmap
to map the file into virtual memory (make it look like memory), now the memory looks like memory. After mmap
, the kernel is not involved.
X11 needs to know about the various graphics hardware, as it accesses it directly, via memory.
(this may have changes, specifically the security model, may no longer give access to ALL of the memory.)
Linux
At the bottom is Linux (the kernel): a small part of the system. It provides access to hardware, and implements security.
Gnu
Then Gnu (Libraries; bash; tools:ls, etc; C compiler, etc). Most of the operating system.
X11 server (e.g. x.org)
Then X11 (Or Wayland, or ...), the base GUI subsystem. This runs in user-land (outside of the kernel): it is just another process, with some privileges.
The kernel does not get involved, except to give access to the hardware. And providing inter-process communication, so that other processes can talk with the X11 server.
X11 library
A simple abstraction to allow you to write code for X11.
GUI libraries
Libraries such as qt, gtk, sdl, are next — they make it easier to use X11, and work on other systems such as wayland, Microsoft's Windows, or MacOS.
Applications
Applications sit on top of the libraries.
Some low-level entry points, for programming
xlib
Using xlib, is a good way to learn about X11. However do some reading about X11 first.
SDL
SDL will give you low level access, direct to bit-planes for you to directly draw to.
Going lower
If you want to go lower, then I am not sure what good current options are, but here are some ideas.
Links
X11
https://en.wikipedia.org/wiki/X_Window_System
Modern ways
Writing this got my interest, so I had a look at what the modern fast way to do it is. Here are some links:
https://blogs.igalia.com/itoral/2014/07/29/a-brief-introduction-to-the-linux-graphics-stack/
Best Answer
Given your requirements, it seems likely to me that you may not need to write your own driver. You may be able to use llvmpipe, which I believe conforms to your requirements. In particular, it is a "real driver" by some meanings of the word, and it does not require that X11 be running.
llvmpipe creates what might be called a virtual GPU that interprets OpenGL shaders by converting them on-the-fly to machine language for your CPU and runs it. It uses parts of the LLVM infrastructure to accomplish this.
However, it might not meet your needs, since what is actually going on is that llvmpipe is linked against by the binaries calling it. In other words, this is not a real, live, running-in-the-kernel driver. Instead, it creates an alternative
libGL.so
which interprets your OpenGL shaders.If you're not able to compile your 3D graphics accelerated program from source, you probably cannot use llvmpipe to good effect. (But you want this to help with debugging your own programs, so that shouldn't be a problem.)
You might want to provide more information about what you need, in your question. In particular: Why do you need to debug your code from the driver side? Why can't you put the necessary debugging code in your program itself (or in your programs themselves)? Both X libraries and OpenGL libraries provide information about what went wrong, when a call fails. Why can't you use that information--plus kernel messages--in your program to facilitate debugging? And why would you expect that debugging information you get on the driver side, with a virtual driver implemented in the kernel, would correspond to what actually happens on real computers? More importantly, why would you assume that if your program produces low-level problems, those problems would be the same for different GPU's and drivers when it's run in the real world? You may have perfectly good answers to these questions (plus maybe I'm missing something), but I think it would be easier to answer your question if you explained this.
(By the way, one interesting application of llvmpipe is to enable graphical user interfaces to be written only in 3D-accelerated versions, but still run on computers without 3D acceleration. Theoretically this should facilitate running GNOME Shell without 3D acceleration, though some development work might be necessary to make it actually work; I think GNOME Shell makes some assumptions relating to compositing that might not be automatically fulfilled. Also, there are apparently some performance problems. A real-world instance of this that actually works is Unity, which in Ubuntu 12.10 will come in just one version, and be able to run on top of llvmpipe instead of there being a separate "Unity 2D" implementation.)