11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***    ltpc.c -- a driver for the LocalTalk PC card.
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Copyright (c) 1995,1996 Bradford W. Johnson <johns393@maroon.tc.umn.edu>
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      This software may be used and distributed according to the terms
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      of the GNU General Public License, incorporated herein by reference.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      This is ALPHA code at best.  It may not work for you.  It may
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      damage your equipment.  It may damage your relations with other
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      users of your network.  Use it at your own risk!
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      Based in part on:
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      skeleton.c      by Donald Becker
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      dummy.c         by Nick Holloway and Alan Cox
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      loopback.c      by Ross Biro, Fred van Kampen, Donald Becker
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      the netatalk source code (UMICH)
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      lots of work on the card...
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      I do not have access to the (proprietary) SDK that goes with the card.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      If you do, I don't want to know about it, and you can probably write
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      a better driver yourself anyway.  This does mean that the pieces that
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      talk to the card are guesswork on my part, so use at your own risk!
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      This is my first try at writing Linux networking code, and is also
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      guesswork.  Again, use at your own risk!  (Although on this part, I'd
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      welcome suggestions)
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      This is a loadable kernel module which seems to work at my site
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      consisting of a 1.2.13 linux box running netatalk 1.3.3, and with
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      the kernel support from 1.3.3b2 including patches routing.patch
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      and ddp.disappears.from.chooser.  In order to run it, you will need
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      to patch ddp.c and aarp.c in the kernel, but only a little...
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      I'm fairly confident that while this is arguably badly written, the
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      problems that people experience will be "higher level", that is, with
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      complications in the netatalk code.  The driver itself doesn't do
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      anything terribly complicated -- it pretends to be an ether device
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      as far as netatalk is concerned, strips the DDP data out of the ether
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      frame and builds a LLAP packet to send out the card.  In the other
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      direction, it receives LLAP frames from the card and builds a fake
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      ether packet that it then tosses up to the networking code.  You can
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      argue (correctly) that this is an ugly way to do things, but it
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      requires a minimal amount of fooling with the code in ddp.c and aarp.c.
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      The card will do a lot more than is used here -- I *think* it has the
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      layers up through ATP.  Even if you knew how that part works (which I
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      don't) it would be a big job to carve up the kernel ddp code to insert
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      things at a higher level, and probably a bad idea...
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      There are a number of other cards that do LocalTalk on the PC.  If
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      nobody finds any insurmountable (at the netatalk level) problems
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      here, this driver should encourage people to put some work into the
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      other cards (some of which I gather are still commercially available)
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      and also to put hooks for LocalTalk into the official ddp code.
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      I welcome comments and suggestions.  This is my first try at Linux
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      networking stuff, and there are probably lots of things that I did
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *      suboptimally.
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ***/
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * $Log: ltpc.c,v $
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.1.2.1  2000/03/01 05:35:07  jgarzik
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * at and tr cleanup
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.8  1997/01/28 05:44:54  bradford
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clean up for non-module a little.
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Hacked about a bit to clean things up - Alan Cox
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Probably broken it from the origina 1.8
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1998/11/09: David Huggins-Daines <dhd@debian.org>
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Cleaned up the initialization code to use the standard autoirq methods,
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   and to probe for things in the standard order of i/o, irq, dma.  This
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   removes the "reset the reset" hack, because I couldn't figure out an
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   easy way to get the card to trigger an interrupt after it.
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Added support for passing configuration parameters on the kernel command
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   line and through insmod
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Changed the device name from "ltalk0" to "lt0", both to conform with the
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   other localtalk driver, and to clear up the inconsistency between the
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   module and the non-module versions of the driver :-)
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Added a bunch of comments (I was going to make some enums for the state
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   codes and the register offsets, but I'm still not sure exactly what their
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   semantics are)
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Don't poll anymore in interrupt-driven mode
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It seems to work as a module now (as of 2.1.127), but I don't think
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds   I'm responsible for that...
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.7  1996/12/12 03:42:33  bradford
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DMA alloc cribbed from 3c505.c.
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.6  1996/12/12 03:18:58  bradford
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Added virt_to_bus; works in 2.1.13.
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.5  1996/12/12 03:13:22  root
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * xmitQel initialization -- think through better though.
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.4  1996/06/18 14:55:55  root
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Change names to ltpc. Tabs. Took a shot at dma alloc,
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * although more needs to be done eventually.
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.3  1996/05/22 14:59:39  root
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Change dev->open, dev->close to track dummy.c in 1.99.(around 7)
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.2  1996/05/22 14:58:24  root
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Change tabs mostly.
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 1.1  1996/04/23 04:45:09  root
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initial revision
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 0.16  1996/03/05 15:59:56  root
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Change ARPHRD_LOCALTLK definition to the "real" one.
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 0.15  1996/03/05 06:28:30  root
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Changes for kernel 1.3.70.  Still need a few patches to kernel, but
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it's getting closer.
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 0.14  1996/02/25 17:38:32  root
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * More cleanups.  Removed query to card on get_stats.
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 0.13  1996/02/21  16:27:40  root
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Refix debug_print_skb.  Fix mac.raw gotcha that appeared in 1.3.65.
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clean up receive code a little.
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 0.12  1996/02/19  16:34:53  root
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fix debug_print_skb.  Kludge outgoing snet to 0 when using startup
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * range.  Change debug to mask: 1 for verbose, 2 for higher level stuff
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * including packet printing, 4 for lower level (card i/o) stuff.
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 0.11  1996/02/12  15:53:38  root
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Added router sends (requires new aarp.c patch)
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 0.10  1996/02/11  00:19:35  root
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Change source LTALK_LOGGING debug switch to insmod ... debug=2.
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 0.9  1996/02/10  23:59:35  root
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fixed those fixes for 1.2 -- DANGER!  The at.h that comes with netatalk
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has a *different* definition of struct sockaddr_at than the Linux kernel
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does.  This is an "insidious and invidious" bug...
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (Actually the preceding comment is false -- it's the atalk.h in the
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ancient atalk-0.06 that's the problem)
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 0.8  1996/02/10 19:09:00  root
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Merge 1.3 changes.  Tested OK under 1.3.60.
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 0.7  1996/02/10 17:56:56  root
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Added debug=1 parameter on insmod for debugging prints.  Tried
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to fix timer unload on rmmod, but I don't think that's the problem.
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 0.6  1995/12/31  19:01:09  root
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clean up rmmod, irq comments per feedback from Corin Anderson (Thanks Corey!)
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clean up initial probing -- sometimes the card wakes up latched in reset.
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 0.5  1995/12/22  06:03:44  root
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Added comments in front and cleaned up a bit.
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This version sent out to people.
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Revision 0.4  1995/12/18  03:46:44  root
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return shortDDP to longDDP fake to 0/0.  Added command structs.
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ***/
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ltpc jumpers are:
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	Interrupts -- set at most one.  If none are set, the driver uses
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	polled mode.  Because the card was developed in the XT era, the
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	original documentation refers to IRQ2.  Since you'll be running
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	this on an AT (or later) class machine, that really means IRQ9.
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	SW1	IRQ 4
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	SW2	IRQ 3
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	SW3	IRQ 9 (2 in original card documentation only applies to XT)
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	DMA -- choose DMA 1 or 3, and set both corresponding switches.
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	SW4	DMA 3
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	SW5	DMA 1
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	SW6	DMA 3
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	SW7	DMA 1
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	I/O address -- choose one.
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	SW8	220 / 240
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*	To have some stuff logged, do
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	insmod ltpc.o debug=1
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	For a whole bunch of stuff, use higher numbers.
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*	The default is 0, i.e. no messages except for the probe results.
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* insmod-tweakable variables */
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int debug;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_VERBOSE 1
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_UPPER 2
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DEBUG_LOWER 4
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int io;
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irq;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dma;
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/fcntl.h>
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h>
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h>
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/in.h>
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h>
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h>
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h>
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h>
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h>
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h>
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_ltalk.h>
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/timer.h>
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/atalk.h>
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h>
2305a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/system.h>
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h>
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h>
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* our stuff */
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "ltpc.h"
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(txqueue_lock);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEFINE_SPINLOCK(mbox_lock);
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* function prototypes */
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_read(struct net_device *dev, void *cbuf, int cbuflen,
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *dbuf, int dbuflen);
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sendup_buffer (struct net_device *dev);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Dma Memory related stuff, cribbed directly from 3c505.c */
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned long dma_mem_alloc(int size)
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        int order = get_order(size);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        return __get_dma_pages(GFP_KERNEL, order);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* DMA data buffer, DMA command buffer */
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char *ltdmabuf;
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char *ltdmacbuf;
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* private struct, holds our appletalk address */
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct ltpc_private
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct atalk_addr my_addr;
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* transmit queue element struct */
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct xmitQel {
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct xmitQel *next;
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* command buffer */
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *cbuf;
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short cbuflen;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* data buffer */
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char *dbuf;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	short dbuflen;
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char QWrite;	/* read or write data */
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned char mailbox;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* the transmit queue itself */
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct xmitQel *xmQhd, *xmQtl;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void enQ(struct xmitQel *qel)
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	qel->next = NULL;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&txqueue_lock, flags);
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (xmQtl) {
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xmQtl->next = qel;
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xmQhd = qel;
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	xmQtl = qel;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&txqueue_lock, flags);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (debug & DEBUG_LOWER)
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("enqueued a 0x%02x command\n",qel->cbuf[0]);
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct xmitQel *deQ(void)
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct xmitQel *qel=NULL;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&txqueue_lock, flags);
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (xmQhd) {
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qel = xmQhd;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xmQhd = qel->next;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(!xmQhd) xmQtl = NULL;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&txqueue_lock, flags);
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((debug & DEBUG_LOWER) && qel) {
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		int n;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_DEBUG "ltpc: dequeued command ");
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		n = qel->cbuflen;
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (n>100) n=100;
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for(i=0;i<n;i++) printk("%02x ",qel->cbuf[i]);
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("\n");
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return qel;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* and... the queue elements we'll be using */
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct xmitQel qels[16];
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* and their corresponding mailboxes */
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char mailbox[16];
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char mboxinuse[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int wait_timeout(struct net_device *dev, int c)
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* returns true if it stayed c */
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* this uses base+6, but it's ok */
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* twenty second or so total */
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i=0;i<200000;i++) {
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ( c != inb_p(dev->base_addr+6) ) return 0;
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		udelay(100);
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1; /* timed out */
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* get the first free mailbox */
3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int getmbox(void)
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&mbox_lock, flags);
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	for(i=1;i<16;i++) if(!mboxinuse[i]) {
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mboxinuse[i]=1;
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&mbox_lock, flags);
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return i;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&mbox_lock, flags);
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* read a command from the card */
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handlefc(struct net_device *dev)
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* called *only* from idle, non-reentrant */
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dma = dev->dma;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int base = dev->base_addr;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags=claim_dma_lock();
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	disable_dma(dma);
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clear_dma_ff(dma);
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_mode(dma,DMA_MODE_READ);
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_addr(dma,virt_to_bus(ltdmacbuf));
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_count(dma,50);
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enable_dma(dma);
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_dma_lock(flags);
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(base+3);
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(base+2);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( wait_timeout(dev,0xfc) ) printk("timed out in handlefc\n");
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* read data from the card */
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handlefd(struct net_device *dev)
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dma = dev->dma;
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int base = dev->base_addr;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags=claim_dma_lock();
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	disable_dma(dma);
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clear_dma_ff(dma);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_mode(dma,DMA_MODE_READ);
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_addr(dma,virt_to_bus(ltdmabuf));
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_count(dma,800);
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enable_dma(dma);
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_dma_lock(flags);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(base+3);
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(base+2);
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( wait_timeout(dev,0xfd) ) printk("timed out in handlefd\n");
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sendup_buffer(dev);
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handlewrite(struct net_device *dev)
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* called *only* from idle, non-reentrant */
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* on entry, 0xfb and ltdmabuf holds data */
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dma = dev->dma;
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int base = dev->base_addr;
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags=claim_dma_lock();
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	disable_dma(dma);
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clear_dma_ff(dma);
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_mode(dma,DMA_MODE_WRITE);
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_addr(dma,virt_to_bus(ltdmabuf));
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_count(dma,800);
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enable_dma(dma);
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_dma_lock(flags);
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(base+3);
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(base+2);
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( wait_timeout(dev,0xfb) ) {
4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flags=claim_dma_lock();
4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("timed out in handlewrite, dma res %d\n",
4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			get_dma_residue(dev->dma) );
4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_dma_lock(flags);
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handleread(struct net_device *dev)
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* on entry, 0xfb */
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* on exit, ltdmabuf holds data */
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dma = dev->dma;
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int base = dev->base_addr;
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags=claim_dma_lock();
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	disable_dma(dma);
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clear_dma_ff(dma);
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_mode(dma,DMA_MODE_READ);
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_addr(dma,virt_to_bus(ltdmabuf));
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_count(dma,800);
4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enable_dma(dma);
4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_dma_lock(flags);
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(base+3);
4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(base+2);
4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( wait_timeout(dev,0xfb) ) printk("timed out in handleread\n");
4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void handlecommand(struct net_device *dev)
4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* on entry, 0xfa and ltdmacbuf holds command */
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dma = dev->dma;
4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int base = dev->base_addr;
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	flags=claim_dma_lock();
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	disable_dma(dma);
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clear_dma_ff(dma);
4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_mode(dma,DMA_MODE_WRITE);
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_addr(dma,virt_to_bus(ltdmacbuf));
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_count(dma,50);
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enable_dma(dma);
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_dma_lock(flags);
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(base+3);
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(base+2);
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( wait_timeout(dev,0xfa) ) printk("timed out in handlecommand\n");
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ready made command for getting the result from the card */
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char rescbuf[2] = {LT_GETRESULT,0};
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char resdbuf[2];
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int QInIdle;
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* idle expects to be called with the IRQ line high -- either because of
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an interrupt, or because the line is tri-stated
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void idle(struct net_device *dev)
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long flags;
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int state;
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME This is initialized to shut the warning up, but I need to
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * think this through again.
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct xmitQel *q = NULL;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int oops;
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int base = dev->base_addr;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock_irqsave(&txqueue_lock, flags);
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(QInIdle) {
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock_irqrestore(&txqueue_lock, flags);
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	QInIdle = 1;
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock_irqrestore(&txqueue_lock, flags);
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* this tri-states the IRQ line */
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) inb_p(base+6);
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	oops = 100;
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsloop:
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (0>oops--) {
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("idle: looped too many times\n");
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto done;
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	state = inb_p(base+6);
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (state != inb_p(base+6)) goto loop;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch(state) {
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xfc:
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* incoming command */
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (debug & DEBUG_LOWER) printk("idle: fc\n");
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			handlefc(dev);
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xfd:
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* incoming data */
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(debug & DEBUG_LOWER) printk("idle: fd\n");
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			handlefd(dev);
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xf9:
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* result ready */
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (debug & DEBUG_LOWER) printk("idle: f9\n");
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(!mboxinuse[0]) {
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				mboxinuse[0] = 1;
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				qels[0].cbuf = rescbuf;
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				qels[0].cbuflen = 2;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				qels[0].dbuf = resdbuf;
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				qels[0].dbuflen = 2;
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				qels[0].QWrite = 0;
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				qels[0].mailbox = 0;
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				enQ(&qels[0]);
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			inb_p(dev->base_addr+1);
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			inb_p(dev->base_addr+0);
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if( wait_timeout(dev,0xf9) )
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("timed out idle f9\n");
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xf8:
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* ?? */
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (xmQhd) {
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				inb_p(dev->base_addr+1);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				inb_p(dev->base_addr+0);
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if(wait_timeout(dev,0xf8) )
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk("timed out idle f8\n");
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto done;
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0xfa:
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* waiting for command */
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(debug & DEBUG_LOWER) printk("idle: fa\n");
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (xmQhd) {
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				q=deQ();
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy(ltdmacbuf,q->cbuf,q->cbuflen);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ltdmacbuf[1] = q->mailbox;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (debug>1) {
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					int n;
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk("ltpc: sent command     ");
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					n = q->cbuflen;
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if (n>100) n=100;
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					for(i=0;i<n;i++)
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						printk("%02x ",ltdmacbuf[i]);
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk("\n");
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				handlecommand(dev);
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					if(0xfa==inb_p(base+6)) {
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						/* we timed out, so return */
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						goto done;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					}
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* we don't seem to have a command */
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!mboxinuse[0]) {
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mboxinuse[0] = 1;
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					qels[0].cbuf = rescbuf;
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					qels[0].cbuflen = 2;
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					qels[0].dbuf = resdbuf;
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					qels[0].dbuflen = 2;
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					qels[0].QWrite = 0;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					qels[0].mailbox = 0;
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					enQ(&qels[0]);
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					printk("trouble: response command already queued\n");
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto done;
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case 0Xfb:
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* data transfer ready */
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(debug & DEBUG_LOWER) printk("idle: fb\n");
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(q->QWrite) {
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				memcpy(ltdmabuf,q->dbuf,q->dbuflen);
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				handlewrite(dev);
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				handleread(dev);
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				/* non-zero mailbox numbers are for
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   commmands, 0 is for GETRESULT
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				   requests */
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if(q->mailbox) {
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					memcpy(q->dbuf,ltdmabuf,q->dbuflen);
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					/* this was a result */
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mailbox[ 0x0f & ltdmabuf[0] ] = ltdmabuf[1];
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					mboxinuse[0]=0;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto loop;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdone:
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	QInIdle=0;
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* now set the interrupts back as appropriate */
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* the first read takes it out of tri-state (but still high) */
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* the second resets it */
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* note that after this point, any read of base+6 will
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   trigger an interrupt */
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->irq) {
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inb_p(base+7);
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inb_p(base+7);
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_write(struct net_device *dev, void *cbuf, int cbuflen,
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *dbuf, int dbuflen)
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = getmbox();
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(i) {
65543d620c82985b19008d87a437b4cf83f356264f7Joe Perches		qels[i].cbuf = cbuf;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qels[i].cbuflen = cbuflen;
65743d620c82985b19008d87a437b4cf83f356264f7Joe Perches		qels[i].dbuf = dbuf;
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qels[i].dbuflen = dbuflen;
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qels[i].QWrite = 1;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qels[i].mailbox = i;  /* this should be initted rather */
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		enQ(&qels[i]);
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		idle(dev);
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = mailbox[i];
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mboxinuse[i]=0;
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("ltpc: could not allocate mbox\n");
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int do_read(struct net_device *dev, void *cbuf, int cbuflen,
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	void *dbuf, int dbuflen)
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i = getmbox();
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(i) {
67943d620c82985b19008d87a437b4cf83f356264f7Joe Perches		qels[i].cbuf = cbuf;
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qels[i].cbuflen = cbuflen;
68143d620c82985b19008d87a437b4cf83f356264f7Joe Perches		qels[i].dbuf = dbuf;
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qels[i].dbuflen = dbuflen;
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qels[i].QWrite = 0;
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		qels[i].mailbox = i;  /* this should be initted rather */
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		enQ(&qels[i]);
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		idle(dev);
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = mailbox[i];
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mboxinuse[i]=0;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return ret;
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk("ltpc: could not allocate mbox\n");
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -1;
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* end of idle handlers -- what should be seen is do_read, do_write */
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct timer_list ltpc_timer;
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6990fc480987e69f22b9212f087545b4d1ca6950807Stephen Hemmingerstatic netdev_tx_t ltpc_xmit(struct sk_buff *skb, struct net_device *dev);
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int read_30 ( struct net_device *dev)
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lt_command c;
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c.getflags.command = LT_GETFLAGS;
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return do_read(dev, &c, sizeof(c.getflags),&c,0);
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int set_30 (struct net_device *dev,int x)
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	lt_command c;
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c.setflags.command = LT_SETFLAGS;
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	c.setflags.flags = x;
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return do_write(dev, &c, sizeof(c.setflags),&c,0);
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* LLAP to DDP translation */
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sendup_buffer (struct net_device *dev)
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* on entry, command is in ltdmacbuf, data in ltdmabuf */
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* called from idle, non-reentrant */
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int dnode, snode, llaptype, len;
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int sklen;
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sk_buff *skb;
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lt_rcvlap *ltc = (struct lt_rcvlap *) ltdmacbuf;
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ltc->command != LT_RCVLAP) {
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("unknown command 0x%02x from ltpc card\n",ltc->command);
730807540baae406c84dcb9c1c8ef07a56d2d2ae84aEric Dumazet		return -1;
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dnode = ltc->dnode;
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	snode = ltc->snode;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	llaptype = ltc->laptype;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	len = ltc->length;
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sklen = len;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (llaptype == 1)
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		sklen += 8;  /* correct for short ddp */
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(sklen > 800) {
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "%s: nonsense length in ltpc command 0x14: 0x%08x\n",
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->name,sklen);
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ( (llaptype==0) || (llaptype>2) ) {
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "%s: unknown LLAP type: %d\n",dev->name,llaptype);
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb = dev_alloc_skb(3+sklen);
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (skb == NULL)
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("%s: dropping packet due to memory squeeze.\n",
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->name);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb->dev = dev;
7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (sklen > len)
7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		skb_reserve(skb,8);
7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_put(skb,len+3);
7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb->protocol = htons(ETH_P_LOCALTALK);
7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* add LLAP header */
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb->data[0] = dnode;
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb->data[1] = snode;
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb->data[2] = llaptype;
769459a98ed881802dee55897441bc7f77af614368eArnaldo Carvalho de Melo	skb_reset_mac_header(skb);	/* save pointer to llap header */
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_pull(skb,3);
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* copy ddp(s,e)hdr + contents */
77327d7ff46a3498d3debc6ba68fb8014c702b81170Arnaldo Carvalho de Melo	skb_copy_to_linear_data(skb, ltdmabuf, len);
7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
775badff6d01a8589a1c828b0bf118903ca38627f4eArnaldo Carvalho de Melo	skb_reset_transport_header(skb);
7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7774fafc12328a4e2d4afbc4541c46be014e22c5b66Stephen Hemminger	dev->stats.rx_packets++;
7784fafc12328a4e2d4afbc4541c46be014e22c5b66Stephen Hemminger	dev->stats.rx_bytes += skb->len;
7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* toss it onwards */
7811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	netif_rx(skb);
7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* the handler for the board interrupt */
7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic irqreturn_t
7887d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsltpc_interrupt(int irq, void *dev_id)
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = dev_id;
7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev==NULL) {
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("ltpc_interrupt: unknown device.\n");
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_NONE;
7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(dev->base_addr+6);  /* disable further interrupts from board */
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	idle(dev); /* handle whatever is coming in */
8001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* idle re-enables interrupts from board */
8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/***
8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    The ioctls that the driver responds to are:
8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    SIOCSIFADDR -- do probe using the passed node hint.
8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    SIOCGIFADDR -- return net, node.
8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    some of this stuff should be done elsewhere.
8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ***/
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ltpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr;
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* we'll keep the localtalk node address in dev->pa_addr */
821454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct ltpc_private *ltpc_priv = netdev_priv(dev);
822454d7c9b14e20fd1949e2686e9de4a2926e01476Wang Chen	struct atalk_addr *aa = &ltpc_priv->my_addr;
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lt_init c;
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ltflags;
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(debug & DEBUG_VERBOSE) printk("ltpc_ioctl called\n");
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch(cmd) {
8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SIOCSIFADDR:
8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			aa->s_net  = sa->sat_addr.s_net;
8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* this does the probe and returns the node addr */
8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			c.command = LT_INIT;
8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			c.hint = sa->sat_addr.s_node;
8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			aa->s_node = do_read(dev,&c,sizeof(c),&c,0);
8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* get all llap frames raw */
8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ltflags = read_30(dev);
8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ltflags |= LT_FLAG_ALLLAP;
8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_30 (dev,ltflags);
8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->broadcast[0] = 0xFF;
8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->dev_addr[0] = aa->s_node;
8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dev->addr_len=1;
8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case SIOCGIFADDR:
8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sa->sat_addr.s_net = aa->s_net;
8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sa->sat_addr.s_node = aa->s_node;
8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		default:
8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -EINVAL;
8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list(struct net_device *dev)
8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* This needs to be present to keep netatalk happy. */
8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Actually netatalk needs fixing! */
8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int ltpc_poll_counter;
8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void ltpc_poll(unsigned long l)
8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev = (struct net_device *) l;
8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer(&ltpc_timer);
8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(debug & DEBUG_VERBOSE) {
8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!ltpc_poll_counter) {
8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			ltpc_poll_counter = 50;
8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("ltpc poll is alive\n");
8811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ltpc_poll_counter--;
8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;  /* we've been downed */
8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* poll 20 times per second */
8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	idle(dev);
8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ltpc_timer.expires = jiffies + HZ/20;
8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	add_timer(&ltpc_timer);
8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* DDP to LLAP translation */
8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8970fc480987e69f22b9212f087545b4d1ca6950807Stephen Hemmingerstatic netdev_tx_t ltpc_xmit(struct sk_buff *skb, struct net_device *dev)
8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* in kernel 1.3.xx, on entry skb->data points to ddp header,
9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * and skb->len is the length of the ddp data + ddp header
9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 */
9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int i;
9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct lt_sendlap cbuf;
9049c70220b73908f64792422a2c39c593c4792f2c5Arnaldo Carvalho de Melo	unsigned char *hdr;
9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cbuf.command = LT_SENDLAP;
9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cbuf.dnode = skb->data[0];
9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cbuf.laptype = skb->data[2];
9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	skb_pull(skb,3);	/* skip past LLAP header */
9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	cbuf.length = skb->len;	/* this is host order */
911badff6d01a8589a1c828b0bf118903ca38627f4eArnaldo Carvalho de Melo	skb_reset_transport_header(skb);
9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(debug & DEBUG_UPPER) {
9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("command ");
9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		for(i=0;i<6;i++)
9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("%02x ",((unsigned char *)&cbuf)[i]);
9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("\n");
9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9209c70220b73908f64792422a2c39c593c4792f2c5Arnaldo Carvalho de Melo	hdr = skb_transport_header(skb);
9219c70220b73908f64792422a2c39c593c4792f2c5Arnaldo Carvalho de Melo	do_write(dev, &cbuf, sizeof(cbuf), hdr, skb->len);
9221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(debug & DEBUG_UPPER) {
9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("sent %d ddp bytes\n",skb->len);
9259c70220b73908f64792422a2c39c593c4792f2c5Arnaldo Carvalho de Melo		for (i = 0; i < skb->len; i++)
9269c70220b73908f64792422a2c39c593c4792f2c5Arnaldo Carvalho de Melo			printk("%02x ", hdr[i]);
9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("\n");
9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9304fafc12328a4e2d4afbc4541c46be014e22c5b66Stephen Hemminger	dev->stats.tx_packets++;
9314fafc12328a4e2d4afbc4541c46be014e22c5b66Stephen Hemminger	dev->stats.tx_bytes += skb->len;
9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_kfree_skb(skb);
9346ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy	return NETDEV_TX_OK;
9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* initialization stuff */
9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ltpc_probe_dma(int base, int dma)
9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int want = (dma == 3) ? 2 : (dma == 1) ? 1 : 3;
9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  	unsigned long timeout;
9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  	unsigned long f;
9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds  	if (want & 1) {
9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (request_dma(1,"ltpc")) {
9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			want &= ~1;
9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			f=claim_dma_lock();
9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			disable_dma(1);
9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			clear_dma_ff(1);
9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_dma_mode(1,DMA_MODE_WRITE);
9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_dma_addr(1,virt_to_bus(ltdmabuf));
9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_dma_count(1,sizeof(struct lt_mem));
9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			enable_dma(1);
9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_dma_lock(f);
9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (want & 2) {
9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (request_dma(3,"ltpc")) {
9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			want &= ~2;
9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			f=claim_dma_lock();
9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			disable_dma(3);
9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			clear_dma_ff(3);
9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_dma_mode(3,DMA_MODE_WRITE);
9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_dma_addr(3,virt_to_bus(ltdmabuf));
9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			set_dma_count(3,sizeof(struct lt_mem));
9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			enable_dma(3);
9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			release_dma_lock(f);
9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* set up request */
9741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* FIXME -- do timings better! */
9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ltdmabuf[0] = LT_READMEM;
9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ltdmabuf[1] = 1;  /* mailbox */
9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ltdmabuf[2] = 0; ltdmabuf[3] = 0;  /* address */
9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ltdmabuf[4] = 0; ltdmabuf[5] = 1;  /* read 0x0100 bytes */
9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ltdmabuf[6] = 0; /* dunno if this is necessary */
9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(io+1);
9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(io+0);
9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies+100*HZ/100;
9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while(time_before(jiffies, timeout)) {
9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ( 0xfa == inb_p(io+6) ) break;
9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(io+3);
9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(io+2);
9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while(time_before(jiffies, timeout)) {
9931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ( 0xfb == inb_p(io+6) ) break;
9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
9951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* release the other dma channel (if we opened both of them) */
9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
9981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((want & 2) && (get_dma_residue(3)==sizeof(struct lt_mem))) {
9991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		want &= ~2;
10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_dma(3);
10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((want & 1) && (get_dma_residue(1)==sizeof(struct lt_mem))) {
10041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		want &= ~1;
10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_dma(1);
10061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!want)
10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return 0;
10101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (want & 2) ? 3 : 1;
10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1014816b26f500e9d78ccd56e1c8ffac85f5d8765c00Stephen Hemmingerstatic const struct net_device_ops ltpc_netdev = {
1015816b26f500e9d78ccd56e1c8ffac85f5d8765c00Stephen Hemminger	.ndo_start_xmit		= ltpc_xmit,
1016816b26f500e9d78ccd56e1c8ffac85f5d8765c00Stephen Hemminger	.ndo_do_ioctl		= ltpc_ioctl,
1017afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= set_multicast_list,
1018816b26f500e9d78ccd56e1c8ffac85f5d8765c00Stephen Hemminger};
1019816b26f500e9d78ccd56e1c8ffac85f5d8765c00Stephen Hemminger
10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct net_device * __init ltpc_probe(void)
10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct net_device *dev;
10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err = -ENOMEM;
10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int x=0,y=0;
10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int autoirq;
10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long f;
10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long timeout;
10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10293ef4e9a8db6c65de7c7f4bc013d62b0d73f50dceChristoph Hellwig	dev = alloc_ltalkdev(sizeof(struct ltpc_private));
10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dev)
10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out;
10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* probe for the I/O port address */
10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (io != 0x240 && request_region(0x220,8,"ltpc")) {
10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		x = inb_p(0x220+6);
10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ( (x!=0xff) && (x>=0xf0) ) {
10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			io = 0x220;
10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto got_port;
10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_region(0x220,8);
10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (io != 0x220 && request_region(0x240,8,"ltpc")) {
10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		y = inb_p(0x240+6);
10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ( (y!=0xff) && (y>=0xf0) ){
10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			io = 0x240;
10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto got_port;
10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_region(0x240,8);
10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* give up in despair */
10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_ERR "LocalTalk card not found; 220 = %02x, 240 = %02x.\n", x,y);
10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = -ENODEV;
10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	goto out1;
10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds got_port:
10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* probe for the IRQ line */
10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (irq < 2) {
10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long irq_mask;
10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		irq_mask = probe_irq_on();
10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* reset the interrupt line */
10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inb_p(io+7);
10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inb_p(io+7);
10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* trigger an interrupt (I hope) */
10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inb_p(io+6);
10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		mdelay(2);
10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		autoirq = probe_irq_off(irq_mask);
10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (autoirq == 0) {
10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR "ltpc: probe at %#x failed to detect IRQ line.\n", io);
10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			irq = autoirq;
10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* allocate a DMA buffer */
10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ltdmabuf = (unsigned char *) dma_mem_alloc(1000);
10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ltdmabuf) {
10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "ltpc: mem alloc failed\n");
10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENOMEM;
10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out2;
10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ltdmacbuf = &ltdmabuf[800];
10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(debug & DEBUG_VERBOSE) {
10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("ltdmabuf pointer %08lx\n",(unsigned long) ltdmabuf);
10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* reset the card */
10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(io+1);
10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(io+3);
10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10972c4ee8f907fc4a3c69273a958f853bf4b358eb49Nishanth Aravamudan	msleep(20);
10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(io+0);
11001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(io+2);
11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(io+7); /* clear reset */
11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(io+4);
11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(io+5);
11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(io+5); /* enable dma */
11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	inb_p(io+6); /* tri-state interrupt line */
11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11072c4ee8f907fc4a3c69273a958f853bf4b358eb49Nishanth Aravamudan	ssleep(1);
11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* now, figure out which dma channel we're using, unless it's
11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   already been specified */
11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* well, 0 is a legal DMA channel, but the LTPC card doesn't
11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	   use it... */
11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dma = ltpc_probe_dma(io, dma);
11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!dma) {  /* no dma channel */
11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_ERR "No DMA channel found on ltpc card.\n");
11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		err = -ENODEV;
11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out3;
11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* print out friendly message */
11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(irq)
11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "Apple/Farallon LocalTalk-PC card at %03x, IR%d, DMA%d.\n",io,irq,dma);
11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_INFO "Apple/Farallon LocalTalk-PC card at %03x, DMA%d.  Using polled mode.\n",io,dma);
11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1126816b26f500e9d78ccd56e1c8ffac85f5d8765c00Stephen Hemminger	dev->netdev_ops = &ltpc_netdev;
11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->base_addr = io;
11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->irq = irq;
11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev->dma = dma;
11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* the card will want to send a result at this point */
11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* (I think... leaving out this part makes the kernel crash,
11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds           so I put it back in...) */
11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	f=claim_dma_lock();
11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	disable_dma(dma);
11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	clear_dma_ff(dma);
11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_mode(dma,DMA_MODE_READ);
11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_addr(dma,virt_to_bus(ltdmabuf));
11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	set_dma_count(dma,0x100);
11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	enable_dma(dma);
11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_dma_lock(f);
11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) inb_p(io+3);
11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	(void) inb_p(io+2);
11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	timeout = jiffies+100*HZ/100;
11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while(time_before(jiffies, timeout)) {
11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if( 0xf9 == inb_p(io+6))
11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		schedule();
11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(debug & DEBUG_VERBOSE) {
11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("setting up timer and irq\n");
11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* grab it and don't let go :-) */
1159a0607fd3a25ba1848a63a0d925e36d914735ab47Joe Perches	if (irq && request_irq( irq, ltpc_interrupt, 0, "ltpc", dev) >= 0)
11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(void) inb_p(io+7);  /* enable interrupts from board */
11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		(void) inb_p(io+7);  /* and reset irq line */
11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if( irq )
11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_ERR "ltpc: IRQ already in use, using polled mode.\n");
11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dev->irq = 0;
11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* polled mode -- 20 times per second */
11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* this is really, really slow... should it poll more often? */
11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		init_timer(&ltpc_timer);
11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ltpc_timer.function=ltpc_poll;
11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ltpc_timer.data = (unsigned long) dev;
11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ltpc_timer.expires = jiffies + HZ/20;
11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		add_timer(&ltpc_timer);
11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
11761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = register_netdev(dev);
11771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out4;
11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout4:
11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer_sync(&ltpc_timer);
11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev->irq)
11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_irq(dev->irq, dev);
11851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout3:
11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_pages((unsigned long)ltdmabuf, get_order(1000));
11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout2:
11881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	release_region(io, 8);
11891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout1:
11901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev);
11911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout:
11921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ERR_PTR(err);
11931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
11941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
11951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef MODULE
11961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* handles "ltpc=io,irq,dma" kernel command lines */
11971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init ltpc_setup(char *str)
11981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ints[5];
12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	str = get_options(str, ARRAY_SIZE(ints), ints);
12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ints[0] == 0) {
12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (str && !strncmp(str, "auto", 4)) {
12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* do nothing :-) */
12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else {
12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* usage message */
12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk (KERN_ERR
12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				"ltpc: usage: ltpc=auto|iobase[,irq[,dma]]\n");
12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		io = ints[1];
12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ints[0] > 1) {
12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			irq = ints[2];
12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ints[0] > 2) {
12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dma = ints[3];
12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
122198a1708de1bfa5fe1c490febba850d6043d3c7faMartin Olsson		/* ignore any other parameters */
12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 1;
12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds__setup("ltpc=", ltpc_setup);
12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* MODULE */
12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct net_device *dev_ltpc;
12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef MODULE
12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, int, 0);
12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(io, int, 0);
12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(irq, int, 0);
12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(dma, int, 0);
12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
124032c9874759651b69e496f89ec9e5e6702f67ffcaJon Schindlerstatic int __init ltpc_module_init(void)
12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds        if(io == 0)
12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_NOTICE
12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "ltpc: Autoprobing is not recommended for modules\n");
12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dev_ltpc = ltpc_probe();
12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (IS_ERR(dev_ltpc))
12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return PTR_ERR(dev_ltpc);
12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
125132c9874759651b69e496f89ec9e5e6702f67ffcaJon Schindlermodule_init(ltpc_module_init);
12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit ltpc_cleanup(void)
12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(debug & DEBUG_VERBOSE) printk("unregister_netdev\n");
12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unregister_netdev(dev_ltpc);
12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ltpc_timer.data = 0;  /* signal the poll routine that we're done */
12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	del_timer_sync(&ltpc_timer);
12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(debug & DEBUG_VERBOSE) printk("freeing irq\n");
12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev_ltpc->irq)
12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_irq(dev_ltpc->irq, dev_ltpc);
12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(debug & DEBUG_VERBOSE) printk("freeing dma\n");
12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev_ltpc->dma)
12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		free_dma(dev_ltpc->dma);
12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(debug & DEBUG_VERBOSE) printk("freeing ioaddr\n");
12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (dev_ltpc->base_addr)
12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		release_region(dev_ltpc->base_addr,8);
12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_netdev(dev_ltpc);
12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(debug & DEBUG_VERBOSE) printk("free_pages\n");
12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_pages( (unsigned long) ltdmabuf, get_order(1000));
12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(debug & DEBUG_VERBOSE) printk("returning from cleanup_module\n");
12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(ltpc_cleanup);
1289