commit e68c1ec8c68f79c49454328a0035fd1c26d65b4d Author: Marcin Bzdulski Date: Mon Nov 2 13:12:04 2026 +0100 fresh commit diff --git a/Devs/networks/3c589.device b/Devs/networks/3c589.device new file mode 100644 index 0000000..091dc4a Binary files /dev/null and b/Devs/networks/3c589.device differ diff --git a/GPL b/GPL new file mode 100644 index 0000000..60549be --- /dev/null +++ b/GPL @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Install b/Install new file mode 100644 index 0000000..ad597c9 --- /dev/null +++ b/Install @@ -0,0 +1,43 @@ +; Installer for 3c589.device. +; Copyright © 2003 Neil Cafferkey. +; $VER: "Install 3c589.device" 1.2 (25.2.2004) + + +; Set constants + +(set #kick-too-low-msg "Kickstart 2.05 or greater is required.") + +(set #dev-name "3c589.device") +(set #devs-source "Devs/networks") +(set @default-dest "DEVS:networks") +(set #pccard-name "pccard.library") +(set #libs-source "Libs") +(set #libs-dest "LIBS:") + + +; Check Kickstart version + +(if (< (/ (getversion) 65536) 37) + (abort #kick-too-low-msg) +) + + +; Install pccard.library + +(copylib + (source (tackon #libs-source #pccard-name)) + (dest #libs-dest) +; (newname #dev-name) + (help @copylib-help) +) + + +; Install device + +(copylib + (source (tackon #devs-source #dev-name)) + (dest @default-dest) + (help @copylib-help) +) + + diff --git a/Install.info b/Install.info new file mode 100644 index 0000000..345717c Binary files /dev/null and b/Install.info differ diff --git a/Libs/pccard.library b/Libs/pccard.library new file mode 100644 index 0000000..b70bf41 Binary files /dev/null and b/Libs/pccard.library differ diff --git a/Manual b/Manual new file mode 100644 index 0000000..ef6fa38 --- /dev/null +++ b/Manual @@ -0,0 +1,234 @@ +@database "3c589.device Manual" +@$VER: "3c589.device Manual" 1.5 (4.2.2010) +@author "Neil Cafferkey" +@(c) "Neil Cafferkey" + +Copyright (C) 2003-2010 Neil Cafferkey + +This manual is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This manual is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this manual; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. + + +@node "main" "3c589.device Manual" + + @{b}@{u}3c589.device 1.5@{uu}@{ub} - A 3Com Etherlink III PC Card driver + + + @{"Introduction" link "intro"} + + @{"Installation and Usage" link "install"} + @{"Performance" link "performance"} + + @{"Author and Legal Information" link "author-legal"} + + @{"History" link "history"} + +@endnode + + +@node "intro" "Introduction" + +@{u}@{b}Introduction@{ub}@{uu} + +3c589.device is a SANA-II network driver for 3Com Etherlink III PC Cards. +These are sold by several companies under a variety of model names; see +below for (probable) compatibility. In short, 10 Mbps cards work; 100 Mbps +cards do not. Also note that the original 3C589 "A" revision (without any +extension letter) does not work. + +The following ethernet and ethernet/modem cards should work: + + @{u}@{b}Company@{uu} @{u}Model@{ub}@{uu} + + @{b}3Com@{ub} 3C562 + 3C562B + 3C562C + 3C562D + 3C563B + 3C563C + 3C563D + 3C589B + 3C589C + 3C589D + 3C589E + + @{b}3Com Megahertz@{ub} 3C3FEM556C + 3CCE589EC + 3CCE589ET + 3CCEM556 + 3CCEM556B + 3CXE589D + 3CXE589EC + 3CXEM556 + + @{b}Farallon/Netopia@{ub} EtherMac/EtherWave PN595-TP + EtherMac/EtherWave PN595-C + + @{b}Hitachi@{ub} HT-4840-13 + + @{b}Motorola@{ub} Marquis + +@endnode + + +@node "install" "Installation and Usage" + +@{u}@{b}Requirements@{ub}@{uu} + +3c589.device needs an A600 or A1200 and OS 2.05 or greater. + +@{u}@{b}Installation@{ub}@{uu} + +To install 3c589.device, run the 'Install' script. In your networking +software, set the SANA-II device name to @{b}networks/3c589.device@{ub} and the +unit number to @{b}0@{ub}. + +@{u}@{b}Cable types@{ub}@{uu} + +Your Etherlink III card will have been programmed to use a certain cable +type. If you need to change this setting, I believe there is 3Com software +available for Windows to change this and other settings. Check their web +site. + +In the future there may be a utility provided to change this setting on an +Amiga. + +3c589.device has so far only been tested with @{"10baseT" link "cable"} cabling. @{"10base2" link "cable"} +cabling should also work. I'm not sure if there was ever an Etherlink III +PC Card with an AUI connection, but if there was, it should work. + +@{u}@{b}Multifunction cards@{ub}@{uu} + +Although 3c589.device works with some multifunction ethernet/modem cards, +only one of these functions can be used at a time. This is due to +limitations in AmigaOS's card.resource. + +@{u}@{b}A1200 hardware bug@{ub}@{uu} + +The A1200 (but not the A600) has a hardware bug which prevents a card being +reset except on insertion or removal. There are both hardware and software +remedies for this problem. The software solution is CardReset +(util/boot/CardReset.lha on Aminet). There are several different types of +hardware fixes, some of which are available commercially. + +@{u}@{b}Problems@{ub}@{uu} + +With some A1200 motherboards, hot insertion or removal of a 3c589-compatible +card may cause the system to reset. + +Miami will cause the system to hang if the card is removed while online. +Re-insertion won't help. + +@endnode + + +@node "performance" "Performance" + +@{u}@{b}Performance@{ub}@{uu} + +On a 40MHz 68030 system, the following FTP speeds have been achieved: + + @{b}@{u}Upload@{uu} @{u}Download@{ub}@{uu} + @{i}kbytes/s kbytes/s@{ui} + + @{b}AmiTCP 3.0b:@{ub} 407 497 + @{b}Genesis:@{ub} 373 551 + @{b}Miami 3.2b:@{ub} 191 279 + +There is no version of the device specially compiled for CPUs above the +68000, since there was no performance benefit. + +@endnode + + +@node "author-legal" "Author and Legal Information" + +@{u}@{b}Author and Legal Information@{ub}@{uu} + +3c589.device was written by Neil Cafferkey. + +Please send bug reports, suggestions, and any other correspondence to one of +the following addresses. + +E-mail: caffer@cs.ucc.ie + +Post: Neil Cafferkey, + 30, Upper Kensington, + Rochestown, + Cork, + Ireland. + +3c589.device and pccard.library are released under the terms of the +@{"GNU General Public Licence" link "GPL/MAIN"}. See the individual source files for copyright +information. + +The full pccard.library archive, which includes the source code and +developer files, is available on Aminet as "util/libs/pccard.lha". + +All trademarks are owned by their owners. + +@endnode + + +@node "history" "History" + +@{u}@{b}History@{ub}@{uu} + +@{b}V1.5 (February 2010)@{ub} + + - Fixed lock-up when closing device under AmigaOS 4.0. + +@{b}V1.4 (March 2004)@{ub} + + - Now works with 3C562D/3C563D (thanks to Francisco Miguel Guerrero García + for lending me one of these cards). + - Multicast and broadcast flags weren't set properly. Fixed. + - Fixed memory leak in initialisation code (thanks to Adam Markiewicz). + - Only the first packet read in any interrupt could be recognised as + an orphan. Fixed. + - Support for IEEE 802.3 frames. + - Fixed bug in media selection code. + - Removed request for information about Farallon and Motorola cards, since + it appears that they use the same manufacturer and product codes as the + official 3Com cards, and hence already work (thanks to Kjell Linden). + - Fixed a bug in handling transmission errors. + +@{b}V1.3 (February 2003)@{ub} + + - Added 4 to reported length of incoming raw packets to make ShapeShifter + and Fusion work (thanks to Marcin Ozdzinski). + - Fixed a buffer overrun. + +@{b}V1.2 (January 2003)@{ub} + + - Bug fix: couldn't handle more than 64kb of attribute address space, + causing some cards not to work (thanks to Tom Parker). + +@{b}V1.1 (January 2003)@{ub} + + - First release. + +@endnode + + +@node "cable" "Cable Types" + +10baseT: Twisted Pair (TP) cabling with RJ45 connectors. + +10base2: Thin coaxial cable with BNC connectors. + +@endnode + + diff --git a/Manual.info b/Manual.info new file mode 100644 index 0000000..b131516 Binary files /dev/null and b/Manual.info differ diff --git a/Read Me b/Read Me new file mode 100644 index 0000000..5e02214 --- /dev/null +++ b/Read Me @@ -0,0 +1,20 @@ +Short: Driver for 3Com PCMCIA network cards +Author: caffer@cs.ucc.ie (Neil Cafferkey) +Uploader: caffer@cs.ucc.ie (Neil Cafferkey) +Version: 1.5 +Type: driver/net +Requires: A1200 or A600, compatible card +Architecture: m68k-amigaos >= 2.0.0 + +3c589.device is a SANA-II network driver for 3Com Etherlink III PC Cards +(PCMCIA cards). Note that not all 3Com cards work with this driver, and that +some compatible cards are rebranded by other manufacturers. See the +documentation in the archive for a list of compatible cards. In short, +10 Mbps cards work; 100 Mbps cards do not. + +This package is released under the GNU General Public Licence. + +Changes in this version: + + - Fixed lock-up when closing device under AmigaOS 4.0. + diff --git a/Read Me.info b/Read Me.info new file mode 100644 index 0000000..8c668c8 Binary files /dev/null and b/Read Me.info differ diff --git a/Source.info b/Source.info new file mode 100644 index 0000000..715cbcb Binary files /dev/null and b/Source.info differ diff --git a/Source/Makefile b/Source/Makefile new file mode 100644 index 0000000..aec3019 --- /dev/null +++ b/Source/Makefile @@ -0,0 +1,31 @@ +# File: Makefile + +CFLAGS = -msmall-code -O3 -ansi -Wall -Wno-uninitialized -Wno-parentheses +CC = gcc $(CFLAGS) +MAKEFILE = Makefile +LINKER = ld -e _Main -s +AMIGA_LIB = GG:lib/libamiga.a +C_LIB = GG:lib/libnix/libnix13.a + +DEV_NAME = 3c589.device +OBJS = device.o unit.o request.o +HDRS = device.h + +.c.o : + $(CC) -c $< + +$(DEV_NAME): $(MAKEFILE) $(OBJS) + $(LINKER) $(OBJS) $(AMIGA_LIB) $(C_LIB) -o $(DEV_NAME) + Protect "$(DEV_NAME)" "-e" + +$(OBJS): $(MAKEFILE) $(HDRS) + +unit.o: etherlink3.h + +install: $(DEV_NAME) + Copy CLONE "$(DEV_NAME)" "DEVS:networks/" + Flush "$(DEV_NAME)" + +clean: + Delete "$(DEV_NAME)" "#?.o" + diff --git a/Source/Notes b/Source/Notes new file mode 100644 index 0000000..2a59821 --- /dev/null +++ b/Source/Notes @@ -0,0 +1,27 @@ + +DESIGN NOTES: + + - Type tracking has been implemented in an unusual way in order to make it + more suitable for multiple users. Each client that tracks a particular + packet type is given the impression that it is the only one doing so. + When a client begins tracking a packet type that is already being + tracked, the current packet statistics are recorded internally. These + initial statistics are then subtracted from the figures returned from + every S2_GETTYPESTATS call the client makes. + - The cards' 8-bit statistics registers appear to be unreadable using the + A1200's PCMCIA slot. + - S2_CopyToBuff32 functions are not used because the non-raw portion of + received packets is not 32-bit aligned. + + +TCP/IP STACK BUGS TO CONSIDER: + + - Miami(DX) doesn't like requests being aborted upon S2_OFFLINE. + - MiamiDX's CopyFromBuff16/32 functions appear to be broken. + - Genesis calls S2_ONLINE before S2_CONFIGINTERFACE? + - When a device goes back online without Genesis's intervention, Genesis + displays the message "eth0 is online again" or similar, but keeps the + interface's indicator red and doesn't disable the "Online" button or + enable the "Offline" button. + + diff --git a/Source/device.c b/Source/device.c new file mode 100644 index 0000000..9903b31 --- /dev/null +++ b/Source/device.c @@ -0,0 +1,651 @@ +/* + +File: device.c +Author: Neil Cafferkey +Copyright (C) 2000-2010 Neil Cafferkey + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. + +*/ + + +#include +#include +#include +#include +#include "initializers.h" + +#include +#include +#include + +#include "device.h" + +#include "unit_protos.h" +#include "request_protos.h" + +#define VERSION 1 +#define REVISION 5 +#define UNIT_COUNT 1 +#define UTILITY_VERSION 36 +#define PCCARD_VERSION 1 + + +/* Private prototypes */ + +static struct DevBase *DevInit(struct DevBase *dev_base REG("d0"), + APTR seg_list REG("a0"),struct DevBase *base REG(BASE_REG)); +static BYTE DevOpen(ULONG unit_no REG("d0"), + struct IOSana2Req *request REG("a1"),ULONG flags REG("d1"), + struct DevBase *base REG(BASE_REG)); +static APTR DevClose(struct IOSana2Req *request REG("a1"), + struct DevBase *base REG(BASE_REG)); +static APTR DevExpunge(struct DevBase *base REG(BASE_REG)); +static APTR DevReserved(); +static VOID DevBeginIO(struct IOSana2Req *request REG("a1"), + struct DevBase *base REG(BASE_REG)); +static VOID DevAbortIO(struct IOSana2Req *request REG("a1"), + struct DevBase *base REG(BASE_REG)); +VOID DeleteDevice(struct DevBase *base); + +extern const APTR vectors[]; +extern const APTR init_table[]; + + +/* Return an error immediately if someone tries to run the device */ + +LONG Main() +{ + return -1; +} + +#define DEVICE_NAME "3c589.device" + +const TEXT device_name[]=DEVICE_NAME; +static const TEXT version_string[]=DEVICE_NAME " 1.5 (3.2.2010)\n"; +static const TEXT card_name[]=CARDRESNAME; +static const TEXT utility_name[]=UTILITYNAME; +static const TEXT pccard_name[]=PCCARDNAME; +static const TEXT timer_name[]=TIMERNAME; + + +const struct Resident device_rom_tag= +{ + RTC_MATCHWORD, + (struct Resident *)&device_rom_tag, + (APTR)init_table, + RTF_AUTOINIT, + VERSION, + NT_DEVICE, + 0, + (STRPTR)device_name, + (STRPTR)version_string, + (APTR)init_table +}; + + +static const APTR vectors[]= +{ + (APTR)DevOpen, + (APTR)DevClose, + (APTR)DevExpunge, + (APTR)DevReserved, + (APTR)DevBeginIO, + (APTR)DevAbortIO, + (APTR)-1 +}; + + +static const struct +{ + SMALLINITBYTEDEF(type); + SMALLINITPINTDEF(name); + SMALLINITBYTEDEF(flags); + SMALLINITWORDDEF(version); + SMALLINITWORDDEF(revision); + SMALLINITPINTDEF(id_string); + INITENDDEF; +} +init_data= +{ + SMALLINITBYTE(OFFSET(Node,ln_Type),NT_DEVICE), + SMALLINITPINT(OFFSET(Node,ln_Name),device_name), + SMALLINITBYTE(OFFSET(Library,lib_Flags),LIBF_SUMUSED|LIBF_CHANGED), + SMALLINITWORD(OFFSET(Library,lib_Version),VERSION), + SMALLINITWORD(OFFSET(Library,lib_Revision),REVISION), + SMALLINITPINT(OFFSET(Library,lib_IdString),version_string), + INITEND +}; + + +static const APTR init_table[]= +{ + (APTR)sizeof(struct DevBase), + (APTR)vectors, + (APTR)&init_data, + (APTR)DevInit +}; + + +static const ULONG rx_tags[]= +{ + S2_CopyToBuff, + S2_CopyToBuff16 +}; + + +static const ULONG tx_tags[]= +{ + S2_CopyFromBuff, + S2_CopyFromBuff16, + S2_CopyFromBuff32 +}; + + + +/****i* 3c589.device/DevInit *********************************************** +* +* NAME +* DevInit -- . +* +* SYNOPSIS +* dev_base = DevInit(dev_base,seg_list) +* +* struct DevBase *DevInit(struct DevBase *,APTR); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static struct DevBase *DevInit(struct DevBase *dev_base REG("d0"), + APTR seg_list REG("a0"),struct DevBase *base REG(BASE_REG)) +{ + BOOL success=TRUE; + + dev_base->sys_base=(APTR)base; + base=dev_base; + base->seg_list=seg_list; + + base->card_base=OpenResource(card_name); + base->utility_base=(APTR)OpenLibrary(utility_name,UTILITY_VERSION); + base->pccard_base=OpenLibrary(pccard_name,PCCARD_VERSION); + if((base->card_base==NULL)||(base->utility_base==NULL)|| + (base->pccard_base==NULL)) + success=FALSE; + + if(OpenDevice(timer_name,UNIT_VBLANK,(APTR)&base->timer_request,0)!=0) + success=FALSE; + + NewList((APTR)(&dev_base->units)); + + if(!success) + { + DeleteDevice(base); + base=NULL; + } + + return base; +} + + + +/****i* 3c589.device/DevOpen *********************************************** +* +* NAME +* DevOpen -- . +* +* SYNOPSIS +* error = DevOpen(unit_num,request,flags) +* +* BYTE DevOpen(ULONG,struct IOSana2Req *,ULONG); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BYTE DevOpen(ULONG unit_num REG("d0"), + struct IOSana2Req *request REG("a1"),ULONG flags REG("d1"), + struct DevBase *base REG(BASE_REG)) +{ + struct DevUnit *unit; + BYTE error=0; + struct Opener *opener; + struct TagItem *tag_list; + UWORD i; + + base->device.dd_Library.lib_OpenCnt++; + base->device.dd_Library.lib_Flags&=~LIBF_DELEXP; + + request->ios2_Req.io_Unit=NULL; + tag_list=request->ios2_BufferManagement; + request->ios2_BufferManagement=NULL; + + /* Check request size and unit number */ + + if((request->ios2_Req.io_Message.mn_Length=UNIT_COUNT)) + error=IOERR_OPENFAIL; + + /* Get the requested unit */ + + if(error==0) + { + request->ios2_Req.io_Unit=(APTR)unit=GetUnit(unit_num,base); + if(unit==NULL) + error=IOERR_OPENFAIL; + } + + /* Handle device sharing */ + + if(error==0) + { + if((unit->open_count!=0)&&(((unit->flags&UNITF_SHARED)==0)|| + ((flags&SANA2OPF_MINE)!=0))) + error=IOERR_UNITBUSY; + unit->open_count++; + } + + if(error==0) + { + if((flags&SANA2OPF_MINE)==0) + unit->flags|=UNITF_SHARED; + else if((flags&SANA2OPF_PROM)!=0) + unit->flags|=UNITF_PROM; + + /* Set up buffer-management structure and get hooks */ + + request->ios2_BufferManagement=opener= + AllocVec(sizeof(struct Opener),MEMF_PUBLIC); + if(opener==NULL) + error=IOERR_OPENFAIL; + } + + if(error==0) + { + NewList(&opener->read_port.mp_MsgList); + opener->read_port.mp_Flags=PA_IGNORE; + NewList((APTR)&opener->initial_stats); + + for(i=0;i<2;i++) + opener->rx_function=(APTR)GetTagData(rx_tags[i], + (UPINT)opener->rx_function,tag_list); + for(i=0;i<3;i++) + opener->tx_function=(APTR)GetTagData(tx_tags[i], + (UPINT)opener->tx_function,tag_list); + + opener->filter_hook=(APTR)GetTagData(S2_PacketFilter,NULL,tag_list); + opener->dma_tx_function= + (APTR)GetTagData(S2_DMACopyFromBuff32,NULL,tag_list); + + Disable(); + AddTail((APTR)&unit->openers,(APTR)opener); + Enable(); + } + + /* Back out if anything went wrong */ + + if(error!=0) + DevClose(request,base); + + /* Return */ + + request->ios2_Req.io_Error=error; + return error; +} + + + +/****i* 3c589.device/DevClose ********************************************** +* +* NAME +* DevClose -- . +* +* SYNOPSIS +* seg_list = DevClose(request) +* +* APTR DevClose(struct IOSana2Req *); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static APTR DevClose(struct IOSana2Req *request REG("a1"), + struct DevBase *base REG(BASE_REG)) +{ + struct DevUnit *unit; + APTR seg_list; + struct Opener *opener; + + /* Free buffer-management resources */ + + opener=(APTR)request->ios2_BufferManagement; + if(opener!=NULL) + { + Disable(); + Remove((APTR)opener); + Enable(); + FreeVec(opener); + } + + /* Delete the unit if it's no longer in use */ + + unit=(APTR)request->ios2_Req.io_Unit; + if(unit!=NULL) + { + if((--unit->open_count)==0) + { + Remove((APTR)unit); + DeleteUnit(unit,base); + } + } + + /* Expunge the device if a delayed expunge is pending */ + + seg_list=NULL; + + if((--base->device.dd_Library.lib_OpenCnt)==0) + { + if((base->device.dd_Library.lib_Flags&LIBF_DELEXP)!=0) + seg_list=DevExpunge(base); + } + + return seg_list; +} + + + +/****i* 3c589.device/DevExpunge ******************************************** +* +* NAME +* DevExpunge -- . +* +* SYNOPSIS +* seg_list = DevExpunge() +* +* APTR DevExpunge(VOID); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static APTR DevExpunge(struct DevBase *base REG(BASE_REG)) +{ + APTR seg_list; + + if(base->device.dd_Library.lib_OpenCnt==0) + { + seg_list=base->seg_list; + Remove((APTR)base); + DeleteDevice(base); + } + else + { + base->device.dd_Library.lib_Flags|=LIBF_DELEXP; + seg_list=NULL; + } + + return seg_list; +} + + + +/****i* 3c589.device/DevReserved ******************************************* +* +* NAME +* DevReserved -- . +* +* SYNOPSIS +* result = DevReserved() +* +* APTR DevReserved(VOID); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static APTR DevReserved() +{ + return NULL; +} + + + +/****i* 3c589.device/DevBeginIO ******************************************** +* +* NAME +* DevBeginIO -- . +* +* SYNOPSIS +* DevBeginIO(request) +* +* VOID DevBeginIO(struct IORequest *); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static VOID DevBeginIO(struct IOSana2Req *request REG("a1"), + struct DevBase *base REG(BASE_REG)) +{ + struct DevUnit *unit; + + request->ios2_Req.io_Error=0; + unit=(APTR)request->ios2_Req.io_Unit; + + if(AttemptSemaphore(&unit->access_lock)) + ServiceRequest(request,base); + else + { + PutRequest(unit->request_ports[GENERAL_QUEUE],(APTR)request,base); + } + + return; +} + + + +/****i* 3c589.device/DevAbortIO ******************************************** +* +* NAME +* DevAbortIO -- Try to stop a request. +* +* SYNOPSIS +* DevAbortIO(request) +* +* VOID DevAbortIO(struct IOSana2Req *); +* +* FUNCTION +* Do our best to halt the progress of a request. +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +* Disable() used instead of a semaphore because device uses interrupts. +* +*/ + +static VOID DevAbortIO(struct IOSana2Req *request REG("a1"), + struct DevBase *base REG(BASE_REG)) +{ + struct DevUnit *unit; + + unit=(APTR)request->ios2_Req.io_Unit; + + Disable(); + if((request->ios2_Req.io_Message.mn_Node.ln_Type==NT_MESSAGE) + &&((request->ios2_Req.io_Flags&IOF_QUICK)==0)) + { + Remove((APTR)request); + request->ios2_Req.io_Error=IOERR_ABORTED; + request->ios2_WireError=S2WERR_GENERIC_ERROR; + ReplyMsg((APTR)request); + } + Enable(); + + return; +} + + + +/****i* 3c589.device/DeleteDevice ****************************************** +* +* NAME +* DeleteDevice -- . +* +* SYNOPSIS +* DeleteDevice() +* +* VOID DeleteDevice(VOID); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +VOID DeleteDevice(struct DevBase *base) +{ + UWORD neg_size,pos_size; + + /* Close devices */ + + CloseDevice((APTR)&base->timer_request); + + /* Close libraries */ + + if(base->pccard_base!=NULL) + CloseLibrary(base->pccard_base); + if(base->utility_base!=NULL) + CloseLibrary((APTR)base->utility_base); + + /* Free device's memory */ + + neg_size=base->device.dd_Library.lib_NegSize; + pos_size=base->device.dd_Library.lib_PosSize; + FreeMem((UBYTE *)base-neg_size,pos_size+neg_size); + + return; +} + + + diff --git a/Source/device.h b/Source/device.h new file mode 100644 index 0000000..6184048 --- /dev/null +++ b/Source/device.h @@ -0,0 +1,257 @@ +/* + +Copyright (C) 2001-2004 Neil Cafferkey + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. + +*/ + +#ifndef DEVICE_H +#define DEVICE_H + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef UPINT +typedef ULONG UPINT; +typedef LONG PINT; +#endif + +#ifdef __mc68000 +#define REG(A) __asm(A) +#else +#define REG(A) +#endif + +#define USE_HACKS + + +struct DevBase +{ + struct Device device; + APTR seg_list; + struct ExecBase *sys_base; + APTR card_base; + struct UtilityBase *utility_base; + struct Library *pccard_base; + struct MinList units; + struct timerequest timer_request; +}; + + +enum +{ + WRITE_QUEUE, + ADOPT_QUEUE, + EVENT_QUEUE, + GENERAL_QUEUE, + REQUEST_QUEUE_COUNT +}; + +#define ADDRESS_SIZE 6 +#define HEADER_SIZE 14 +#define PREAMBLE_SIZE 4 +#define PACKET_DEST 0 +#define PACKET_SOURCE 6 +#define PACKET_TYPE 12 +#define PACKET_DATA 14 +#define MTU 1500 +#define MAX_PACKET_SIZE ((HEADER_SIZE)+(MTU)) + +#define STAT_COUNT 3 + + +struct DevUnit +{ + struct MinNode node; + ULONG unit_num; + ULONG open_count; + UWORD flags; + UWORD transceiver; + struct Task *task; + struct MsgPort *request_ports[REQUEST_QUEUE_COUNT]; + struct DevBase *device; + struct CardHandle *card_handle; + UBYTE *tuple_buffer; + UBYTE *rx_buffer; + UBYTE *tx_buffer; + volatile UBYTE *config_base; + volatile UBYTE *io_base; + ULONG card_removed_signal; + ULONG card_inserted_signal; + ULONG range_count; + UBYTE address[ADDRESS_SIZE]; + UBYTE default_address[ADDRESS_SIZE]; + struct MinList openers; + struct MinList type_trackers; + struct MinList multicast_ranges; + struct Interrupt rx_int; + struct Interrupt tx_int; + struct Sana2DeviceStats stats; + ULONG special_stats[STAT_COUNT]; + struct SignalSemaphore access_lock; + UWORD rx_filter_cmd; +}; + + +struct Opener +{ + struct MinNode node; + struct MsgPort read_port; + BOOL (*rx_function)(APTR REG("a0"),APTR REG("a1"),ULONG REG("d0")); + BOOL (*tx_function)(APTR REG("a0"),APTR REG("a1"),ULONG REG("d0")); + ULONG *(*dma_tx_function)(APTR REG("a0")); + struct Hook *filter_hook; + struct MinList initial_stats; +}; + + +struct TypeStats +{ + struct MinNode node; + ULONG packet_type; + struct Sana2PacketTypeStats stats; +}; + + +struct TypeTracker +{ + struct MinNode node; + ULONG packet_type; + struct Sana2PacketTypeStats stats; + ULONG user_count; +}; + + +struct AddressRange +{ + struct MinNode node; + ULONG add_count; + ULONG lower_bound_left; + ULONG upper_bound_left; + UWORD lower_bound_right; + UWORD upper_bound_right; +}; + + +/* Unit flags */ + +#define UNITF_SHARED (1<<0) +#define UNITF_ONLINE (1<<1) +#define UNITF_HAVECARD (1<<2) +#define UNITF_HAVEADAPTER (1<<3) +#define UNITF_CONFIGURED (1<<4) +#define UNITF_PROM (1<<5) +#define UNITF_ROADRUNNER (1<<6) + + +IMPORT const TEXT device_name[]; + +#define HANDLE_PRIORITY 10 + +#define S2_3C589_WRITEEEPROM 0x998f + + +/* Endianness macros */ + +#define BEWord(A)\ + (A) + +#define MakeBEWord(A)\ + BEWord(A) + +#define LEWord(A)\ + ({\ + UWORD _LEWord_A=(A);\ + _LEWord_A=((_LEWord_A)<<8)|((_LEWord_A)>>8);\ + }) + +#define MakeLEWord(A)\ + LEWord(A) + +#define BELong(A)\ + (A) + +#define LELong(A)\ + ({\ + ULONG _LELong_A=(A);\ + _LELong_A=(LEWord(_LELong_A)<<16)|LEWord((_LELong_A)>>16);\ + }) + +#define MakeLELong(A)\ + LELong(A) + + +/* I/O macros */ + +#define ByteIn(address)\ + (*((volatile UBYTE *)(address))) + +#define ByteOut(address,value)\ + *((volatile UBYTE *)(address))=(value) + +#define WordIn(address)\ + (*((volatile UWORD *)(address))) + +#define WordOut(address,value)\ + *((volatile UWORD *)(address))=(value) + +#define LongIn(address)\ + (*((volatile ULONG *)(address))) + +#define LongOut(address,value)\ + *((volatile ULONG *)(address))=(value) + +#define LEWordIn(address)\ + LEWord(WordIn(address)) + +#define LEWordOut(address,value)\ + WordOut(address,MakeLEWord(value)) + +#define LELongIn(address)\ + LELong(LongIn(address)) + +#define LELongOut(address,value)\ + LongOut(address,MakeLELong(value)) + +#define BEWordOut(address,value)\ + WordOut(address,MakeBEWord(value)) + + +/* Library and device bases */ + +#define SysBase (base->sys_base) +#define CardResource (base->card_base) +#define UtilityBase (base->utility_base) +#define PCCardBase (base->pccard_base) +#define TimerBase (base->timer_request.tr_node.io_Device) + +#ifndef BASE_REG +#define BASE_REG "a6" +#endif + +/*register APTR base asm(BASE_REG);*/ + + +#endif diff --git a/Source/etherlink3.h b/Source/etherlink3.h new file mode 100644 index 0000000..164700d --- /dev/null +++ b/Source/etherlink3.h @@ -0,0 +1,320 @@ +/* + +Copyright (C) 2002 Neil Cafferkey + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. + +*/ + +#ifndef ETHERLINK3_H +#define ETHERLINK3_H + + +/* Registers */ +/* ========= */ + +/* All Windows */ + +#define EL3REG_COMMAND 14 +#define EL3REG_STATUS 14 + +/* Window 0 */ + +#define EL3REG_MAKERID 0 +#define EL3REG_PRODUCTID 2 +#define EL3REG_ADAPTERID 2 +#define EL3REG_CONFIG 4 +#define EL3REG_ADDRCONFIG 6 +#define EL3REG_RESCONFIG 8 /* also in window 3 */ +#define EL3REG_EEPROMCMD 10 /* window 2 has alternative version */ +#define EL3REG_EEPROMDATA 12 + +/* Window 1 */ + +#define EL3REG_DATA0 0 +#define EL3REG_DATA1 2 +#define EL3REG_RXSTATUS 8 +#define EL3REG_TIMER 10 +#define EL3REG_TXSTATUS 11 +#define EL3REG_TXSPACE 12 /* also in window 3 */ + +/* Window 2 */ + +#define EL3REG_ADDRESS0 0 +#define EL3REG_ADDRESS1 1 +#define EL3REG_ADDRESS2 2 +#define EL3REG_ADDRESS3 3 +#define EL3REG_ADDRESS4 4 +#define EL3REG_ADDRESS5 5 +#define EL3REG_SRAMDIAG 6 +#define EL3REG_MULTIFUNCCONFIG 8 +#define EL3REG_ALTEEPROMCMD 10 + +/* Window 3 */ + +#define EL3REG_ROMCONTROL 4 +#define EL3REG_TXRECLAIM 6 +#define EL3REG_RXSPACE 10 + +/* Window 4 */ + +#define EL3REG_FIFODIAG 4 +#define EL3REG_NETDIAG 6 +#define EL3REG_CONTROLLERSTATUS 8 +#define EL3REG_MEDIA 10 + +/* Window 5 */ + +#define EL3REG_TXSTARTTHRESH 0 +#define EL3REG_TXAVAILTHRESH 2 +#define EL3REG_RXEARLYTHRESH 6 +#define EL3REG_RXFILTER 8 +#define EL3REG_INTMASK 10 +#define EL3REG_READZEROMASK 12 + + +/* (Some) EEPROM data offsets */ +/* ========================== */ + +#define EL3EEPROM_ADDRESS0 0 +#define EL3EEPROM_ADDRESS1 1 +#define EL3EEPROM_ADDRESS2 2 +#define EL3EEPROM_PRODUCTID 3 +#define EL3EEPROM_MANFDATA0 4 +#define EL3EEPROM_MANFDATA1 5 +#define EL3EEPROM_MANFDATA2 6 +#define EL3EEPROM_MAKERID 7 +#define EL3EEPROM_ADDRCONFIG 8 +#define EL3EEPROM_RESCONFIG 9 +#define EL3EEPROM_ALTADDRESS0 10 +#define EL3EEPROM_ALTADDRESS1 11 +#define EL3EEPROM_ALTADDRESS2 12 +#define EL3EEPROM_SOFTWAREINFO 13 +#define EL3EEPROM_COMPATIBILITY 14 +#define EL3EEPROM_CHECKSUM 15 + + +/* EEPROM commands */ +/* =============== */ + +#define EL3ECMD_WRITEDISABLE (0x0<<4) +#define EL3ECMD_WRITEALL (0x1<<4) +#define EL3ECMD_ERASEALL (0x2<<4) +#define EL3ECMD_WRITEENABLE (0x3<<4) +#define EL3ECMD_WRITE (0x4<<4) +#define EL3ECMD_READ (0x8<<4) +#define EL3ECMD_ERASE (0xc<<4) + + +/* Commands */ +/* ======== */ + +#define EL3CMD_GLOBALRESET (0<<11) +#define EL3CMD_SELECTWINDOW (1<<11) +#define EL3CMD_STARTCOAX (2<<11) +#define EL3CMD_RXDISABLE (3<<11) +#define EL3CMD_RXENABLE (4<<11) +#define EL3CMD_RXRESET (5<<11) +#define EL3CMD_RXDISCARD (8<<11) +#define EL3CMD_TXENABLE (9<<11) +#define EL3CMD_TXDISABLE (10<<11) +#define EL3CMD_TXRESET (11<<11) +#define EL3CMD_REQINT (12<<11) +#define EL3CMD_ACKINT (13<<11) +#define EL3CMD_SETINTMASK (14<<11) +#define EL3CMD_SETZEROMASK (15<<11) +#define EL3CMD_SETRXFILTER (16<<11) +#define EL3CMD_SETRXTHRESH (17<<11) +#define EL3CMD_SETTXTHRESH (18<<11) +#define EL3CMD_SETTXSTART (19<<11) +#define EL3CMD_STATSENABLE (21<<11) +#define EL3CMD_STATSDISABLE (22<<11) +#define EL3CMD_STOPCOAX (23<<11) +#define EL3CMD_POWERUP (27<<11) +#define EL3CMD_POWERDOWN (28<<11) +#define EL3CMD_POWERAUTO (29<<11) + + +/* Interrupt types */ +/* =============== */ + +#define EL3INTB_UPDATESTATS 7 +#define EL3INTB_REQINT 6 +#define EL3INTB_RXEARLY 5 +#define EL3INTB_RXCOMPLETE 4 +#define EL3INTB_TXAVAIL 3 +#define EL3INTB_TXCOMPLETE 2 +#define EL3INTB_FAILURE 1 +#define EL3INTB_ANY 0 + +#define EL3INTF_UPDATESTATS (1< + + +/* Use the OFFSET macro as the offset parameter of one of the other + macros */ +/* +#ifdef OFFSET +#undef OFFSET +#endif +*/ +#define OFFSET(struct_name, struct_field) \ + ((ULONG)(&(((struct struct_name *)0)->struct_field))) + +/* Use the following macros in the structure definition */ + +#define INITBYTEDEF(name) \ + UBYTE name ## _c; UBYTE name ## _o1; UBYTE name ## _o2; \ + UBYTE name ## _o3; UBYTE name ## _v; UBYTE name ## _p +#define INITWORDDEF(name) \ + UBYTE name ## _c; UBYTE name ## _o1; UBYTE name ## _o2; \ + UWORD name ## _v +#define INITLONGDEF(name) \ + UBYTE name ## _c; UBYTE name ## _o1; UBYTE name ## _o2; \ + ULONG name ## _v +#define INITPINTDEF(name) \ + UBYTE name ## _c; UBYTE name ## _o1; UBYTE name ## _o2; \ + UPINT name ## _v + +#define SMALLINITBYTEDEF(name) \ + UBYTE name ## _c; UBYTE name ## _o; UBYTE name ## _v; UBYTE name ## _p +#define SMALLINITWORDDEF(name) \ + UBYTE name ## _c; UBYTE name ## _o; UWORD name ## _v +#define SMALLINITLONGDEF(name) \ + UBYTE name ## _c; UBYTE name ## _o; ULONG name ## _v +#define SMALLINITPINTDEF(name) \ + UBYTE name ## _c; UBYTE name ## _o; UPINT name ## _v + +#define INITENDDEF UBYTE the_end + +/* Use the following macros to fill in a structure */ + +#define NEWINITBYTE(offset, value) \ + 0xe0, (UBYTE)((offset) >> 16), (UBYTE)((offset) >> 8), (UBYTE)(offset), \ + (UBYTE)(value), 0 +#define NEWINITWORD(offset, value) \ + 0xd0, (UBYTE)((offset) >> 16), (UBYTE)((offset) >> 8), (UBYTE)(offset), \ + (UWORD)(value) +#define NEWINITLONG(offset, value) \ + 0xc0, (UBYTE)((offset) >> 16), (UBYTE)((offset) >> 8), (UBYTE)(offset), \ + (ULONG)(value) +#define INITPINT(offset, value) \ + 0xc0, (UBYTE)((offset) >> 16), (UBYTE)((offset) >> 8), (UBYTE)(offset), \ + (UPINT)(value) + +#define SMALLINITBYTE(offset, value) \ + 0xa0, (offset), (UBYTE)(value), 0 +#define SMALLINITWORD(offset, value) \ + 0x90, (offset), (UWORD)(value) +#define SMALLINITLONG(offset, value) \ + 0x80, (offset), (ULONG)(value) +#define SMALLINITPINT(offset, value) \ + 0x80, (offset), (UPINT)(value) + +#define INITEND 0 + +/* Obsolete definitions */ + +#define INITBYTE(offset, value) \ + (0xe000 | ((UWORD)(offset) >> 16)), \ + (UWORD)(offset), (UWORD)((value) << 8) +#define INITWORD(offset, value) \ + (0xd000 | ((UWORD)(offset) >> 16)), (UWORD)(offset), (UWORD)(value) +#define INITLONG(offset, value) \ + (0xc000 | ((UWORD)(offset) >> 16)), (UWORD)(offset), \ + (UWORD)((value) >> 16), (UWORD)(value) +#define INITAPTR(offset, value) \ + (0xc000 | ((UWORD)(offset) >> 16)), (UWORD)(offset), \ + (UWORD)((ULONG)(value) >> 16), (UWORD)(value) + +#endif diff --git a/Source/request.c b/Source/request.c new file mode 100644 index 0000000..02ca84e --- /dev/null +++ b/Source/request.c @@ -0,0 +1,1523 @@ +/* + +File: request.c +Author: Neil Cafferkey +Copyright (C) 2001-2010 Neil Cafferkey + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. + +*/ + + +#include +#include +#include +#include + +#include +#include + +#include "device.h" + +#include "request_protos.h" +#include "unit_protos.h" + + +#define KNOWN_EVENTS (S2EVENT_ERROR|S2EVENT_TX|S2EVENT_RX|S2EVENT_ONLINE|\ + S2EVENT_OFFLINE|S2EVENT_BUFF|S2EVENT_HARDWARE|S2EVENT_SOFTWARE) + + +static BOOL CmdInvalid(struct IOSana2Req *request,struct DevBase *base); +static BOOL CmdRead(struct IOSana2Req *request,struct DevBase *base); +static BOOL CmdWrite(struct IOSana2Req *request,struct DevBase *base); +static BOOL CmdFlush(struct IORequest *request,struct DevBase *base); +static BOOL CmdS2DeviceQuery(struct IOSana2Req *request, + struct DevBase *base); +static BOOL CmdGetStationAddress(struct IOSana2Req *request, + struct DevBase *base); +static BOOL CmdConfigInterface(struct IOSana2Req *request, + struct DevBase *base); +static BOOL CmdBroadcast(struct IOSana2Req *request, + struct DevBase *base); +static BOOL CmdTrackType(struct IOSana2Req *request, + struct DevBase *base); +static BOOL CmdUntrackType(struct IOSana2Req *request, + struct DevBase *base); +static BOOL CmdGetTypeStats(struct IOSana2Req *request, + struct DevBase *base); +static BOOL CmdGetSpecialStats(struct IOSana2Req *request, + struct DevBase *base); +static BOOL CmdGetGlobalStats(struct IOSana2Req *request, + struct DevBase *base); +static BOOL CmdOnEvent(struct IOSana2Req *request,struct DevBase *base); +static BOOL CmdReadOrphan(struct IOSana2Req *request, + struct DevBase *base); +static BOOL CmdOnline(struct IOSana2Req *request,struct DevBase *base); +static BOOL CmdOffline(struct IOSana2Req *request,struct DevBase *base); +static BOOL CmdDeviceQuery(struct IOStdReq *request, + struct DevBase *base); +static BOOL CmdAddMulticastAddresses(struct IOSana2Req *request, + struct DevBase *base); +static BOOL CmdDelMulticastAddresses(struct IOSana2Req *request, + struct DevBase *base); + + +static const UWORD supported_commands[]= +{ + CMD_READ, + CMD_WRITE, + CMD_FLUSH, + S2_DEVICEQUERY, + S2_GETSTATIONADDRESS, + S2_CONFIGINTERFACE, + S2_ADDMULTICASTADDRESS, + S2_DELMULTICASTADDRESS, + S2_MULTICAST, + S2_BROADCAST, + S2_TRACKTYPE, + S2_UNTRACKTYPE, + S2_GETTYPESTATS, + S2_GETSPECIALSTATS, + S2_GETGLOBALSTATS, + S2_ONEVENT, + S2_READORPHAN, + S2_ONLINE, + S2_OFFLINE, + NSCMD_DEVICEQUERY, + S2_ADDMULTICASTADDRESSES, + S2_DELMULTICASTADDRESSES, + 0 +}; + + +struct Sana2DeviceQuery sana2_info= +{ + 0, + 0, + 0, + 0, + ADDRESS_SIZE*8, + MTU, + 10000000, + S2WireType_Ethernet +}; + + + +/****i* 3c589.device/ServiceRequest **************************************** +* +* NAME +* ServiceRequest -- Attempt to service a device request. +* +* SYNOPSIS +* ServiceRequest(request) +* +* VOID ServiceRequest(struct IORequest *); +* +* FUNCTION +* Attempts to carry out a request. The relevant unit's semaphore must +* be obtained before calling this function. This function releases the +* semaphore before returning. +* +* INPUTS +* request +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +VOID ServiceRequest(struct IOSana2Req *request,struct DevBase *base) +{ + BOOL complete; + + switch(request->ios2_Req.io_Command) + { + case CMD_READ: + complete=CmdRead(request,base); + break; + case CMD_WRITE: + complete=CmdWrite(request,base); + break; + case CMD_FLUSH: + complete=CmdFlush((APTR)request,base); + break; + case S2_DEVICEQUERY: + complete=CmdS2DeviceQuery((APTR)request,base); + break; + case S2_GETSTATIONADDRESS: + complete=CmdGetStationAddress((APTR)request,base); + break; + case S2_CONFIGINTERFACE: + complete=CmdConfigInterface((APTR)request,base); + break; + case S2_ADDMULTICASTADDRESS: + complete=CmdAddMulticastAddresses((APTR)request,base); + break; + case S2_DELMULTICASTADDRESS: + complete=CmdDelMulticastAddresses((APTR)request,base); + break; + case S2_MULTICAST: + complete=CmdWrite((APTR)request,base); + break; + case S2_BROADCAST: + complete=CmdBroadcast((APTR)request,base); + break; + case S2_TRACKTYPE: + complete=CmdTrackType((APTR)request,base); + break; + case S2_UNTRACKTYPE: + complete=CmdUntrackType((APTR)request,base); + break; + case S2_GETTYPESTATS: + complete=CmdGetTypeStats((APTR)request,base); + break; + case S2_GETSPECIALSTATS: + complete=CmdGetSpecialStats((APTR)request,base); + break; + case S2_GETGLOBALSTATS: + complete=CmdGetGlobalStats((APTR)request,base); + break; + case S2_ONEVENT: + complete=CmdOnEvent((APTR)request,base); + break; + case S2_READORPHAN: + complete=CmdReadOrphan((APTR)request,base); + break; + case S2_ONLINE: + complete=CmdOnline((APTR)request,base); + break; + case S2_OFFLINE: + complete=CmdOffline((APTR)request,base); + break; + case NSCMD_DEVICEQUERY: + complete=CmdDeviceQuery((APTR)request,base); + break; + case S2_ADDMULTICASTADDRESSES: + complete=CmdAddMulticastAddresses((APTR)request,base); + break; + case S2_DELMULTICASTADDRESSES: + complete=CmdDelMulticastAddresses((APTR)request,base); + break; + default: + complete=CmdInvalid((APTR)request,base); + } + + if(complete&&((request->ios2_Req.io_Flags&IOF_QUICK)==0)) + ReplyMsg((APTR)request); + + ReleaseSemaphore(&((struct DevUnit *)request->ios2_Req.io_Unit)-> + access_lock); + return; +} + + + +/****i* 3c589.device/CMD_INVALID ******************************************* +* +* NAME +* CMD_INVALID -- Reject invalid commands. +* +* FUNCTION +* +* INPUTS +* None. +* +* RESULTS +* io_Error - IOERR_NOCMD. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdInvalid(struct IOSana2Req *request,struct DevBase *base) +{ + request->ios2_Req.io_Error=IOERR_NOCMD; + request->ios2_WireError=S2WERR_GENERIC_ERROR; + + return TRUE; +} + + + +/****** 3c589.device/CMD_READ ********************************************** +* +* NAME +* CMD_READ -- Read data. +* +* FUNCTION +* +* INPUTS +* io_Flags +* ios2_PacketType +* ios2_Data +* +* RESULTS +* io_Flags +* io_Error +* ios2_WireError +* ios2_SrcAddr +* ios2_DstAddr +* ios2_DataLength +* ios2_Data +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdRead(struct IOSana2Req *request,struct DevBase *base) +{ + struct DevUnit *unit; + struct Opener *opener; + BOOL complete=FALSE; + + unit=(APTR)request->ios2_Req.io_Unit; + + if((unit->flags&UNITF_ONLINE)!=0) + { + opener=request->ios2_BufferManagement; + PutRequest(&opener->read_port,(APTR)request,base); + } + else + { + request->ios2_Req.io_Error=S2ERR_OUTOFSERVICE; + request->ios2_WireError=S2WERR_UNIT_OFFLINE; + complete=TRUE; + } + + /* Return */ + + return complete; +} + + + +/****** 3c589.device/CMD_WRITE ********************************************* +* +* NAME +* CMD_WRITE -- Write data. +* +* FUNCTION +* +* INPUTS +* io_Flags +* ios2_DstAddr +* ios2_PacketType +* ios2_DataLength +* ios2_Data +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +/****** 3c589.device/S2_MULTICAST ****************************************** +* +* NAME +* S2_MULTICAST -- +* +* FUNCTION +* +* INPUTS +* io_Flags +* ios2_DstAddr - multicast address. +* ios2_PacketType +* ios2_DataLength +* ios2_Data +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdWrite(struct IOSana2Req *request,struct DevBase *base) +{ + struct DevUnit *unit; + BYTE error=0; + ULONG wire_error; + BOOL complete=FALSE; + + /* Check request is valid */ + + unit=(APTR)request->ios2_Req.io_Unit; + if((unit->flags&UNITF_ONLINE)==0) + { + error=S2ERR_OUTOFSERVICE; + wire_error=S2WERR_UNIT_OFFLINE; + } + else if((request->ios2_Req.io_Command==S2_MULTICAST)&& + ((request->ios2_DstAddr[0]&0x1)==0)) + { + error=S2ERR_BAD_ADDRESS; + wire_error=S2WERR_BAD_MULTICAST; + } + + /* Queue request for sending */ + + if(error==0) + PutRequest(unit->request_ports[WRITE_QUEUE],(APTR)request,base); + else + { + request->ios2_Req.io_Error=error; + request->ios2_WireError=wire_error; + complete=TRUE; + } + + /* Return */ + + return complete; +} + + + +/****** 3c589.device/CMD_FLUSH ********************************************* +* +* NAME +* CMD_FLUSH -- . +* +* FUNCTION +* +* INPUTS +* None. +* +* RESULTS +* io_Error +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdFlush(struct IORequest *request,struct DevBase *base) +{ + FlushUnit((APTR)request->io_Unit,EVENT_QUEUE,IOERR_ABORTED,base); + + return TRUE; +} + + + +/****** 3c589.device/S2_DEVICEQUERY **************************************** +* +* NAME +* S2_DEVICEQUERY -- Query device capabilities. +* +* FUNCTION +* +* INPUTS +* ios2_StatData - Pointer to Sana2DeviceQuery structure. +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdS2DeviceQuery(struct IOSana2Req *request, + struct DevBase *base) +{ + struct DevUnit *unit; + struct Sana2DeviceQuery *info; + ULONG size_available,size; + + /* Copy device info */ + + unit=(APTR)request->ios2_Req.io_Unit; + info=request->ios2_StatData; + size=size_available=info->SizeAvailable; + if(size>sizeof(struct Sana2DeviceQuery)) + size=sizeof(struct Sana2DeviceQuery); + + CopyMem(&sana2_info,info,size); + if((unit->flags&UNITF_ROADRUNNER)!=0) + info->BPS=100000000; + + info->SizeAvailable=size_available; + info->SizeSupplied=size; + + /* Return */ + + return TRUE; +} + + + +/****** 3c589.device/S2_GETSTATIONADDDRESS ********************************* +* +* NAME +* S2_GETSTATIONADDDRESS -- +* +* FUNCTION +* +* INPUTS +* None. +* +* RESULTS +* io_Error +* ios2_WireError +* ios2_SrcAddr - current address. +* ios2_DstAddr - default address (zero if none?). +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdGetStationAddress(struct IOSana2Req *request, + struct DevBase *base) +{ + struct DevUnit *unit; + + /* Copy addresses */ + + unit=(APTR)request->ios2_Req.io_Unit; + CopyMem(unit->address,request->ios2_SrcAddr,ADDRESS_SIZE); + CopyMem(unit->default_address,request->ios2_DstAddr,ADDRESS_SIZE); + + /* Return */ + + return TRUE; +} + + + +/****** 3c589.device/S2_CONFIGINTERFACE ************************************ +* +* NAME +* S2_CONFIGINTERFACE -- +* +* FUNCTION +* +* INPUTS +* ios2_SrcAddr - address to use. +* +* RESULTS +* io_Error +* ios2_WireError +* ios2_SrcAddr - address used. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdConfigInterface(struct IOSana2Req *request, + struct DevBase *base) +{ + struct DevUnit *unit; + + /* Configure adapter */ + + unit=(APTR)request->ios2_Req.io_Unit; + if((unit->flags&UNITF_CONFIGURED)==0) + { + CopyMem(request->ios2_SrcAddr,unit->address,ADDRESS_SIZE); + if((unit->flags&UNITF_HAVEADAPTER)!=0) + ConfigureAdapter(unit,base); + unit->flags|=UNITF_CONFIGURED; + } + else + { + request->ios2_Req.io_Error=S2ERR_BAD_STATE; + request->ios2_WireError=S2WERR_IS_CONFIGURED; + } + + /* Return */ + + return TRUE; +} + + + +/****** 3c589.device/S2_BROADCAST ****************************************** +* +* NAME +* S2_BROADCAST -- +* +* FUNCTION +* +* INPUTS +* io_Flags +* ios2_PacketType +* ios2_DataLength +* ios2_Data +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdBroadcast(struct IOSana2Req *request, + struct DevBase *base) +{ + /* Fill in the broadcast address as destination */ + + *((ULONG *)request->ios2_DstAddr)=0xffffffff; + *((UWORD *)(request->ios2_DstAddr+4))=0xffff; + + /* Queue the write as normal */ + + return CmdWrite(request,base); +} + + + +/****** 3c589.device/S2_TRACKTYPE ****************************************** +* +* NAME +* S2_TRACKTYPE -- +* +* FUNCTION +* +* INPUTS +* ios2_PacketType - packet type to start tracking. +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdTrackType(struct IOSana2Req *request, + struct DevBase *base) +{ + struct DevUnit *unit; + struct Opener *opener; + ULONG packet_type,wire_error; + struct TypeTracker *tracker; + struct TypeStats *initial_stats; + BYTE error=0; + + unit=(APTR)request->ios2_Req.io_Unit; + packet_type=request->ios2_PacketType; + + /* Get global tracker */ + + tracker=(struct TypeTracker *) + FindTypeStats(unit,&unit->type_trackers,packet_type,base); + + if(tracker!=NULL) + tracker->user_count++; + else + { + tracker=AllocMem(sizeof(struct TypeTracker),MEMF_PUBLIC|MEMF_CLEAR); + if(tracker!=NULL) + { + tracker->packet_type=packet_type; + tracker->user_count=1; + + Disable(); + AddTail((APTR)&unit->type_trackers,(APTR)tracker); + Enable(); + } + } + + /* Store initial figures for this opener */ + + opener=request->ios2_BufferManagement; + initial_stats=FindTypeStats(unit,&opener->initial_stats,packet_type, + base); + + if(initial_stats!=NULL) + { + error=S2ERR_BAD_STATE; + wire_error=S2WERR_ALREADY_TRACKED; + } + + if(error==0) + { + initial_stats=AllocMem(sizeof(struct TypeStats),MEMF_PUBLIC); + if(initial_stats==NULL) + { + error=S2ERR_NO_RESOURCES; + wire_error=S2WERR_GENERIC_ERROR; + } + } + + if(error==0) + { + CopyMem(tracker,initial_stats,sizeof(struct TypeStats)); + AddTail((APTR)&opener->initial_stats,(APTR)initial_stats); + } + + /* Return */ + + request->ios2_Req.io_Error=error; + request->ios2_WireError=wire_error; + return TRUE; +} + + + +/****** 3c589.device/S2_UNTRACKTYPE **************************************** +* +* NAME +* S2_UNTRACKTYPE -- +* +* FUNCTION +* +* INPUTS +* ios2_PacketType - packet type to stop tracking. +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdUntrackType(struct IOSana2Req *request, + struct DevBase *base) +{ + struct DevUnit *unit; + struct Opener *opener; + ULONG packet_type; + struct TypeTracker *tracker; + struct TypeStats *initial_stats; + + unit=(APTR)request->ios2_Req.io_Unit; + packet_type=request->ios2_PacketType; + + /* Get global tracker and initial figures */ + + tracker=(struct TypeTracker *) + FindTypeStats(unit,&unit->type_trackers,packet_type,base); + opener=request->ios2_BufferManagement; + initial_stats=FindTypeStats(unit,&opener->initial_stats,packet_type, + base); + + /* Decrement tracker usage and free unused structures */ + + if(initial_stats!=NULL) + { + if((--tracker->user_count)==0) + { + Disable(); + Remove((APTR)tracker); + Enable(); + FreeMem(tracker,sizeof(struct TypeTracker)); + } + + Remove((APTR)initial_stats); + FreeMem(initial_stats,sizeof(struct TypeStats)); + } + else + { + request->ios2_Req.io_Error=S2ERR_BAD_STATE; + request->ios2_WireError=S2WERR_NOT_TRACKED; + } + + /* Return */ + + return TRUE; +} + + + +/****** 3c589.device/S2_GETTYPESTATS *************************************** +* +* NAME +* S2_GETTYPESTATS -- +* +* FUNCTION +* +* INPUTS +* ios2_PacketType - packet type to get statistics on. +* ios2_StatData - pointer to a Sana2PacketTypeStats structure. +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdGetTypeStats(struct IOSana2Req *request, + struct DevBase *base) +{ + struct DevUnit *unit; + struct Opener *opener; + ULONG packet_type; + struct TypeStats *initial_stats,*tracker; + struct Sana2PacketTypeStats *stats; + + unit=(APTR)request->ios2_Req.io_Unit; + packet_type=request->ios2_PacketType; + + /* Get global tracker and initial figures */ + + tracker=FindTypeStats(unit,&unit->type_trackers,packet_type,base); + opener=request->ios2_BufferManagement; + initial_stats=FindTypeStats(unit,&opener->initial_stats,packet_type, + base); + + /* Copy and adjust figures */ + + if(initial_stats!=NULL) + { + stats=request->ios2_StatData; + CopyMem(&tracker->stats,stats,sizeof(struct Sana2PacketTypeStats)); + stats->PacketsSent-=initial_stats->stats.PacketsSent; + stats->PacketsReceived-=initial_stats->stats.PacketsReceived; + stats->BytesSent-=initial_stats->stats.BytesSent; + stats->BytesReceived-=initial_stats->stats.BytesReceived; + stats->PacketsDropped-=initial_stats->stats.PacketsDropped; + } + else + { + request->ios2_Req.io_Error=S2ERR_BAD_STATE; + request->ios2_WireError=S2WERR_NOT_TRACKED; + } + + /* Return */ + + return TRUE; +} + + + +/****** 3c589.device/S2_GETSPECIALSTATS ************************************ +* +* NAME +* S2_GETSPECIALSTATS -- +* +* FUNCTION +* +* INPUTS +* ios2_StatData - Pointer to Sana2SpecialStatHeader structure. +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdGetSpecialStats(struct IOSana2Req *request, + struct DevBase *base) +{ + struct DevUnit *unit; + UWORD i,stat_count; + struct Sana2SpecialStatHeader *header; + struct Sana2SpecialStatRecord *record; + + /* Fill in stats */ + + unit=(APTR)request->ios2_Req.io_Unit; + header=request->ios2_StatData; + record=(APTR)(header+1); + + stat_count=header->RecordCountMax; + if(stat_count>STAT_COUNT) + stat_count=STAT_COUNT; + + for(i=0;iType=(S2WireType_Ethernet<<16)+i; + record->Count=unit->special_stats[i]; + record->String=(TEXT *)&unit->openers.mlh_Tail; + record++; + } + + header->RecordCountSupplied=stat_count; + + /* Return */ + + return TRUE; +} + + + +/****** 3c589.device/S2_GETGLOBALSTATS ************************************* +* +* NAME +* S2_GETGLOBALSTATS -- +* +* FUNCTION +* +* INPUTS +* ios2_StatData - Pointer to Sana2DeviceStats structure. +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdGetGlobalStats(struct IOSana2Req *request, + struct DevBase *base) +{ + struct DevUnit *unit; + + /* Copy stats */ + + unit=(APTR)request->ios2_Req.io_Unit; + CopyMem(&unit->stats,request->ios2_StatData, + sizeof(struct Sana2DeviceStats)); + + /* Return */ + + return TRUE; +} + + + +/****** 3c589.device/S2_ONEVENT ******************************************** +* +* NAME +* S2_ONEVENT -- +* +* FUNCTION +* +* INPUTS +* ios2_WireError +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdOnEvent(struct IOSana2Req *request,struct DevBase *base) +{ + struct DevUnit *unit; + ULONG events,wanted_events; + BOOL complete=FALSE; + + /* Check if we understand the event types */ + + unit=(APTR)request->ios2_Req.io_Unit; + wanted_events=request->ios2_WireError; + if((wanted_events&~KNOWN_EVENTS)!=0) + { + request->ios2_Req.io_Error=S2ERR_NOT_SUPPORTED; + events=S2WERR_BAD_EVENT; + } + else + { + if((unit->flags&UNITF_ONLINE)!=0) + events=S2EVENT_ONLINE; + else + events=S2EVENT_OFFLINE; + + events&=wanted_events; + } + + /* Reply request if a wanted event has already occurred */ + + if(events!=0) + { + request->ios2_WireError=events; + complete=TRUE; + } + else + PutRequest(unit->request_ports[EVENT_QUEUE],(APTR)request,base); + + /* Return */ + + return complete; +} + + + +/****** 3c589.device/S2_READORPHAN ***************************************** +* +* NAME +* S2_READORPHAN -- +* +* FUNCTION +* +* INPUTS +* io_Flags +* ios2_Data +* +* RESULTS +* io_Flags +* io_Error +* ios2_WireError +* ios2_PacketType - A copy of the packet's type field. +* ios2_SrcAddr +* ios2_DstAddr +* ios2_DataLength +* ios2_Data +* +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdReadOrphan(struct IOSana2Req *request, + struct DevBase *base) +{ + struct DevUnit *unit; + BYTE error=0; + ULONG wire_error; + BOOL complete=FALSE; + + /* Check request is valid */ + + unit=(APTR)request->ios2_Req.io_Unit; + if((unit->flags&UNITF_ONLINE)==0) + { + error=S2ERR_OUTOFSERVICE; + wire_error=S2WERR_UNIT_OFFLINE; + } + + /* Queue request */ + + if(error==0) + PutRequest(unit->request_ports[ADOPT_QUEUE],(APTR)request,base); + else + { + request->ios2_Req.io_Error=error; + request->ios2_WireError=wire_error; + complete=TRUE; + } + + /* Return */ + + return complete; +} + + + +/****** 3c589.device/S2_ONLINE ********************************************* +* +* NAME +* S2_ONLINE -- +* +* FUNCTION +* +* INPUTS +* None. +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdOnline(struct IOSana2Req *request,struct DevBase *base) +{ + struct DevUnit *unit; + BYTE error=0; + ULONG wire_error; + UWORD i; + + /* Check request is valid */ + + unit=(APTR)request->ios2_Req.io_Unit; + if((unit->flags&UNITF_CONFIGURED)==0) + { + error=S2ERR_BAD_STATE; + wire_error=S2WERR_NOT_CONFIGURED; + } + if((unit->flags&UNITF_HAVEADAPTER)==0) + { + error=S2ERR_OUTOFSERVICE; + wire_error=S2WERR_RCVREL_HDW_ERR; + } + + /* Clear global and special stats and put adapter back online */ + + if((error==0)&&((unit->flags&UNITF_ONLINE)==0)) + { + unit->stats.PacketsReceived=0; + unit->stats.PacketsSent=0; + unit->stats.BadData=0; + unit->stats.Overruns=0; + unit->stats.UnknownTypesReceived=0; + unit->stats.Reconfigurations=0; + + for(i=0;ispecial_stats[i]=0; + + GoOnline(unit,base); + } + + /* Return */ + + request->ios2_Req.io_Error=error; + request->ios2_WireError=wire_error; + return TRUE; +} + + + +/****** 3c589.device/S2_OFFLINE ******************************************** +* +* NAME +* S2_OFFLINE -- +* +* FUNCTION +* +* INPUTS +* None. +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdOffline(struct IOSana2Req *request,struct DevBase *base) +{ + struct DevUnit *unit; + + /* Put adapter offline */ + + unit=(APTR)request->ios2_Req.io_Unit; + if((unit->flags&UNITF_ONLINE)!=0) + GoOffline(unit,base); + + /* Return */ + + return TRUE; +} + + + +/****** 3c589.device/NSCMD_DEVICEQUERY ************************************* +* +* NAME +* NSCMD_DEVICEQUERY -- Query device capabilities. +* +* FUNCTION +* +* INPUTS +* io_Length - ???. +* io_Data - pointer to NSDeviceQueryResult structure. +* +* RESULTS +* io_Error +* io_Actual - size of structure device can handle. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +* Note that we have to pretend the request structure is an IOStdReq. +* +*/ + +static BOOL CmdDeviceQuery(struct IOStdReq *request, + struct DevBase *base) +{ + struct NSDeviceQueryResult *info; + + /* Set structure size twice */ + + info=request->io_Data; + request->io_Actual=info->SizeAvailable= + (ULONG)OFFSET(NSDeviceQueryResult,SupportedCommands)+sizeof(APTR); + + /* Report device details */ + + info->DeviceType=NSDEVTYPE_SANA2; + info->DeviceSubType=0; + + info->SupportedCommands=(APTR)supported_commands; + + /* Return */ + + return TRUE; +} + + + +/****** 3c589.device/S2_ADDMULTICASTADDRESS ******************************** +* +* NAME +* S2_ADDMULTICASTADDRESS -- +* +* FUNCTION +* +* INPUTS +* ios2_SrcAddr - multicast address. +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +/****** 3c589.device/S2_ADDMULTICASTADDRESSES ****************************** +* +* NAME +* S2_ADDMULTICASTADDRESSES -- +* +* FUNCTION +* +* INPUTS +* ios2_SrcAddr - lower bound. +* ios2_DstAddr - upper bound. +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdAddMulticastAddresses(struct IOSana2Req *request, + struct DevBase *base) +{ + struct DevUnit *unit; + UBYTE *lower_bound,*upper_bound; + + unit=(APTR)request->ios2_Req.io_Unit; + + lower_bound=request->ios2_SrcAddr; + if(request->ios2_Req.io_Command==S2_ADDMULTICASTADDRESS) + upper_bound=lower_bound; + else + upper_bound=request->ios2_DstAddr; + + if(!AddMulticastRange(unit,lower_bound,upper_bound,base)) + { + request->ios2_Req.io_Error=S2ERR_NO_RESOURCES; + request->ios2_WireError=S2WERR_GENERIC_ERROR; + } + + /* Return */ + + return TRUE; +} + + + +/****** 3c589.device/S2_DELMULTICASTADDRESS ******************************** +* +* NAME +* S2_DELMULTICASTADDRESS -- +* +* FUNCTION +* +* INPUTS +* ios2_SrcAddr - multicast address. +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +/****** 3c589.device/S2_DELMULTICASTADDRESSES ****************************** +* +* NAME +* S2_DELMULTICASTADDRESSES -- +* +* FUNCTION +* +* INPUTS +* ios2_SrcAddr - lower bound. +* ios2_DstAddr - upper bound. +* +* RESULTS +* io_Error +* ios2_WireError +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL CmdDelMulticastAddresses(struct IOSana2Req *request, + struct DevBase *base) +{ + struct DevUnit *unit; + UBYTE *lower_bound,*upper_bound; + + unit=(APTR)request->ios2_Req.io_Unit; + + lower_bound=request->ios2_SrcAddr; + if(request->ios2_Req.io_Command==S2_DELMULTICASTADDRESS) + upper_bound=lower_bound; + else + upper_bound=request->ios2_DstAddr; + + if(!RemMulticastRange(unit,lower_bound,upper_bound,base)) + { + request->ios2_Req.io_Error=S2ERR_BAD_STATE; + request->ios2_WireError=S2WERR_BAD_MULTICAST; + } + + /* Return */ + + return TRUE; +} + + + +/****i* 3c589.device/PutRequest ******************************************** +* +* NAME +* PutRequest -- . +* +* SYNOPSIS +* PutRequest(port,request) +* +* VOID PutRequest(struct MsgPort *,struct IORequest *); +* +* FUNCTION +* +* INPUTS +* port +* request +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +VOID PutRequest(struct MsgPort *port,struct IORequest *request, + struct DevBase *base) +{ + request->io_Flags&=~IOF_QUICK; + PutMsg(port,(APTR)request); + + return; +} + + + diff --git a/Source/request_protos.h b/Source/request_protos.h new file mode 100644 index 0000000..e52ad7f --- /dev/null +++ b/Source/request_protos.h @@ -0,0 +1,36 @@ +/* + +File: request_protos.h +Author: Neil Cafferkey +Copyright (C) 2002 Neil Cafferkey + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. + +*/ + +#ifndef REQUEST_PROTOS_H +#define REQUEST_PROTOS_H + + +#include "device.h" + +VOID ServiceRequest(struct IOSana2Req *request,struct DevBase *base); +VOID PutRequest(struct MsgPort *port,struct IORequest *request, + struct DevBase *base); + +#endif + + diff --git a/Source/unit.c b/Source/unit.c new file mode 100644 index 0000000..cb1f9bc --- /dev/null +++ b/Source/unit.c @@ -0,0 +1,2166 @@ +/* + +File: unit.c +Author: Neil Cafferkey +Copyright (C) 2001-2010 Neil Cafferkey + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. + +*/ + + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "device.h" +#include "etherlink3.h" + +#include "unit_protos.h" +#include "request_protos.h" + + +#define TASK_PRIORITY 0 +#define STACK_SIZE 4096 +#define MAX_TUPLE_SIZE 0xff +#define TUPLE_BUFFER_SIZE (MAX_TUPLE_SIZE+8) +#define INT_MASK\ + (EL3INTF_RXCOMPLETE|EL3INTF_TXAVAIL|EL3INTF_TXCOMPLETE) + + +IMPORT struct ExecBase *AbsExecBase; + +static BOOL InitialiseCard(struct DevUnit *unit,struct DevBase *base); +static VOID InitialiseAdapter(struct DevUnit *unit,struct DevBase *base); +static struct AddressRange *FindMulticastRange(struct DevUnit *unit, + ULONG lower_bound_left,UWORD lower_bound_right,ULONG upper_bound_left, + UWORD upper_bound_right,struct DevBase *base); +static VOID CardRemovedInt(struct DevUnit *unit REG("a1")); +static VOID CardInsertedInt(struct DevUnit *unit REG("a1")); +static UBYTE CardStatusInt(UBYTE mask REG("d0"), + struct DevUnit *unit REG("a1")); +static VOID RxInt(struct DevUnit *unit REG("a1")); +static VOID CopyPacket(struct DevUnit *unit,struct IOSana2Req *request, + UWORD packet_size,UWORD packet_type,BOOL all_read,struct DevBase *base); +static BOOL AddressFilter(struct DevUnit *unit,UBYTE *address, + struct DevBase *base); +static VOID TxInt(struct DevUnit *unit REG("a1")); +static VOID TxError(struct DevUnit *unit,struct DevBase *base); +static VOID ReportEvents(struct DevUnit *unit,ULONG events, + struct DevBase *base); +static VOID UnitTask(); +static UWORD ReadEEPROM(volatile UBYTE *io_base,UWORD index); + + + +/****i* 3c589.device/GetUnit *********************************************** +* +* NAME +* GetUnit -- Get a unit by number. +* +* SYNOPSIS +* unit = GetUnit(unit_num) +* +* struct DevUnit *GetUnit(ULONG); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +struct DevUnit *GetUnit(ULONG unit_num,struct DevBase *base) +{ + struct DevUnit *unit; + + unit=FindUnit(unit_num,base); + + if(unit==NULL) + { + unit=CreateUnit(unit_num,base); + if(unit!=NULL) + AddTail((APTR)&base->units,(APTR)unit); + } + + return unit; +} + + + +/****i* 3c589.device/FindUnit ********************************************** +* +* NAME +* FindUnit -- Find a unit by number. +* +* SYNOPSIS +* unit = FindUnit(unit_num) +* +* struct DevUnit *FindUnit(ULONG); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +struct DevUnit *FindUnit(ULONG unit_num,struct DevBase *base) +{ + struct DevUnit *unit,*tail; + BOOL found; + + unit=(APTR)base->units.mlh_Head; + tail=(APTR)&base->units.mlh_Tail; + found=FALSE; + + while((unit!=tail)&&!found) + { + if(unit->unit_num==unit_num) + found=TRUE; + else + unit=(APTR)unit->node.mln_Succ; + } + + if(!found) + unit=NULL; + + return unit; +} + + + +/****i* 3c589.device/CreateUnit ******************************************** +* +* NAME +* CreateUnit -- Create a unit. +* +* SYNOPSIS +* unit = CreateUnit(unit_num) +* +* struct DevUnit *CreateUnit(ULONG); +* +* FUNCTION +* Creates a new unit. +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +struct DevUnit *CreateUnit(ULONG unit_num,struct DevBase *base) +{ + BOOL success=TRUE; + struct DevUnit *unit; + struct Task *task; + struct MsgPort *port; + UBYTE i; + struct CardHandle *card_handle; + APTR stack; + struct Interrupt *card_removed_int,*card_inserted_int,*card_status_int; + + unit=AllocMem(sizeof(struct DevUnit),MEMF_CLEAR); + if(unit==NULL) + success=FALSE; + + if(success) + { + unit->unit_num=unit_num; + unit->device=base; + + InitSemaphore(&unit->access_lock); + + /* Set up packet filter command */ + + unit->rx_filter_cmd=EL3CMD_SETRXFILTER|EL3CMD_SETRXFILTERF_BCAST + |EL3CMD_SETRXFILTERF_UCAST; + + /* Create the message ports for queuing requests */ + + for(i=0;irequest_ports[i]=port=AllocMem(sizeof(struct MsgPort), + MEMF_PUBLIC|MEMF_CLEAR); + if(port==NULL) + success=FALSE; + + if(success) + { + NewList(&port->mp_MsgList); + port->mp_Flags=PA_IGNORE; + port->mp_SigTask=&unit->tx_int; + } + } + + card_handle=unit->card_handle= + AllocMem(sizeof(struct CardHandle),MEMF_PUBLIC|MEMF_CLEAR); + unit->tuple_buffer= + AllocVec(TUPLE_BUFFER_SIZE,MEMF_ANY); + unit->rx_buffer=AllocVec((MAX_PACKET_SIZE+3)&~3,MEMF_PUBLIC); + unit->tx_buffer=AllocVec(MAX_PACKET_SIZE,MEMF_PUBLIC); + if((card_handle==NULL)||(unit->tuple_buffer==NULL)|| + (unit->rx_buffer==NULL)||(unit->tx_buffer==NULL)) + success=FALSE; + } + + if(success) + { + NewList((APTR)&unit->openers); + NewList((APTR)&unit->type_trackers); + NewList((APTR)&unit->multicast_ranges); + + /* Initialise transmit and receive interrupts */ + + unit->rx_int.is_Node.ln_Name=(TEXT *)device_name; + unit->rx_int.is_Node.ln_Pri=16; + unit->rx_int.is_Code=RxInt; + unit->rx_int.is_Data=unit; + + unit->tx_int.is_Node.ln_Name=(TEXT *)device_name; + unit->tx_int.is_Code=TxInt; + unit->tx_int.is_Data=unit; + + unit->request_ports[WRITE_QUEUE]->mp_Flags=PA_SOFTINT; + } + + if(success) + { + /* Set up card handle */ + + card_handle->cah_CardNode.ln_Pri=HANDLE_PRIORITY; + card_handle->cah_CardNode.ln_Name=(APTR)device_name; + card_handle->cah_CardFlags=CARDF_IFAVAILABLE; + + card_handle->cah_CardRemoved=card_removed_int= + AllocVec(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_CLEAR); + + card_handle->cah_CardInserted=card_inserted_int= + AllocVec(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_CLEAR); + + card_handle->cah_CardStatus=card_status_int= + AllocVec(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_CLEAR); + + if((card_removed_int==NULL) + ||(card_inserted_int==NULL) + ||(card_status_int==NULL)) + success=FALSE; + } + + if(success) + { + /* Try to gain access to card */ + + card_removed_int->is_Code=CardRemovedInt; + card_removed_int->is_Data=unit; + card_inserted_int->is_Code=CardInsertedInt; + card_inserted_int->is_Data=unit; + card_status_int->is_Code=(APTR)CardStatusInt; + card_status_int->is_Data=unit; + + if(OwnCard(card_handle)!=0) + success=FALSE; + } + + if(success) + { + unit->flags|=UNITF_HAVECARD; + if(!InitialiseCard(unit,base)) + success=FALSE; + + /* Create a new task */ + + unit->task=task=AllocMem(sizeof(struct Task),MEMF_PUBLIC|MEMF_CLEAR); + if(task==NULL) + success=FALSE; + } + + if(success) + { + stack=AllocMem(STACK_SIZE,MEMF_PUBLIC); + if(stack==NULL) + success=FALSE; + } + + if(success) + { + /* Initialise and start task */ + + task->tc_Node.ln_Type=NT_TASK; + task->tc_Node.ln_Pri=TASK_PRIORITY; + task->tc_Node.ln_Name=(APTR)device_name; + task->tc_SPUpper=stack+STACK_SIZE; + task->tc_SPLower=stack; + task->tc_SPReg=stack+STACK_SIZE; + NewList(&task->tc_MemEntry); + + if(AddTask(task,UnitTask,NULL)==NULL) + success=FALSE; + } + + /* Send the unit to the new task */ + + if(success) + task->tc_UserData=unit; + + if(!success) + { + DeleteUnit(unit,base); + unit=NULL; + } + + return unit; +} + + + +/****i* 3c589.device/DeleteUnit ******************************************** +* +* NAME +* DeleteUnit -- Delete a unit. +* +* SYNOPSIS +* DeleteUnit(unit) +* +* VOID DeleteUnit(struct DevUnit *); +* +* FUNCTION +* Deletes a unit. +* +* INPUTS +* unit - Device unit (can be NULL). +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +VOID DeleteUnit(struct DevUnit *unit,struct DevBase *base) +{ + UBYTE i; + struct CardHandle *card_handle; + struct Task *task; + + if(unit!=NULL) + { + task=unit->task; + if(task!=NULL) + { + if(task->tc_SPLower!=NULL) + { + RemTask(task); + FreeMem(task->tc_SPLower,STACK_SIZE); + } + FreeMem(task,sizeof(struct Task)); + } + + for(i=0;irequest_ports[i]!=NULL) + FreeMem(unit->request_ports[i],sizeof(struct MsgPort)); + } + + FreeVec(unit->tuple_buffer); + + card_handle=unit->card_handle; + if(card_handle!=NULL) + { + if((unit->flags&UNITF_HAVECARD)!=0) + { + if((unit->flags&UNITF_HAVEADAPTER)!=0) + GoOffline(unit,base); + + unit->flags&=~UNITF_HAVEADAPTER; + CardMiscControl(card_handle,0); + CardResetCard(card_handle); + ReleaseCard(card_handle,CARDF_REMOVEHANDLE); + } + + FreeVec(card_handle->cah_CardStatus); + FreeVec(card_handle->cah_CardInserted); + FreeVec(card_handle->cah_CardRemoved); + + FreeMem(card_handle,sizeof(struct CardHandle)); + } + + FreeVec(unit->tx_buffer); + FreeVec(unit->rx_buffer); + + FreeMem(unit,sizeof(struct DevUnit)); + } + + return; +} + + + +/****i* 3c589.device/InitialiseCard **************************************** +* +* NAME +* InitialiseCard -- . +* +* SYNOPSIS +* success = InitialiseCard(unit) +* +* BOOL InitialiseCard(struct DevUnit *); +* +* FUNCTION +* +* INPUTS +* unit +* +* RESULT +* success +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL InitialiseCard(struct DevUnit *unit,struct DevBase *base) +{ + BOOL success=TRUE; + struct CardMemoryMap *card_map; + struct CardHandle *card_handle; + UBYTE config_value,i,window_count,*tuple_buffer; + const struct TagItem *tuple_tags=NULL; + ULONG *io_bases,*io_lengths,io_base=0,config_base_offset; + UWORD maker,product; + + /* Wake up card */ + + card_handle=unit->card_handle; + CardMiscControl(card_handle,CARD_ENABLEF_DIGAUDIO|CARD_DISABLEF_WP); + + /* Get card's make and model */ + + tuple_buffer=unit->tuple_buffer; + if(CopyTuple(card_handle,tuple_buffer,PCCARD_TPL_MANFID,MAX_TUPLE_SIZE)) + { + tuple_tags=PCCard_GetTupleInfo(tuple_buffer); + if(tuple_tags!=NULL) + { + maker=GetTagData(PCCARD_Maker,0,tuple_tags); + product=GetTagData(PCCARD_Product,0,tuple_tags); + } + } + + /* Check this is a card we can use */ + + if((tuple_tags==NULL)||!((maker==0x101)&&((product==0x35)|| + (product==0x3d)||(product==0x562)||(product==0x589)|| + (product==0x556)||(product==0x574)))) + success=FALSE; + + if((product==0x556)||(product==0x574)) + unit->flags|=UNITF_ROADRUNNER; + + /* Get configuration data */ + + if(!CopyTuple(card_handle,tuple_buffer,PCCARD_TPL_CONFIG,MAX_TUPLE_SIZE)) + success=FALSE; + + if(success) + { + PCCard_FreeTupleInfo(tuple_tags); + tuple_tags=PCCard_GetTupleInfo(tuple_buffer); + if(tuple_tags==NULL) + success=FALSE; + } + + if(success) + { + config_base_offset=GetTagData(PCCARD_RegisterBase,0,tuple_tags); + + PCCard_FreeTupleInfo(tuple_tags); + tuple_tags=NULL; + + /* Get IO base */ + + if(!CopyTuple(card_handle,tuple_buffer,PCCARD_TPL_CFTABLEENTRY, + MAX_TUPLE_SIZE)) + success=FALSE; + } + + if(success) + { + tuple_tags=PCCard_GetTupleInfo(tuple_buffer); + if(tuple_tags==NULL) + success=FALSE; + } + + if(success) + { + config_value=GetTagData(PCCARD_ModeNo,0,tuple_tags); + if(product = 0x562 && config_value == 9) + config_value = 7; + + io_bases=(APTR)GetTagData(PCCARD_IOWinBases,NULL,tuple_tags); + if(io_bases==NULL) + success=FALSE; + } + + if(success) + { + io_lengths=(APTR)GetTagData(PCCARD_IOWinLengths,NULL,tuple_tags); + + window_count=GetTagData(PCCARD_IOWinCount,0,tuple_tags); + + for(i=0;(iconfig_base=card_map->cmm_AttributeMemory+config_base_offset; + + unit->io_base=card_map->cmm_IOMemory+io_base; + unit->config_base[PCCARD_REG_COR]=config_value; + unit->config_base[PCCARD_REG_CCSR]|=PCCARD_REG_CCSRF_AUDIOENABLE; + + InitialiseAdapter(unit,base); + unit->flags|=UNITF_HAVEADAPTER; + } + + return success; +} + + + +/****i* 3c589.device/InitialiseAdapter ************************************* +* +* NAME +* InitialiseAdapter -- . +* +* SYNOPSIS +* InitialiseAdapter(unit) +* +* VOID InitialiseAdapter(struct DevUnit *); +* +* FUNCTION +* +* INPUTS +* unit +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static VOID InitialiseAdapter(struct DevUnit *unit,struct DevBase *base) +{ + volatile UBYTE *io_base; + UBYTE *p,i; + UWORD address_part,config,link,media,new_media,medium,media_status; + + /* Select IO addresses and interrupt */ + + io_base=unit->io_base; + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|0); + LEWordOut(io_base+EL3REG_RESCONFIG,0x3f00); + + /* Get default MAC address */ + + p=unit->default_address; + + for(i=0;i>8; + *p++=address_part&0xff; + } + + /* Get available transceivers */ + + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|0); + media=LEWordIn(io_base+EL3REG_CONFIG); + + /* Get transceivers with an active link */ + + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|4); + link=0; + media_status=LEWordIn(io_base+EL3REG_MEDIA); + if((media_status&EL3REG_MEDIAF_BEAT)!=0) + link|=EL3REG_CONFIGF_HASTP; + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|0); + + new_media=media&link; + if((new_media)!=0) + media=new_media; + else + { + /* Get transceiver choice from EEPROM */ + + config=ReadEEPROM(io_base,EL3EEPROM_ADDRCONFIG)& + (EL3REG_ADDRCONFIG_XCVRMASK|EL3REG_ADDRCONFIGF_AUTOSELECT); + + if(config==EL3REG_ADDRCONFIG_XCVRTP) + new_media=EL3REG_CONFIGF_HASTP; + else if(config==EL3REG_ADDRCONFIG_XCVRAUI) + new_media=EL3REG_CONFIGF_HASAUI; + else if(config==EL3REG_ADDRCONFIG_XCVRCOAX) + new_media=EL3REG_CONFIGF_HASCOAX; + else + new_media=EL3REG_CONFIGF_HASTP|EL3REG_CONFIGF_HASCOAX| + EL3REG_CONFIGF_HASAUI; + + new_media&=media; + if(new_media!=0) + media=new_media; + } + + /* Prioritised choice from remaining transceivers */ + + if((media&EL3REG_CONFIGF_HASTP)!=0) + medium=EL3REG_ADDRCONFIG_XCVRTP; + else if((media&EL3REG_CONFIGF_HASCOAX)!=0) + medium=EL3REG_ADDRCONFIG_XCVRCOAX; + else + medium=EL3REG_ADDRCONFIG_XCVRAUI; + unit->transceiver=medium; + + return; +} + + + +/****i* 3c589.device/ConfigureAdapter ************************************** +* +* NAME +* ConfigureAdapter -- . +* +* SYNOPSIS +* ConfigureAdapter(unit) +* +* VOID ConfigureAdapter(struct DevUnit *); +* +* FUNCTION +* +* INPUTS +* unit +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +VOID ConfigureAdapter(struct DevUnit *unit,struct DevBase *base) +{ + volatile UBYTE *io_base; + UBYTE i; + + /* Set MAC address */ + + io_base=unit->io_base; + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|2); + + for(i=0;iaddress[i]); + + /* Decide on promiscuous mode */ + + if((unit->flags&UNITF_PROM)!=0) + unit->rx_filter_cmd|=EL3CMD_SETRXFILTERF_PROM; + + /* Select chosen transceiver */ + + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|0); + LEWordOut(io_base+EL3REG_ADDRCONFIG,unit->transceiver); + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|1); + + /* Go online */ + + GoOnline(unit,base); + + /* Return */ + + return; +} + + + +/****i* 3c589.device/GoOnline ********************************************** +* +* NAME +* GoOnline -- . +* +* SYNOPSIS +* GoOnline(unit) +* +* VOID GoOnline(struct DevUnit *); +* +* FUNCTION +* +* INPUTS +* unit +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +VOID GoOnline(struct DevUnit *unit,struct DevBase *base) +{ + volatile UBYTE *io_base; + UWORD transceiver; + + /* Choose interrupts */ + + unit->flags|=UNITF_ONLINE; + io_base=unit->io_base; + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SETINTMASK|INT_MASK); + LEWordOut(io_base+EL3REG_COMMAND,(EL3CMD_SETZEROMASK)|0xff); + + /* Enable the transceiver */ + + transceiver=unit->transceiver; + + if(transceiver==EL3REG_ADDRCONFIG_XCVRTP) + { + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|4); + LEWordOut(io_base+EL3REG_MEDIA, + EL3REG_MEDIAF_BEATENABLE|EL3REG_MEDIAF_JABBERENABLE); + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|1); + } + else if(transceiver==EL3REG_ADDRCONFIG_XCVRCOAX) + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_STARTCOAX|0); + + LEWordOut(io_base+EL3REG_COMMAND,unit->rx_filter_cmd); + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_RXENABLE); + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_TXENABLE); + + /* Record start time and report Online event */ + + GetSysTime(&unit->stats.LastStart); + ReportEvents(unit,S2EVENT_ONLINE,base); + + return; +} + + + +/****i* 3c589.device/GoOffline ********************************************* +* +* NAME +* GoOffline -- . +* +* SYNOPSIS +* GoOffline(unit) +* +* VOID GoOffline(struct DevUnit *); +* +* FUNCTION +* +* INPUTS +* unit +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +VOID GoOffline(struct DevUnit *unit,struct DevBase *base) +{ + volatile UBYTE *io_base; + + io_base=unit->io_base; + unit->flags&=~UNITF_ONLINE; + + if((unit->flags&UNITF_HAVEADAPTER)!=0) + { + /* Stop interrupts */ + + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SETINTMASK|0); + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_ACKINT|EL3INTF_ANY); + + /* Stop transmission and reception */ + + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_RXDISABLE); + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_TXDISABLE); + + /* Turn off media functions */ + + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|4); + LEWordOut(io_base+EL3REG_MEDIA,0); + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SELECTWINDOW|1); + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_STOPCOAX|0); + } + + /* Flush pending read and write requests */ + + FlushUnit(unit,WRITE_QUEUE,S2ERR_OUTOFSERVICE,base); + + /* Report Offline event and return */ + + ReportEvents(unit,S2EVENT_OFFLINE,base); + return; +} + + + +/****i* 3c589.device/AddMulticastRange ************************************* +* +* NAME +* AddMulticastRange -- . +* +* SYNOPSIS +* success = AddMulticastRange(unit,lower_bound,upper_bound) +* +* BOOL AddMulticastRange(struct DevUnit *,UBYTE *,UBYTE *); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +BOOL AddMulticastRange(struct DevUnit *unit,UBYTE *lower_bound, + UBYTE *upper_bound,struct DevBase *base) +{ + struct AddressRange *range; + ULONG lower_bound_left,upper_bound_left; + UWORD lower_bound_right,upper_bound_right; + + lower_bound_left=BELong(*((ULONG *)lower_bound)); + lower_bound_right=BEWord(*((UWORD *)(lower_bound+4))); + upper_bound_left=BELong(*((ULONG *)upper_bound)); + upper_bound_right=BEWord(*((UWORD *)(upper_bound+4))); + + range=FindMulticastRange(unit,lower_bound_left,lower_bound_right, + upper_bound_left,upper_bound_right,base); + + if(range!=NULL) + range->add_count++; + else + { + range=AllocMem(sizeof(struct AddressRange),MEMF_PUBLIC); + if(range!=NULL) + { + range->lower_bound_left=lower_bound_left; + range->lower_bound_right=lower_bound_right; + range->upper_bound_left=upper_bound_left; + range->upper_bound_right=upper_bound_right; + range->add_count=1; + + Disable(); + AddTail((APTR)&unit->multicast_ranges,(APTR)range); + Enable(); + + if(unit->range_count++==0) + { + unit->rx_filter_cmd|=EL3CMD_SETRXFILTERF_MCAST; + LEWordOut(unit->io_base+EL3REG_COMMAND,unit->rx_filter_cmd); + } + } + } + + return range!=NULL; +} + + + +/****i* 3c589.device/RemMulticastRange ************************************* +* +* NAME +* RemMulticastRange -- . +* +* SYNOPSIS +* found = RemMulticastRange(unit,lower_bound,upper_bound) +* +* BOOL RemMulticastRange(struct DevUnit *,UBYTE *,UBYTE *); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +BOOL RemMulticastRange(struct DevUnit *unit,UBYTE *lower_bound, + UBYTE *upper_bound,struct DevBase *base) +{ + struct AddressRange *range; + ULONG lower_bound_left,upper_bound_left; + UWORD lower_bound_right,upper_bound_right; + + lower_bound_left=BELong(*((ULONG *)lower_bound)); + lower_bound_right=BEWord(*((UWORD *)(lower_bound+4))); + upper_bound_left=BELong(*((ULONG *)upper_bound)); + upper_bound_right=BEWord(*((UWORD *)(upper_bound+4))); + + range=FindMulticastRange(unit,lower_bound_left,lower_bound_right, + upper_bound_left,upper_bound_right,base); + + if(range!=NULL) + { + if(--range->add_count==0) + { + Disable(); + Remove((APTR)range); + Enable(); + FreeMem(range,sizeof(struct AddressRange)); + + if(--unit->range_count==0) + { + unit->rx_filter_cmd&=~EL3CMD_SETRXFILTERF_MCAST; + LEWordOut(unit->io_base+EL3REG_COMMAND,unit->rx_filter_cmd); + } + } + } + + return range!=NULL; +} + + + +/****i* 3c589.device/FindMulticastRange ************************************* +* +* NAME +* FindMulticastRange -- . +* +* SYNOPSIS +* range = FindMulticastRange(unit,lower_bound_left, +* lower_bound_right,upper_bound_left,upper_bound_right) +* +* struct AddressRange *FindMulticastRange(struct DevUnit *,ULONG, +* UWORD,ULONG,UWORD); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static struct AddressRange *FindMulticastRange(struct DevUnit *unit, + ULONG lower_bound_left,UWORD lower_bound_right,ULONG upper_bound_left, + UWORD upper_bound_right,struct DevBase *base) +{ + struct AddressRange *range,*tail; + BOOL found; + + range=(APTR)unit->multicast_ranges.mlh_Head; + tail=(APTR)&unit->multicast_ranges.mlh_Tail; + found=FALSE; + + while((range!=tail)&&!found) + { + if((lower_bound_left==range->lower_bound_left)&& + (lower_bound_right==range->lower_bound_right)&& + (upper_bound_left==range->upper_bound_left)&& + (upper_bound_right==range->upper_bound_right)) + found=TRUE; + else + range=(APTR)range->node.mln_Succ; + } + + if(!found) + range=NULL; + + return range; +} + + + +/****i* 3c589.device/FindTypeStats ***************************************** +* +* NAME +* FindTypeStats -- . +* +* SYNOPSIS +* stats = FindTypeStats(unit,list, +* packet_type) +* +* struct TypeStats *FindTypeStats(struct DevUnit *,struct MinList *, +* ULONG); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +struct TypeStats *FindTypeStats(struct DevUnit *unit,struct MinList *list, + ULONG packet_type,struct DevBase *base) +{ + struct TypeStats *stats,*tail; + BOOL found; + + stats=(APTR)list->mlh_Head; + tail=(APTR)&list->mlh_Tail; + found=FALSE; + + while((stats!=tail)&&!found) + { + if(stats->packet_type==packet_type) + found=TRUE; + else + stats=(APTR)stats->node.mln_Succ; + } + + if(!found) + stats=NULL; + + return stats; +} + + + +/****i* 3c589.device/FlushUnit ********************************************* +* +* NAME +* FlushUnit -- . +* +* SYNOPSIS +* FlushUnit(unit) +* +* VOID FlushUnit(struct DevUnit *); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +VOID FlushUnit(struct DevUnit *unit,UBYTE last_queue,BYTE error, + struct DevBase *base) +{ + struct IORequest *request; + UBYTE i; + struct Opener *opener,*tail; + + /* Abort queued requests */ + + for(i=0;i<=last_queue;i++) + { + while((request=(APTR)GetMsg(unit->request_ports[i]))!=NULL) + { + request->io_Error=IOERR_ABORTED; + ReplyMsg((APTR)request); + } + } + +#if 1 + opener=(APTR)unit->openers.mlh_Head; + tail=(APTR)&unit->openers.mlh_Tail; + + /* Flush every opener's read queue */ + + while(opener!=tail) + { + while((request=(APTR)GetMsg(&opener->read_port))!=NULL) + { + request->io_Error=error; + ReplyMsg((APTR)request); + } + opener=(APTR)opener->node.mln_Succ; + } + +#else + opener=request->ios2_BufferManagement; + while((request=(APTR)GetMsg(&opener->read_port))!=NULL) + { + request->io_Error=IOERR_ABORTED; + ReplyMsg((APTR)request); + } +#endif + + /* Return */ + + return; +} + + + +/****i* 3c589.device/CardRemovedInt **************************************** +* +* NAME +* CardRemovedInt -- . +* +* SYNOPSIS +* CardRemovedInt(unit) +* +* VOID CardRemovedInt(struct DevUnit *); +* +* FUNCTION +* +* INPUTS +* unit +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static VOID CardRemovedInt(struct DevUnit *unit REG("a1")) +{ + struct DevBase *base; + + /* Record loss of card and get our task to call ReleaseCard() */ + + base=unit->device; + unit->flags&=~(UNITF_HAVEADAPTER|UNITF_HAVECARD|UNITF_ONLINE); + Signal(unit->task,unit->card_removed_signal); + + return; +} + + + +/****i* 3c589.device/CardInsertedInt *************************************** +* +* NAME +* CardInsertedInt -- . +* +* SYNOPSIS +* CardInsertedInt(unit) +* +* VOID CardInsertedInt(struct DevUnit *); +* +* FUNCTION +* +* INPUTS +* unit +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static VOID CardInsertedInt(struct DevUnit *unit REG("a1")) +{ + struct DevBase *base; + + base=unit->device; + + Signal(unit->task,unit->card_inserted_signal); + + return; +} + + + +/****i* 3c589.device/CardStatusInt ***************************************** +* +* NAME +* CardStatusInt -- . +* +* SYNOPSIS +* mask = CardStatusInt(mask,unit) +* +* UBYTE CardStatusInt(UBYTE mask,struct DevUnit *); +* +* FUNCTION +* +* INPUTS +* mask +* unit +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static UBYTE CardStatusInt(UBYTE mask REG("d0"), + struct DevUnit *unit REG("a1")) +{ + struct DevBase *base; + volatile UBYTE *io_base; + UWORD ints; + + base=unit->device; + + if(((unit->flags&UNITF_HAVEADAPTER)!=0)&&((mask&CARD_STATUSF_IRQ)!=0)) + { + io_base=unit->io_base; + ints=LEWordIn(io_base+EL3REG_STATUS); + + if((ints&EL3INTF_ANY)!=0) /* ??? */ + { + /* Handle interrupts */ + + if((ints&EL3INTF_RXCOMPLETE)!=0) + { + LEWordOut(io_base+EL3REG_COMMAND, + EL3CMD_SETINTMASK|(INT_MASK&~EL3INTF_RXCOMPLETE)); + Cause(&unit->rx_int); + } + if((ints&EL3INTF_TXAVAIL)!=0) + { + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_ACKINT| + EL3INTF_TXAVAIL); + Cause(&unit->tx_int); + } + if((ints&EL3INTF_TXCOMPLETE)!=0) + TxError(unit,base); + + /* Acknowledge interrupt request */ + + LEWordOut(io_base+EL3REG_COMMAND, + EL3CMD_ACKINT|EL3INTF_ANY); + } + + /* Work around gayle interrupt bug */ + + *((volatile UBYTE *)0xda9000)=(mask^0x2c)|0xc0; + mask=0; + } + + return mask; +} + + + +/****i* 3c589.device/RxInt ************************************************* +* +* NAME +* RxInt -- . +* +* SYNOPSIS +* RxInt(unit) +* +* VOID RxInt(struct DevUnit *); +* +* FUNCTION +* +* INPUTS +* unit - A unit of this device. +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static VOID RxInt(struct DevUnit *unit REG("a1")) +{ + volatile UBYTE *io_base; + UWORD rx_status,packet_size; + struct DevBase *base; + BOOL is_orphan,accepted; + ULONG packet_type,*p,*end; + UBYTE *buffer; + struct IOSana2Req *request,*request_tail; + struct Opener *opener,*opener_tail; + struct TypeStats *tracker; + + base=unit->device; + io_base=unit->io_base; + buffer=unit->rx_buffer; + end=(ULONG *)(buffer+HEADER_SIZE); + + while(((rx_status=LEWordIn(io_base+EL3REG_RXSTATUS)) + &EL3REG_RXSTATUSF_INCOMPLETE)==0) + { + if((rx_status&EL3REG_RXSTATUSF_ERROR)==0) + { + /* Read packet header */ + + is_orphan=TRUE; + packet_size=rx_status&EL3REG_RXSTATUS_SIZEMASK; + p=(ULONG *)buffer; + while(popeners.mlh_Head; + opener_tail=(APTR)&unit->openers.mlh_Tail; + + /* Offer packet to every opener */ + + while(opener!=opener_tail) + { + request=(APTR)opener->read_port.mp_MsgList.lh_Head; + request_tail=(APTR)&opener->read_port.mp_MsgList.lh_Tail; + accepted=FALSE; + + /* Offer packet to each request until it's accepted */ + + while((request!=request_tail)&&!accepted) + { + if(request->ios2_PacketType==packet_type + ||request->ios2_PacketType<=MTU + &&packet_type<=MTU) + { + CopyPacket(unit,request,packet_size,packet_type, + !is_orphan,base); + accepted=TRUE; + } + request= + (APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ; + } + + if(accepted) + is_orphan=FALSE; + opener=(APTR)opener->node.mln_Succ; + } + + /* If packet was unwanted, give it to S2_READORPHAN request */ + + if(is_orphan) + { + unit->stats.UnknownTypesReceived++; + if(!IsMsgPortEmpty(unit->request_ports[ADOPT_QUEUE])) + { + CopyPacket(unit, + (APTR)unit->request_ports[ADOPT_QUEUE]-> + mp_MsgList.lh_Head,packet_size,packet_type, + FALSE,base); + } + } + + /* Update remaining statistics */ + + unit->stats.PacketsReceived++; + + tracker= + FindTypeStats(unit,&unit->type_trackers,packet_type,base); + if(tracker!=NULL) + { + tracker->stats.PacketsReceived++; + tracker->stats.BytesReceived+=packet_size; + } + } + } + else + { + unit->stats.BadData++; + ReportEvents(unit,S2EVENT_ERROR|S2EVENT_HARDWARE|S2EVENT_RX,base); + } + + /* Discard packet */ + + Disable(); /* Needed? */ + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_RXDISCARD); + while((LEWordIn(io_base+EL3REG_STATUS)& + EL3REG_STATUSF_CMDINPROGRESS)!=0); + Enable(); + } + + /* Return */ + + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SETINTMASK|INT_MASK); + return; +} + + + +/****i* 3c589.device/CopyPacket ******************************************** +* +* NAME +* CopyPacket -- . +* +* SYNOPSIS +* CopyPacket(unit,request,packet_size,packet_type, +* all_read) +* +* VOID CopyPacket(struct DevUnit *,struct IOSana2Req *,UWORD,UWORD, +* BOOL); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static VOID CopyPacket(struct DevUnit *unit,struct IOSana2Req *request, + UWORD packet_size,UWORD packet_type,BOOL all_read,struct DevBase *base) +{ + volatile UBYTE *io_base; + struct Opener *opener; + UBYTE *buffer; + BOOL filtered=FALSE; + ULONG *p,*end; + + /* Set multicast and broadcast flags */ + + io_base=unit->io_base; + buffer=unit->rx_buffer; + request->ios2_Req.io_Flags&=~(SANA2IOF_BCAST|SANA2IOF_MCAST); + if((*((ULONG *)(buffer+PACKET_DEST))==0xffffffff)&& + (*((UWORD *)(buffer+PACKET_DEST+4))==0xffff)) + request->ios2_Req.io_Flags|=SANA2IOF_BCAST; + else if((buffer[PACKET_DEST]&0x1)!=0) + request->ios2_Req.io_Flags|=SANA2IOF_MCAST; + + /* Set source and destination addresses and packet type */ + + CopyMem(buffer+PACKET_SOURCE,request->ios2_SrcAddr,ADDRESS_SIZE); + CopyMem(buffer+PACKET_DEST,request->ios2_DstAddr,ADDRESS_SIZE); + request->ios2_PacketType=packet_type; + + /* Read rest of packet */ + + if(!all_read) + { + p=(ULONG *)(buffer+((PACKET_DATA+3)&~3)); + end=(ULONG *)(buffer+packet_size); + while(pios2_Req.io_Flags&SANA2IOF_RAW)==0) + { + packet_size-=PACKET_DATA; + buffer+=PACKET_DATA; + } +#ifdef USE_HACKS + else + packet_size+=4; /* Needed for Shapeshifter & Fusion */ +#endif + + request->ios2_DataLength=packet_size; + + /* Filter packet */ + + opener=request->ios2_BufferManagement; + if((request->ios2_Req.io_Command==CMD_READ)&& + (opener->filter_hook!=NULL)) + if(!CallHookPkt(opener->filter_hook,request,buffer)) + filtered=TRUE; + + if(!filtered) + { + /* Copy packet into opener's buffer and reply packet */ + + if(!opener->rx_function(request->ios2_Data,buffer,packet_size)) + { + request->ios2_Req.io_Error=S2ERR_NO_RESOURCES; + request->ios2_WireError=S2WERR_BUFF_ERROR; + ReportEvents(unit, + S2EVENT_ERROR|S2EVENT_SOFTWARE|S2EVENT_BUFF|S2EVENT_RX,base); + } + Remove((APTR)request); + ReplyMsg((APTR)request); + + } + + return; +} + + + +/****i* 3c589.device/AddressFilter ***************************************** +* +* NAME +* AddressFilter -- . +* +* SYNOPSIS +* accept = AddressFilter(unit,address) +* +* BOOL AddressFilter(struct DevUnit *,UBYTE *); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static BOOL AddressFilter(struct DevUnit *unit,UBYTE *address, + struct DevBase *base) +{ + struct AddressRange *range,*tail; + BOOL accept=TRUE; + ULONG address_left; + UWORD address_right; + + /* Check whether address is unicast/broadcast or multicast */ + + address_left=BELong(*((ULONG *)address)); + address_right=BEWord(*((UWORD *)(address+4))); + + if(((address_left&0x01000000)!=0)&& + !((address_left==0xffffffff)&&(address_right==0xffff))) + { + /* Check if this multicast address is wanted */ + + range=(APTR)unit->multicast_ranges.mlh_Head; + tail=(APTR)&unit->multicast_ranges.mlh_Tail; + accept=FALSE; + + while((range!=tail)&&!accept) + { + if(((address_left>range->lower_bound_left)|| + (address_left==range->lower_bound_left)&& + (address_right>=range->lower_bound_right))&& + ((address_leftupper_bound_left)|| + (address_left==range->upper_bound_left)&& + (address_right<=range->upper_bound_right))) + accept=TRUE; + range=(APTR)range->node.mln_Succ; + } + + if(!accept) + unit->special_stats[S2SS_ETHERNET_BADMULTICAST&0xffff]++; + } + + return accept; +} + + + +/****i* 3c589.device/TxInt ************************************************* +* +* NAME +* TxInt -- . +* +* SYNOPSIS +* TxInt(unit) +* +* VOID TxInt(struct DevUnit *); +* +* FUNCTION +* +* INPUTS +* unit - A unit of this device. +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static VOID TxInt(struct DevUnit *unit REG("a1")) +{ + volatile UBYTE *io_base; + UWORD packet_size,data_size,send_size; + struct DevBase *base; + struct IOSana2Req *request; + BOOL proceed=TRUE; + struct Opener *opener; + ULONG *buffer,*end,wire_error; + ULONG *(*dma_tx_function)(APTR REG("a0")); + BYTE error; + struct MsgPort *port; + struct TypeStats *tracker; + + base=unit->device; + io_base=unit->io_base; + + port=unit->request_ports[WRITE_QUEUE]; + + while(proceed&&(!IsMsgPortEmpty(port))) + { + error=0; + + request=(APTR)port->mp_MsgList.lh_Head; + data_size=packet_size=request->ios2_DataLength; + + if((request->ios2_Req.io_Flags&SANA2IOF_RAW)==0) + packet_size+=PACKET_DATA; + + if(LEWordIn(io_base+EL3REG_TXSPACE)>PREAMBLE_SIZE+packet_size) + { + /* Write packet preamble */ + + LELongOut(io_base+EL3REG_DATA0,packet_size); + + /* Write packet header */ + + send_size=(packet_size+3)&(~0x3); + if((request->ios2_Req.io_Flags&SANA2IOF_RAW)==0) + { + LongOut(io_base+EL3REG_DATA0,*((ULONG *)request->ios2_DstAddr)); + WordOut(io_base+EL3REG_DATA0, + *((UWORD *)(request->ios2_DstAddr+4))); + WordOut(io_base+EL3REG_DATA0,*((UWORD *)unit->address)); + LongOut(io_base+EL3REG_DATA0,*((ULONG *)(unit->address+2))); + BEWordOut(io_base+EL3REG_DATA0,request->ios2_PacketType); + send_size-=PACKET_DATA; + } + + /* Get packet data */ + + opener=(APTR)request->ios2_BufferManagement; + dma_tx_function=opener->dma_tx_function; + if(dma_tx_function!=NULL) + buffer=dma_tx_function(request->ios2_Data); + else + buffer=NULL; + + if(buffer==NULL) + { + buffer=(ULONG *)unit->tx_buffer; + if(!opener->tx_function(buffer,request->ios2_Data,data_size)) + { + error=S2ERR_NO_RESOURCES; + wire_error=S2WERR_BUFF_ERROR; + ReportEvents(unit, + S2EVENT_ERROR|S2EVENT_SOFTWARE|S2EVENT_BUFF|S2EVENT_TX, + base); + } + } + + /* Write packet data */ + + if(error==0) + { + end=buffer+(send_size>>2); + while(bufferios2_Req.io_Error=error; + request->ios2_WireError=wire_error; + Remove((APTR)request); + ReplyMsg((APTR)request); + + /* Update statistics */ + + if(error==0) + { + unit->stats.PacketsSent++; + + tracker=FindTypeStats(unit,&unit->type_trackers, + request->ios2_PacketType,base); + if(tracker!=NULL) + { + tracker->stats.PacketsSent++; + tracker->stats.BytesSent+=packet_size; + } + } + } + else + proceed=FALSE; + } + + if(proceed) + unit->request_ports[WRITE_QUEUE]->mp_Flags=PA_SOFTINT; + else + { + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_SETTXTHRESH + |(PREAMBLE_SIZE+packet_size)); + unit->request_ports[WRITE_QUEUE]->mp_Flags=PA_IGNORE; + } + + return; +} + + + +/****i* 3c589.device/TxError *********************************************** +* +* NAME +* TxError -- . +* +* SYNOPSIS +* TxError(unit) +* +* VOID TxError(struct DevUnit *); +* +* FUNCTION +* +* INPUTS +* unit - A unit of this device. +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +VOID TxError(struct DevUnit *unit,struct DevBase *base) +{ + volatile UBYTE *io_base; + UBYTE tx_status,flags=0; + + io_base=unit->io_base; + + /* Gather all errors */ + + while(((tx_status=ByteIn(io_base+EL3REG_TXSTATUS)) + &EL3REG_TXSTATUSF_COMPLETE)!=0) + { + flags|=tx_status; + ByteOut(io_base+EL3REG_TXSTATUS,0); + } + + /* Restart transmitter if necessary */ + + if((flags&EL3REG_TXSTATUSF_JABBER)!=0) + { + Disable(); + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_TXRESET); + while((LEWordIn(io_base+EL3REG_STATUS)& + EL3REG_STATUSF_CMDINPROGRESS)!=0); + Enable(); + } + + if((flags&(EL3REG_TXSTATUSF_JABBER|EL3REG_TXSTATUSF_OVERFLOW))!=0) + LEWordOut(io_base+EL3REG_COMMAND,EL3CMD_TXENABLE); + + /* Report the error(s) */ + + ReportEvents(unit,S2EVENT_ERROR|S2EVENT_HARDWARE|S2EVENT_TX,base); + + return; +} + + + +/****i* 3c589.device/ReportEvents ****************************************** +* +* NAME +* ReportEvents -- . +* +* SYNOPSIS +* ReportEvents(unit,events) +* +* VOID ReportEvents(struct DevUnit *,ULONG); +* +* FUNCTION +* +* INPUTS +* unit - A unit of this device. +* events - A mask of events to report. +* +* RESULT +* None. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static VOID ReportEvents(struct DevUnit *unit,ULONG events, + struct DevBase *base) +{ + struct IOSana2Req *request,*tail,*next_request; + struct List *list; + + list=&unit->request_ports[EVENT_QUEUE]->mp_MsgList; + next_request=(APTR)list->lh_Head; + tail=(APTR)&list->lh_Tail; + + Disable(); + while(next_request!=tail) + { + request=next_request; + next_request=(APTR)request->ios2_Req.io_Message.mn_Node.ln_Succ; + + if((request->ios2_WireError&events)!=0) + { + request->ios2_WireError=events; + Remove((APTR)request); + ReplyMsg((APTR)request); + } + } + Enable(); + + return; +} + + + +/****i* 3c589.device/UnitTask ********************************************** +* +* NAME +* UnitTask -- . +* +* SYNOPSIS +* UnitTask() +* +* VOID UnitTask(); +* +* FUNCTION +* +* INPUTS +* +* RESULT +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static VOID UnitTask() +{ + struct Task *task; + struct IORequest *request; + struct DevUnit *unit; + struct DevBase *base; + struct MsgPort *general_port; + ULONG signals,wait_signals,card_removed_signal,card_inserted_signal, + general_port_signal; + + /* Get parameters */ + + task=AbsExecBase->ThisTask; + unit=task->tc_UserData; + base=unit->device; + + /* Activate general request port */ + + general_port=unit->request_ports[GENERAL_QUEUE]; + general_port->mp_SigTask=task; + general_port->mp_SigBit=AllocSignal(-1); + general_port_signal=1<mp_SigBit; + general_port->mp_Flags=PA_SIGNAL; + + /* Allocate a signal for notification of card removal */ + + card_removed_signal=unit->card_removed_signal=1<card_inserted_signal=1<mp_SigBit)|card_removed_signal + |card_inserted_signal; + + /* Tell ourselves to check port for old messages */ + + Signal(task,general_port_signal); + + /* Infinite loop to service requests and signals */ + + while(TRUE) + { + signals=Wait(wait_signals); + + if((signals&card_inserted_signal)!=0) + { + if(InitialiseCard(unit,base)) + { + unit->flags|=UNITF_HAVECARD; + if((unit->flags&UNITF_CONFIGURED)!=0) + ConfigureAdapter(unit,base); + } + else + ReleaseCard(unit->card_handle,0); + } + + if((signals&card_removed_signal)!=0) + { + ReleaseCard(unit->card_handle,0); + GoOffline(unit,base); + } + + if((signals&general_port_signal)!=0) + { + while((request=(APTR)GetMsg(general_port))!=NULL) + { + /* Service the request as soon as the unit is free */ + + ObtainSemaphore(&unit->access_lock); + ServiceRequest((APTR)request,base); + } + } + } +} + + + +/****i* 3c589.device/ReadEEPROM ******************************************** +* +* NAME +* ReadEEPROM -- . +* +* SYNOPSIS +* value = ReadEEPROM(io_base,index) +* +* UWORD ReadEEPROM(UBYTE *,UWORD); +* +* FUNCTION +* +* INPUTS +* io_base - Base of adapter's register window. +* index - Offset within EEPROM. +* +* RESULT +* value - Contents of specified EEPROM location. +* +* EXAMPLE +* +* NOTES +* +* BUGS +* +* SEE ALSO +* +**************************************************************************** +* +*/ + +static UWORD ReadEEPROM(volatile UBYTE *io_base,UWORD index) +{ + LEWordOut(io_base+EL3REG_EEPROMCMD,EL3ECMD_READ|index); + while((LEWordIn(io_base+EL3REG_EEPROMCMD)&EL3REG_EEPROMCMDF_BUSY) + !=0); + return LEWordIn(io_base+EL3REG_EEPROMDATA); +} + + + diff --git a/Source/unit_protos.h b/Source/unit_protos.h new file mode 100644 index 0000000..d0bcbd3 --- /dev/null +++ b/Source/unit_protos.h @@ -0,0 +1,49 @@ +/* + +File: unit_protos.h +Author: Neil Cafferkey +Copyright (C) 2002 Neil Cafferkey + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, +MA 02111-1307, USA. + +*/ + +#ifndef UNIT_PROTOS_H +#define UNIT_PROTOS_H + + +#include "device.h" + +struct DevUnit *GetUnit(ULONG unit_num,struct DevBase *base); +struct DevUnit *FindUnit(ULONG unit_num,struct DevBase *base); +struct DevUnit *CreateUnit(ULONG unit_num,struct DevBase *base); +VOID DeleteUnit(struct DevUnit *unit,struct DevBase *base); +VOID ConfigureAdapter(struct DevUnit *unit,struct DevBase *base); +VOID GoOnline(struct DevUnit *unit,struct DevBase *base); +VOID GoOffline(struct DevUnit *unit,struct DevBase *base); +BOOL AddMulticastRange(struct DevUnit *unit,UBYTE *lower_bound, + UBYTE *upper_bound,struct DevBase *base); +BOOL RemMulticastRange(struct DevUnit *unit,UBYTE *lower_bound, + UBYTE *upper_bound,struct DevBase *base); +struct TypeStats *FindTypeStats(struct DevUnit *unit,struct MinList *list, + ULONG packet_type,struct DevBase *base); +VOID FlushUnit(struct DevUnit *unit,UBYTE last_queue,BYTE error, + struct DevBase *base); + + +#endif + +