From: email@example.com (Linus Torvalds)
Subject: Re: Fix for maestro in 2.3.99-preX
Date: 17 Apr 2000 09:15:20 -0700
In article <firstname.lastname@example.org>,
Jes Sorensen <Jes.Sorensen@cern.ch> wrote:
>Some of us are trying to maintain drivers that are being used both in
>2.2.x and 2.3.x - having the compatibillity code stripped out
>regularly from someone making a quick hack in the 2.3.x tree is a
It's a major pain just because you do it wrong.
A lot of network drivers have this bass-ackwards way of maintaining both
2.3.x and 2.2.x drivers- they do something like
#ifdef LINUX_VERSION_CODE > 0x20139
struct net_device_stats stats;
struct enet_statistics stats;
or something like
#if (LINUX_VERSION_CODE < 0x02030d)
dev->base_addr = pdev->base_address;
dev->base_addr = pdev->resource.start;
and they do this in the middle of code that makes it fairly unreadable.
And then people complain when 2.3.x cleans stuff up, and removes those
stupid things. Without realizing that the cleaned up version is often
much better, and _can_ be made to work with the older kernels too.
What you can much more cleanly do in almost all cases is to have a
"forwards compatibility" layer, so that you can write the driver for the
current code, and then still be able to compile it for 2.2.x. And that
forwards compatibility code doesn't even need to be in the recent
kernels: after all, it is really only needed on the =old= setups.
Why do it that way? The BIG reason for doing it this way is that by
putting the compatibility code into _old_ kernels when supporting a
driver like that, you don't perpetuate the code. It automatically and
magically just gets dropped whenever people don't care enough about
older versions, because it's not carried around in the new code.
Example of how this _can_ be done (network drivers are the best example,
simply because there are so many of them, and because there are some
recent changes to how they operate that people still remember):
- use the new operations everywhere. That means using
WITHOUT any #ifdef's. They =do= work on 2.2.x too, with minimal glue
(and that glue should be maintained in the 2.2.x tree, not in the
- use things like "pci_resource_start()" which have been added
explicitly to make it easier to do certain backport things. It's
defined in 2.3.x, and not defined in 2.2.x, but again you can have
trivial backwards compatibility glue to take care of the issue. And
again, the compatibility crud goes into the _old_ tree.
So for example, the backwards compatibility crud in 2.2.x (which doesn't
even need #ifdef's, because it only exists in 2.2.x) would look
#define net_device device
#define net_device_stats enet_statistics
#define dev_kfree_skb_irq(a) dev_kfree_skb(a)
#define netif_wake_queue(dev) clear_bit(0, &dev->tbusy)
#define netif_stop_queue(dev) set_bit(0, &dev->tbusy)
#define netif_queue_stopped(dev) ((dev)->tbusy != 0)
#define netif_running(dev) ((dev)->start != 0)
static inline void netif_start_queue(struct net_device *dev)
dev->tbusy = 0;
dev->start = 1;
#define pci_resource_start(dev,bar) \
#define module_init(x) ...
and you're now almost done. With a clean driver, and without any
#ifdef's AT ALL.
(Yes, there are still going to be details, but you're getting the
picture on how this should work).
Now, one argument is commonly that "but you can't change old kernels, so
the old kernels cannot have new interfaces added to them when a
development kernel changes". And that argument is _bogus_. Because if
you truly don't change old kernels, then you also don't need to have any
backwards compatibility AT ALL, because the old driver will obviously
continue to work (or not work) forever unchanged.
This is why I do not want to add compatibility files to development
kernels. It's the wrong thing to do, because adding compatibility files
to new kernels always implies carrying baggage around forever. Adding
the compatibility files to old kernels is conceptually the right thing
to do: it tells you (in the right place) that old kernels are still