## Automatically generated incremental diff ## From: linux-2.5.70-bk10 ## To: linux-2.5.70-bk11 ## Robot: $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $ diff -urN linux-2.5.70-bk10/Documentation/00-INDEX linux-2.5.70-bk11/Documentation/00-INDEX --- linux-2.5.70-bk10/Documentation/00-INDEX 2003-05-26 18:00:26.000000000 -0700 +++ linux-2.5.70-bk11/Documentation/00-INDEX 2003-06-06 04:38:19.000000000 -0700 @@ -182,6 +182,8 @@ - short guide on how to set up and use the RAM disk. riscom8.txt - notes on using the RISCom/8 multi-port serial driver. +rocket.txt + - info on installing/using the Comtrol RocketPort multiport serial driver rtc.txt - notes on how to use the Real Time Clock (aka CMOS clock) driver. s390/ diff -urN linux-2.5.70-bk10/Documentation/DocBook/Makefile linux-2.5.70-bk11/Documentation/DocBook/Makefile --- linux-2.5.70-bk10/Documentation/DocBook/Makefile 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk11/Documentation/DocBook/Makefile 2003-06-06 04:38:19.000000000 -0700 @@ -11,7 +11,8 @@ kernel-locking.sgml via-audio.sgml mousedrivers.sgml \ deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \ writing_usb_driver.sgml scsidrivers.sgml sis900.sgml \ - kernel-api.sgml journal-api.sgml lsm.sgml usb.sgml + kernel-api.sgml journal-api.sgml lsm.sgml usb.sgml \ + gadget.sgml ### # The build process is as follows (targets): diff -urN linux-2.5.70-bk10/Documentation/DocBook/gadget.tmpl linux-2.5.70-bk11/Documentation/DocBook/gadget.tmpl --- linux-2.5.70-bk10/Documentation/DocBook/gadget.tmpl 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk11/Documentation/DocBook/gadget.tmpl 2003-06-06 04:38:19.000000000 -0700 @@ -0,0 +1,966 @@ + + + + USB Gadget API for Linux + 02 June 2003 + 02 June 2003 + + + Permission is granted to copy, distribute, and/or modify + this document under the terms of the GNU Free Documentation + License, version 1.2, or any later version published by the + Free Software Foundation; with the Invariant Sections being + the "GNU Free Documentation License", + no Front-Cover Texts, + and + no Back-Cover Texts. + + + This documentation 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 Free Documentation License for more details. + + + Note that certain sections of this document are merged + into Linux kernel source code. + That content is the bulk of + and + , + where the "GNU Free Documentation License" is identified + as an alternate licence for its documentation. + + + + + 2003 + David Brownell + + + + David + Brownell + +
dbrownell@users.sourceforge.net
+
+
+
+ + + +Introduction + +This document presents a Linux-USB "Gadget" +kernel mode +API, for use within peripherals and other USB devices +that embed Linux. +It provides an overview of the API structure, +and shows how that fits into a system development project. +This is the first such API released on Linux to address +a number of important problems, including: + + + Supports USB 2.0, for high speed devices which + can stream data at several dozen megabytes per second. + + Handles devices with dozens of endpoints just as + well as ones with just two fixed-function ones. Gadget drivers + can be written so they're easy to port to new hardware. + + Flexible enough to expose more complex USB device + capabilities such as multiple configurations, multiple interfaces, + composite devices, + and alternate interface settings. + + Sharing data structures and API models with the + Linux-USB host side API. This looks forward to USB "On-The-Go" + (OTG) and similar more-symmetric frameworks. + + Minimalist, so it's easier to support new device + controller hardware. I/O processing doesn't imply large + demands for memory or CPU resources. + + + + +Most Linux developers will not be able to use this API, since they +have USB "host" hardware in a PC, workstation, or server. +Linux users with embedded systems are more likely to +have USB peripheral hardware. +To distinguish drivers running inside such hardware from the +more familiar Linux "USB device drivers", +which are host side proxies for the real USB devices, +a different term is used: +the drivers inside the peripherals are "USB gadget drivers". +In USB protocol interactions, the device driver is the master +(or "client driver") +and the gadget driver is the slave (or "function driver"). + + +The gadget API resembles the host side Linux-USB API in that both +use queues of request objects to package I/O buffers, and those requests +may be submitted or canceled. +They share common definitions for the standard USB +Chapter 9 messages, structures, and constants. +Also, both APIs bind and unbind drivers to devices. +The APIs differ in detail, since the host side's current +URB framework exposes a number of implementation details +and assumptions that are inappropriate for a gadget API. +While the model for control transfers and configuration +management is necessarily different (one side is a hardware-neutral master, +the other is a hardware-aware slave), the endpoint I/0 API used here +should also be usable for an overhead-reduced host side API. + + + + +Structure of Gadget Drivers + +A system running inside a USB peripheral +normally has at least three layers inside the kernel to handle +USB protocol processing, and may have additional layers in +user space code. +The "gadget" API is used by the middle layer to interact +with the lowest level (which directly handles hardware). + + +In Linux, from the bottom up, these layers are: + + + + + + USB Controller Driver + + + This is the lowest software level. + It is the only layer that talks to hardware, + through registers, fifos, dma, irqs, and the like. + The <linux/usb_gadget.h> API abstracts + the peripheral controller endpoint hardware. + That hardware is exposed through endpoint objects, which accept + streams of IN/OUT buffers, and through callbacks that interact + with gadget drivers. + Since normal USB devices only have one upstream + port, they only have one of these drivers. + The controller driver can support any number of different + gadget drivers, but only one of them can be used at a time. + + + Examples of such controller hardware include + the PCI-based NetChip 2280 USB 2.0 high speed controller, + the SA-11x0 or PXA-25x UDC (found within many PDAs), + and a variety of other products. + + + + + Gadget Driver + + + The lower boundary of this driver implements hardware-neutral + USB functions, using calls to the controller driver. + Because such hardware varies widely in capabilities and restrictions, + the gadget driver is normally configured at compile time + to work with endpoints supported by one particular controller. + Gadget drivers may be portable to several different controllers, + using conditional compilation. + Gadget driver responsibilities include: + + + handling setup requests (ep0 protocol responses) + possibly including class-specific functionality + + returning configuration and string descriptors + + (re)setting configurations and interface + altsettings, including enabling and configuring endpoints + + handling life cycle events, such as managing + bindings + to hardware, and disconnection from the USB host. + + managing IN and OUT transfers on all currently + enabled endpoints + + + + + Such drivers may be modules of proprietary code, although + that approach is discouraged in the Linux community. + + + + + Upper Level + + + Most gadget drivers have an upper boundary that connects + to some Linux driver or framework in Linux. + Through that boundary flows the data which the gadget driver + produces and/or consumes through protocol transfers over USB. + Examples include: + + + user mode code, using generic (gadgetfs) + or application specific files in + /dev + + networking subsystem (for network gadgets, + like the CDC Ethernet Model gadget driver) + + data capture drivers, perhaps video4Linux or + a scanner driver; or test and measurement hardware. + + input subsystem (for HID gadgets) + + sound subsystem (for audio gadgets) + + file system (for PTP gadgets) + + block i/o subsystem (for usb-storage gadgets) + + ... and more + + + + + Additional Layers + + + Other layers may exist. + These could include kernel layers, such as network protocol stacks, + as well as user mode applications building on standard POSIX + system call APIs such as + open(), close(), + read() and write(). + On newer systems, POSIX Async I/O calls may be an option. + Such user mode code will not necessarily be subject to + the GNU General Public License (GPL). + + + + + + +Over time, reusable utilities should evolve to help make some +gadget driver tasks simpler. An example of particular interest +is code implementing standard USB-IF protocols for +HID, networking, storage, or audio classes. +Some developers are interested in KDB or KGDB hooks, to let +target hardware be remotely debugged. +Most such USB protocol code doesn't need to be hardware-specific, +any more than network protocols like X11, HTTP, or NFS are. +Such interface drivers might be combined, to support composite devices. + + + + + +Kernel Mode Gadget API + +Gadget drivers declare themselves through a +struct usb_gadget_driver, which is responsible for +most parts of enumeration for a struct usb_gadget. +The response to a set_configuration usually involves +enabling one or more of the struct usb_ep objects +exposed by the gadget, and submitting one or more +struct usb_request buffers to transfer data. +Understand those four data types, and their operations, and +you will understand how this API works. + + +Incomplete Data Type Descriptions + +This documentation was prepared using the standard Linux +kernel docproc tool, which turns text +and in-code comments into SGML DocBook and then into usable +formats such as HTML or PDF. +Other than the "Chapter 9" data types, most of the significant +data types and functions are described here. + + +However, docproc does not understand all the C constructs +that are used, so some relevant information is likely omitted from +what you are reading. +One example of such information is several per-request flags. +You'll have to read the header file, and use example source +code (such as that for "Gadget Zero"), to fully understand the API. + + +The part of the API implementing some basic +driver capabilities is specific to the version of the +Linux kernel that's in use. +The 2.5 kernel includes a driver model +framework that has no analogue on earlier kernels; +so those parts of the gadget API are not fully portable. +(They are implemented on 2.4 kernels, but in a different way.) +The driver model state is another part of this API that is +ignored by the kerneldoc tools. + + + +The core API does not expose +every possible hardware feature, only the most widely available ones. +There are significant hardware features, such as device-to-device DMA +(without temporary storage in a memory buffer) +that would be added using hardware-specific APIs. + + +This API expects drivers to use conditional compilation to handle +endpoint capabilities of different hardware. +Those tend to have arbitrary restrictions, relating to +transfer types, addressing, packet sizes, buffering, and availability. +As a rule, such differences only matter for "endpoint zero" logic +that handles device configuration and management. +The API only supports limited run-time +detection of capabilities, through naming conventions for endpoints. +Although a gadget driver could scan the endpoints available to it and +choose to map those capabilities onto driver functionality in some way, +few drivers will want to reconfigure themselves at run-time. + + +Like the Linux-USB host side API, this API exposes +the "chunky" nature of USB messages: I/O requests are in terms +of one or more "packets", and packet boundaries are visible to drivers. +Compared to RS-232 serial protocols, USB resembles +synchronous protocols like HDLC +(N bytes per frame, multipoint addressing from the host) +more than asynchronous ones +(tty style, like 8 bytes, no parity, one stop bit). +So for example the controller drivers won't buffer +two single byte writes into a single two-byte USB IN packet, +although gadget drivers may do so when they implement +protocols where packet boundaries (and "short packets") +are not significant. + + +Driver Life Cycle + +Gadget drivers make endpoint I/O requests to hardware without +needing to know many details of the hardware, but driver +setup/configuration code needs to handle some differences. +Use the API like this: + + + + +Register a driver for the particular device side +usb controller hardware, +such as the net2280 on PCI (USB 2.0), +sa11x0 or pxa25x as found in Linux PDAs, +and so on. +At this point the device is logically in the USB ch9 initial state +("attached"), drawing no power and not usable +(since it does not yet support enumeration). + + +Register a gadget driver that implements some higher level +device function. That will then bind() to a usb_gadget. + + +The hardware driver can now start enumerating. +The steps it handles are to accept USB power and set_address requests. +Other steps are handled by the gadget driver. +If the gadget driver module is unloaded before the host starts to +enumerate, steps before step 7 are skipped. + + +The gadget driver's setup() call returns usb descriptors, +based both on what the bus interface hardware provides and on the +functionality being implemented. +That can involve alternate settings or configurations, +unless the hardware prevents such operation. + + +The gadget driver handles the last step of enumeration, +when the USB host issues a set_configuration call. +It enables all endpoints used in that configuration, +with all interfaces in their default settings. +That involves using a list of the hardware's endpoints, enabling each +endpoint according to its descriptor. + + +Do real work and perform data transfers, possibly involving +changes to interface settings or switching to new configurations, until the +device is disconnect()ed from the host. +Queue any number of transfer requests to each endpoint. +The drivers then go back to step 3 (above). + + +When the gadget driver module is being unloaded, +the driver unbind() callback is issued. That lets the controller +driver be unloaded. + + + + +Drivers will normally be arranged so that just loading the +gadget driver module (or statically linking it into a Linux kernel) +allows the peripheral device to be enumerated. +Note that at this lowest level there are no policies about how +ep0 configuration logic is implemented, +except that it should obey USB specifications. +Such issues are in the domain of gadget drivers, +including knowing about implementation constraints +imposed by some USB controllers +or understanding that composite devices might happen to +be built by integrating reusable components. + + + + +USB 2.0 Chapter 9 Types and Constants + +Gadget drivers +rely on common USB structures and constants +defined in the +<linux/usb_ch9.h> +header file, which is standard in Linux 2.5 kernels. +These are the same types and constants used by host +side drivers. + + +!Iinclude/linux/usb_ch9.h + + +Core Objects and Methods + +These are declared in +<linux/usb_gadget.h>, +and are used by gadget drivers to interact with +USB peripheral controller drivers. + + + + +!Iinclude/linux/usb_gadget.h + + +Optional Utilities + +The core API is sufficient for writing a USB Gadget Driver, +but some optional utilities are provided to simplify common tasks. + + +!Edrivers/usb/gadget/usbstring.c + + + + +Peripheral Controller Drivers + +The first hardware supporting this API is the NetChip 2280 +controller, which supports USB 2.0 high speed and is based on PCI. +This is the net2280 driver module. +The driver supports Linux kernel versions 2.4 and 2.5; +contact NetChip Technologies for development boards and product +information. + + + + +A partial USB simulator, +the dummy_hcd driver, is available. +It can act like a net2280, a pxa25x, or an sa11x0 in terms +of available endpoints and device speeds; and it simulates +control, bulk, and to some extent interrupt transfers. +That lets you develop some parts of a gadget driver on a normal PC, +without any special hardware, and perhaps with the assistance +of tools such as GDB running with User Mode Linux. +At least one person has expressed interest in adapting that +approach, hooking it up to a simulator for a microcontroller. +Such simulators can help debug subsystems where the runtime hardware +is unfriendly to software development, or is not yet available. + + +Support for other controllers is expected to be developed +and contributed +over time, as this driver framework evolves. + + + + +Gadget Drivers + +In addition to Gadget Zero +(used primarily for testing and development with drivers +for usb controller hardware), other gadget drivers exist. + + +There's an ethernet gadget +driver, which implements one of the most useful +Communications Device Class models. +One of the standards for cable modem interoperability even +specifies the use of this ethernet model as one of two +mandatory options. +Gadgets using this code look to a USB host as if they're +an Ethernet adapter. +It provides access to a network where the gadget's CPU is one host, +which could easily be bridging, routing, or firewalling +access to other networks. + + +There is also support for user mode gadget drivers, +using gadgetfs. +This provides a User Mode API that presents +each endpoint as a single file descriptor. I/O is done using +normal read() and read() calls. +Familiar tools like GDB and pthreads can be used to +develop and debug user mode drivers, so that once a robust +controller driver is available many applications for it +won't require new kernel mode software. + + +Support for other kinds of gadget is expected to +be developed and contributed +over time, as this driver framework evolves. + + + + + + +GNU Free Documentation License +Version 1.2, November 2002 + + + +PREAMBLE + +The purpose of this License is to make a manual, textbook, or +other functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, with +or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible for +modifications made by others. + +This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft license +designed for free software. + +We have designed this License in order to use it for manuals for +free software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; it +can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. + + +APPLICABILITY AND DEFINITIONS + +This License applies to any manual or other work, in +any medium, that contains a notice placed by the copyright holder saying +it can be distributed under the terms of this License. Such a notice +grants a world-wide, royalty-free license, unlimited in duration, to use +that work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission under +copyright law. + +A "Modified Version" of the Document means any +work containing the Document or a portion of it, either copied verbatim, +or with modifications and/or translated into another language. + +A "Secondary Section" is a named appendix or +a front-matter section of the Document that deals exclusively with the +relationship of the publishers or authors of the Document to the +Document's overall subject (or to related matters) and contains nothing +that could fall directly within that overall subject. (Thus, if the +Document is in part a textbook of mathematics, a Secondary Section may +not explain any mathematics.) The relationship could be a matter of +historical connection with the subject or with related matters, or of +legal, commercial, philosophical, ethical or political position +regarding them. + +The "Invariant Sections" are certain Secondary +Sections whose titles are designated, as being those of Invariant +Sections, in the notice that says that the Document is released under +this License. If a section does not fit the above definition of +Secondary then it is not allowed to be designated as Invariant. The +Document may contain zero Invariant Sections. If the Document does not +identify any Invariant Sections then there are none. + +The "Cover Texts" are certain short passages of +text that are listed, as Front-Cover Texts or Back-Cover Texts, in the +notice that says that the Document is released under this License. A +Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at +most 25 words. + +A "Transparent" copy of the Document means a +machine-readable copy, represented in a format whose specification is +available to the general public, that is suitable for revising the +document straightforwardly with generic text editors or (for images +composed of pixels) generic paint programs or (for drawings) some widely +available drawing editor, and that is suitable for input to text +formatters or for automatic translation to a variety of formats suitable +for input to text formatters. A copy made in an otherwise Transparent +file format whose markup, or absence of markup, has been arranged to +thwart or discourage subsequent modification by readers is not +Transparent. An image format is not Transparent if used for any +substantial amount of text. A copy that is not "Transparent" is called +"Opaque". + +Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML or +XML using a publicly available DTD, and standard-conforming simple HTML, +PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the machine-generated +HTML, PostScript or PDF produced by some word processors for output +purposes only. + +The "Title Page" means, for a printed book, +the title page itself, plus such following pages as are needed to hold, +legibly, the material this License requires to appear in the title page. +For works in formats which do not have any title page as such, "Title +Page" means the text near the most prominent appearance of the work's +title, preceding the beginning of the body of the text. + +A section "Entitled XYZ" means a named subunit +of the Document whose title either is precisely XYZ or contains XYZ in +parentheses following text that translates XYZ in another language. +(Here XYZ stands for a specific section name mentioned below, such as +"Acknowledgements", "Dedications", "Endorsements", or "History".) To +"Preserve the Title" of such a section when you modify the Document +means that it remains a section "Entitled XYZ" according to this +definition. + +The Document may include Warranty Disclaimers next to the notice +which states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this License, +but only as regards disclaiming warranties: any other implication that +these Warranty Disclaimers may have is void and has no effect on the +meaning of this License. + + +VERBATIM COPYING + +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies to +the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further copying +of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. + + +You may also lend copies, under the same conditions stated above, +and you may publicly display copies. + + +COPYING IN QUANTITY + +If you publish printed copies (or copies in media that commonly +have printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover Texts: +Front-Cover Texts on the front cover, and Back-Cover Texts on the back +cover. Both covers must also clearly and legibly identify you as the +publisher of these copies. The front cover must present the full title +with all words of the title equally prominent and visible. You may add +other material on the covers in addition. Copying with changes limited +to the covers, as long as they preserve the title of the Document and +satisfy these conditions, can be treated as verbatim copying in other +respects. + +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. + +If you publish or distribute Opaque copies of the Document +numbering more than 100, you must either include a machine-readable +Transparent copy along with each Opaque copy, or state in or with each +Opaque copy a computer-network location from which the general +network-using public has access to download using public-standard +network protocols a complete Transparent copy of the Document, free of +added material. If you use the latter option, you must take reasonably +prudent steps, when you begin distribution of Opaque copies in quantity, +to ensure that this Transparent copy will remain thus accessible at the +stated location until at least one year after the last time you +distribute an Opaque copy (directly or through your agents or retailers) +of that edition to the public. + +It is requested, but not required, that you contact the authors of +the Document well before redistributing any large number of copies, to +give them a chance to provide you with an updated version of the +Document. + + +MODIFICATIONS + +You may copy and distribute a Modified Version of the Document +under the conditions of sections 2 and 3 above, provided that you +release the Modified Version under precisely this License, with the +Modified Version filling the role of the Document, thus licensing +distribution and modification of the Modified Version to whoever +possesses a copy of it. In addition, you must do these things in the +Modified Version: + + +Use in the Title Page (and on the covers, if any) a + title distinct from that of the Document, and from those of previous + versions (which should, if there were any, be listed in the History + section of the Document). You may use the same title as a previous + version if the original publisher of that version gives permission. + +List on the Title Page, as authors, one or more + persons or entities responsible for authorship of the modifications in + the Modified Version, together with at least five of the principal + authors of the Document (all of its principal authors, if it has fewer + than five), unless they release you from this requirement. + +State on the Title page the name of the publisher of + the Modified Version, as the publisher. +Preserve all the copyright notices of the Document. + +Add an appropriate copyright notice for your + modifications adjacent to the other copyright notices. + +Include, immediately after the copyright notices, a + license notice giving the public permission to use the Modified + Version under the terms of this License, in the form shown in the + Addendum below. + +Preserve in that license notice the full lists of + Invariant Sections and required Cover Texts given in the Document's + license notice. +Include an unaltered copy of this License. + +Preserve the section Entitled "History", Preserve its + Title, and add to it an item stating at least the title, year, new + authors, and publisher of the Modified Version as given on the Title + Page. If there is no section Entitled "History" in the Document, + create one stating the title, year, authors, and publisher of the + Document as given on its Title Page, then add an item describing the + Modified Version as stated in the previous sentence. + +Preserve the network location, if any, given in the + Document for public access to a Transparent copy of the Document, and + likewise the network locations given in the Document for previous + versions it was based on. These may be placed in the "History" + section. You may omit a network location for a work that was + published at least four years before the Document itself, or if the + original publisher of the version it refers to gives permission. + +For any section Entitled "Acknowledgements" or + "Dedications", Preserve the Title of the section, and preserve in the + section all the substance and tone of each of the contributor + acknowledgements and/or dedications given therein. + +Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers or the + equivalent are not considered part of the section titles. + +Delete any section Entitled "Endorsements". + Such a section may not be included in the Modified Version. + +Do not retitle any existing section to be Entitled + "Endorsements" or to conflict in title with any Invariant Section. + +Preserve any Warranty Disclaimers. + + + +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. + +You may add a section Entitled "Endorsements", provided it +contains nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. + +You may add a passage of up to five words as a Front-Cover Text, +and a passage of up to 25 words as a Back-Cover Text, to the end of the +list of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or through +arrangements made by) any one entity. If the Document already includes +a cover text for the same cover, previously added by you or by +arrangement made by the same entity you are acting on behalf of, you may +not add another; but you may replace the old one, on explicit permission +from the previous publisher that added the old one. + +The author(s) and publisher(s) of the Document do not by this +License give permission to use their names for publicity for or to +assert or imply endorsement of any Modified Version. + + +COMBINING DOCUMENTS + +You may combine the Document with other documents released under +this License, under the terms defined in section +4 above for modified versions, provided that you include in the +combination all of the Invariant Sections of all of the original +documents, unmodified, and list them all as Invariant Sections of your +combined work in its license notice, and that you preserve all their +Warranty Disclaimers. + +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by adding +at the end of it, in parentheses, the name of the original author or +publisher of that section if known, or else a unique number. Make the +same adjustment to the section titles in the list of Invariant Sections +in the license notice of the combined work. + +In the combination, you must combine any sections Entitled +"History" in the various original documents, forming one section +Entitled "History"; likewise combine any sections Entitled +"Acknowledgements", and any sections Entitled "Dedications". You must +delete all sections Entitled "Endorsements". + + +COLLECTIONS OF DOCUMENTS + +You may make a collection consisting of the Document and other +documents released under this License, and replace the individual copies +of this License in the various documents with a single copy that is +included in the collection, provided that you follow the rules of this +License for verbatim copying of each of the documents in all other +respects. + +You may extract a single document from such a collection, and +distribute it individually under this License, provided you insert a +copy of this License into the extracted document, and follow this +License in all other respects regarding verbatim copying of that +document. + + +AGGREGATION WITH INDEPENDENT WORKS + +A compilation of the Document or its derivatives with other +separate and independent documents or works, in or on a volume of a +storage or distribution medium, is called an "aggregate" if the +copyright resulting from the compilation is not used to limit the legal +rights of the compilation's users beyond what the individual works +permit. When the Document is included an aggregate, this License does +not apply to the other works in the aggregate which are not themselves +derivative works of the Document. + +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on covers +that bracket the Document within the aggregate, or the electronic +equivalent of covers if the Document is in electronic form. Otherwise +they must appear on printed covers that bracket the whole +aggregate. + + +TRANSLATION + +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between the +translation and the original version of this License or a notice or +disclaimer, the original version will prevail. + +If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve its +Title (section 1) will typically require changing the actual +title. + + +TERMINATION + +You may not copy, modify, sublicense, or distribute the Document +except as expressly provided for under this License. Any other attempt +to copy, modify, sublicense or distribute the Document 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. + + +FUTURE REVISIONS OF THIS LICENSE + +The Free Software Foundation may publish new, revised versions of +the GNU Free Documentation 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. See +http://www.gnu.org/copyleft/. + +Each version of the License is given a distinguishing version +number. If the Document specifies that a particular numbered version of +this License "or any later version" applies to it, you have the option +of following the terms and conditions either of that specified version +or of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. + + +ADDENDUM: How to use this License for + your documents + +To use this License in a document you have written, include a copy +of the License in the document and put the following copyright and +license notices just after the title page: + + + +If you have Invariant Sections, Front-Cover Texts and Back-Cover +Texts, replace the "with...Texts." line with this: + +
+ with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. +
+ +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. + +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of free +software license, such as the GNU General Public License, to permit +their use in free software. +
+
+ +
+ diff -urN linux-2.5.70-bk10/Documentation/rocket.txt linux-2.5.70-bk11/Documentation/rocket.txt --- linux-2.5.70-bk10/Documentation/rocket.txt 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk11/Documentation/rocket.txt 2003-06-06 04:38:19.000000000 -0700 @@ -0,0 +1,87 @@ +Comtrol(tm) RocketPort(R)/RocketModem(TM) Series +Device Driver for the Linux Operating System + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +PRODUCT OVERVIEW +---------------- + +This driver provides a loadable kernel driver for the Comtrol RocketPort +and RocketModem PCI boards. These boards provide, 2, 4, 8, 16, or 32 +high-speed serial ports or modems. This driver supports up to a combination +of four RocketPort or RocketModems boards in one machine simultaneously. +This file assumes that you are using the RocketPort driver which is +integrated into the kernel sources. + +The driver can also be installed as an external module using the usual +"make;make install" routine. This external module driver, obtainable +from the Comtrol website listed below, is useful for updating the driver +or installing it into kernels which do not have the driver configured +into them. Installations instructions for the external module +are in the included README and HW_INSTALL files. + +RocketPort ISA and RocketModem II PCI boards are also supported by this +driver, but must use the external module driver for configuration reasons. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +INSTALLATION PROCEDURES +----------------------- + +RocketPort/RocketModem PCI cards require no driver configuration, they are +automatically detected and configured. + +The RocketPort driver can be installed as a module (recommended) or built +into the kernel. This is selected, as for other drivers, through the `make config` +command from the root of the Linux source tree during the kernel build process. + +The RocketPort/RocketModem serial ports installed by this driver are assigned +device major number 46, and will be named /dev/ttyRx, where x is the port number +starting at zero (ex. /dev/ttyR0, /devttyR1, ...). If you have multiple cards +installed in the system, the mapping of port names to serial ports is displayed +in the system log at /var/log/messages. + +If installed as a module, the module must be loaded. This can be done +manually by entering "modprobe rocket". To have the module loaded automatically +upon system boot, edit the /etc/modules.conf file and add the line +"alias char-major-46 rocket". + +In order to use the ports, their device names (nodes) must be created with mknod. +This is only required once, the system will retain the names once created. To +create the RocketPort/RocketModem device names, use the command +"mknod /dev/ttyRx c 46 x" where x is the port number starting at zero. For example: + +>mknod /dev/ttyR0 c 46 0 +>mknod /dev/ttyR1 c 46 1 +>mknod /dev/ttyR2 c 46 2 + +The Linux script MAKEDEV will create the first 16 ttyRx device names (nodes) for you: + +>/dev/MAKEDEV ttyR + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +REPORTING BUGS +-------------- + +For technical support, please provide the following +information: Driver version, kernel release, distribution of +kernel, and type of board you are using. Error messages and log +printouts port configuration details are especially helpful. + +USA + Phone: (612) 494-4100 + FAX: (612) 494-4199 + email: support@comtrol.com + +Comtrol Europe + Phone: +44 (0) 1 869 323-220 + FAX: +44 (0) 1 869 323-211 + email: support@comtrol.co.uk + +Web: http://www.comtrol.com +FTP: ftp.comtrol.com + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + diff -urN linux-2.5.70-bk10/MAINTAINERS linux-2.5.70-bk11/MAINTAINERS --- linux-2.5.70-bk10/MAINTAINERS 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk11/MAINTAINERS 2003-06-06 04:38:19.000000000 -0700 @@ -281,6 +281,13 @@ W: http://linux-atm.sourceforge.net S: Maintained +ATMEL WIRELESS DRIVER +P: Simon Kelley +M: simon@thekelleys.org.uk +W: http://www.thekelleys.org.uk/atmel +W: http://atmelwlandriver.sourceforge.net/ +S: Maintained + AX.25 NETWORK LAYER P: Ralf Baechle M: ralf@linux-mips.org @@ -1524,6 +1531,12 @@ W: http://www.namesys.com S: Supported +ROCKETPORT DRIVER +P: Comtrol Corp. +M: support@comtrol.com +W: http://www.comtrol.com +S: Maintained + ROSE NETWORK LAYER P: Ralf Baechle M: ralf@linux-mips.org diff -urN linux-2.5.70-bk10/Makefile linux-2.5.70-bk11/Makefile --- linux-2.5.70-bk10/Makefile 2003-06-06 04:38:11.000000000 -0700 +++ linux-2.5.70-bk11/Makefile 2003-06-06 04:38:19.000000000 -0700 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 5 SUBLEVEL = 70 -EXTRAVERSION = -bk10 +EXTRAVERSION = -bk11 # *DOCUMENTATION* # To see a list of typical targets execute "make help" diff -urN linux-2.5.70-bk10/arch/alpha/kernel/core_marvel.c linux-2.5.70-bk11/arch/alpha/kernel/core_marvel.c --- linux-2.5.70-bk10/arch/alpha/kernel/core_marvel.c 2003-05-26 18:00:22.000000000 -0700 +++ linux-2.5.70-bk11/arch/alpha/kernel/core_marvel.c 2003-06-06 04:38:19.000000000 -0700 @@ -980,7 +980,7 @@ } static int -marvel_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem) +marvel_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem) { struct marvel_agp_aperture *aper = agp->aperture.sysdata; return iommu_bind(aper->arena, aper->pg_start + pg_start, @@ -988,7 +988,7 @@ } static int -marvel_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem) +marvel_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem) { struct marvel_agp_aperture *aper = agp->aperture.sysdata; return iommu_unbind(aper->arena, aper->pg_start + pg_start, diff -urN linux-2.5.70-bk10/arch/alpha/kernel/core_titan.c linux-2.5.70-bk11/arch/alpha/kernel/core_titan.c --- linux-2.5.70-bk10/arch/alpha/kernel/core_titan.c 2003-05-26 18:00:27.000000000 -0700 +++ linux-2.5.70-bk11/arch/alpha/kernel/core_titan.c 2003-06-06 04:38:19.000000000 -0700 @@ -679,7 +679,7 @@ } static int -titan_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem) +titan_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem) { struct titan_agp_aperture *aper = agp->aperture.sysdata; return iommu_bind(aper->arena, aper->pg_start + pg_start, @@ -687,7 +687,7 @@ } static int -titan_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem) +titan_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem) { struct titan_agp_aperture *aper = agp->aperture.sysdata; return iommu_unbind(aper->arena, aper->pg_start + pg_start, diff -urN linux-2.5.70-bk10/arch/alpha/kernel/systbls.S linux-2.5.70-bk11/arch/alpha/kernel/systbls.S --- linux-2.5.70-bk10/arch/alpha/kernel/systbls.S 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk11/arch/alpha/kernel/systbls.S 2003-06-06 04:38:19.000000000 -0700 @@ -433,6 +433,15 @@ .quad sys_set_tid_address .quad sys_restart_syscall .quad sys_fadvise64 + .quad sys_timer_create + .quad sys_timer_settime /* 415 */ + .quad sys_timer_gettime + .quad sys_timer_getoverrun + .quad sys_timer_delete + .quad sys_clock_settime + .quad sys_clock_gettime /* 420 */ + .quad sys_clock_getres + .quad sys_clock_nanosleep .size sys_call_table, . - sys_call_table .type sys_call_table, @object diff -urN linux-2.5.70-bk10/arch/cris/drivers/ethernet.c linux-2.5.70-bk11/arch/cris/drivers/ethernet.c --- linux-2.5.70-bk10/arch/cris/drivers/ethernet.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk11/arch/cris/drivers/ethernet.c 2003-06-06 04:38:19.000000000 -0700 @@ -292,37 +292,19 @@ */ static int __init -etrax_ethernet_init(struct net_device *dev) +etrax_ethernet_init(void) { - int i; + struct net_device *dev; + int i, err; int anOffset = 0; printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2001 Axis Communications AB\n"); - dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ - - printk("%s initialized\n", dev->name); - - /* make Linux aware of the new hardware */ - - if (!dev) { - printk(KERN_WARNING "%s: dev == NULL. Should this happen?\n", - cardname); - dev = init_etherdev(dev, sizeof(struct net_local)); - if (!dev) - panic("init_etherdev failed\n"); - } - - /* setup generic handlers and stuff in the dev struct */ - - ether_setup(dev); - - /* make room for the local structure containing stats etc */ - - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); + + dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ /* now setup our etrax specific stuff */ @@ -340,10 +322,6 @@ dev->do_ioctl = e100_ioctl; dev->tx_timeout = e100_tx_timeout; - /* set the default MAC address */ - - e100_set_mac_address(dev, &default_mac); - /* Initialise the list of Etrax DMA-descriptors */ /* Initialise receive descriptors */ @@ -371,6 +349,16 @@ myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + err = register_netdev(dev); + if (err) { + kfree(dev); + return err; + } + + /* set the default MAC address */ + + e100_set_mac_address(dev, &default_mac); + /* Initialize speed indicator stuff. */ current_speed = 10; @@ -1349,19 +1337,10 @@ } } -static struct net_device dev_etrax_ethernet; /* only got one */ - static int etrax_init_module(void) { - struct net_device *d = &dev_etrax_ethernet; - - d->init = etrax_ethernet_init; - - if (register_netdev(d) == 0) - return 0; - else - return -ENODEV; + return etrax_ethernet_init(); } module_init(etrax_init_module); diff -urN linux-2.5.70-bk10/arch/cris/drivers/lpslave/e100lpslavenet.c linux-2.5.70-bk11/arch/cris/drivers/lpslave/e100lpslavenet.c --- linux-2.5.70-bk10/arch/cris/drivers/lpslave/e100lpslavenet.c 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk11/arch/cris/drivers/lpslave/e100lpslavenet.c 2003-06-06 04:38:19.000000000 -0700 @@ -162,37 +162,19 @@ * (detachable devices only). */ static int __init -etrax_ethernet_lpslave_init(struct net_device *dev) +etrax_ethernet_lpslave_init(void) { - int i; + struct net_device *dev; + int i, err; int anOffset = 0; printk("Etrax/100 lpslave ethernet driver v0.3, (c) 1999 Axis Communications AB\n"); - dev->base_addr = 2; - - printk("%s initialized\n", dev->name); - - /* make Linux aware of the new hardware */ - - if (!dev) { - printk(KERN_WARNING "%s: dev == NULL. Should this happen?\n", - cardname); - dev = init_etherdev(dev, sizeof(struct net_local)); - if (!dev) - panic("init_etherdev failed\n"); - } - - /* setup generic handlers and stuff in the dev struct */ - - ether_setup(dev); - - /* make room for the local structure containing stats etc */ - - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) + dev = alloc_etherdev(sizeof(struct net_lock)); + if (!dev) return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); + + dev->base_addr = 2; /* now setup our etrax specific stuff */ @@ -242,7 +224,11 @@ TxDescList[0].buf = virt_to_phys(&host_command); TxDescList[0].next = virt_to_phys(&TxDescList[1]); - return 0; + err = register_netdev(dev); + if (err) + kfree(dev); + + return err; } /* set MAC address of the interface. called from the core after a @@ -1017,19 +1003,10 @@ } #endif /* ETHDEBUG */ -static struct net_device dev_etrax_slave_ethernet; - static int etrax_init_module(void) { - struct net_device *d = &dev_etrax_slave_ethernet; - - d->init = etrax_ethernet_lpslave_init; - - if(register_netdev(d) == 0) - return 0; - else - return -ENODEV; + return etrax_ethernet_lpslave_init(); } module_init(etrax_init_module); diff -urN linux-2.5.70-bk10/arch/ia64/hp/sim/simeth.c linux-2.5.70-bk11/arch/ia64/hp/sim/simeth.c --- linux-2.5.70-bk10/arch/ia64/hp/sim/simeth.c 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk11/arch/ia64/hp/sim/simeth.c 2003-06-06 04:38:19.000000000 -0700 @@ -191,7 +191,7 @@ unsigned char mac_addr[ETH_ALEN]; struct simeth_local *local; struct net_device *dev; - int fd, i; + int fd, i, err; /* * XXX Fix me @@ -207,22 +207,12 @@ if (fd == -1) return -ENODEV; - dev = init_etherdev(NULL, sizeof(struct simeth_local)); + dev = alloc_etherdev(sizeof(struct simeth_local)); if (!dev) return -ENOMEM; memcpy(dev->dev_addr, mac_addr, sizeof(mac_addr)); - dev->irq = ia64_alloc_vector(); - - /* - * attach the interrupt in the simulator, this does enable interrupts - * until a netdev_attach() is called - */ - netdev_connect(dev->irq); - - memset(dev->priv, 0, sizeof(struct simeth_local)); - local = dev->priv; local->simfd = fd; /* keep track of underlying file descriptor */ @@ -232,8 +222,19 @@ dev->get_stats = simeth_get_stats; dev->set_multicast_list = set_multicast_list; /* no yet used */ - /* Fill in the fields of the device structure with ethernet-generic values. */ - ether_setup(dev); + err = register_netdev(dev); + if (dev) { + kfree(dev); + return err; + } + + dev->irq = ia64_alloc_vector(); + + /* + * attach the interrupt in the simulator, this does enable interrupts + * until a netdev_attach() is called + */ + netdev_connect(dev->irq); printk(KERN_INFO "%s: hosteth=%s simfd=%d, HwAddr", dev->name, simeth_device, local->simfd); @@ -242,7 +243,7 @@ } printk(", IRQ %d\n", dev->irq); - return 0; + return 0; } /* diff -urN linux-2.5.70-bk10/arch/m68k/atari/hades-pci.c linux-2.5.70-bk11/arch/m68k/atari/hades-pci.c --- linux-2.5.70-bk10/arch/m68k/atari/hades-pci.c 2003-05-26 18:00:40.000000000 -0700 +++ linux-2.5.70-bk11/arch/m68k/atari/hades-pci.c 2003-06-06 04:38:20.000000000 -0700 @@ -297,14 +297,14 @@ IRQ_TT_MFP_SCC, /* Slot 2. */ IRQ_TT_MFP_SCSIDMA /* Slot 3. */ }; - struct pci_dev *dev; + struct pci_dev *dev = NULL; unsigned char slot; /* * Go through all devices, fixing up irqs as we see fit: */ - for (dev = pci_devices; dev; dev = dev->next) + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) { diff -urN linux-2.5.70-bk10/arch/ppc/8260_io/enet.c linux-2.5.70-bk11/arch/ppc/8260_io/enet.c --- linux-2.5.70-bk10/arch/ppc/8260_io/enet.c 2003-05-26 18:00:20.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/8260_io/enet.c 2003-06-06 04:38:20.000000000 -0700 @@ -630,19 +630,15 @@ bd = (bd_t *)__res; - /* Allocate some private information. + /* Create an Ethernet device instance. */ - cep = (struct scc_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL); - if (cep == NULL) + dev = alloc_etherdev(sizeof(*cep)); + if (!dev) return -ENOMEM; - __clear_user(cep,sizeof(*cep)); + cep = dev->priv; spin_lock_init(&cep->lock); - /* Create an Ethernet device instance. - */ - dev = init_etherdev(0, 0); - /* Get pointer to SCC area in parameter RAM. */ ep = (scc_enet_t *)(&immap->im_dprambase[PROFF_ENET]); @@ -771,6 +767,7 @@ /* Allocate a page. */ mem_addr = __get_free_page(GFP_KERNEL); + /* BUG: no check for failure */ /* Initialize the BD for every fragment in the page. */ @@ -808,6 +805,7 @@ /* Install our interrupt handler. */ request_irq(SIU_INT_ENET, scc_enet_interrupt, 0, "enet", dev); + /* BUG: no check for failure */ /* Set GSMR_H to enable all normal operating modes. * Set GSMR_L to enable Ethernet to MC68160. @@ -837,7 +835,6 @@ io->iop_pdatc |= PC_EST8260_ENET_NOTFD; dev->base_addr = (unsigned long)ep; - dev->priv = cep; /* The CPM Ethernet specific entries in the device structure. */ dev->open = scc_enet_open; @@ -852,6 +849,12 @@ */ sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + err = register_netdev(dev); + if (err) { + kfree(dev); + return err; + } + printk("%s: SCC ENET Version 0.1, ", dev->name); for (i=0; i<5; i++) printk("%02x:", dev->dev_addr[i]); diff -urN linux-2.5.70-bk10/arch/ppc/8260_io/fcc_enet.c linux-2.5.70-bk11/arch/ppc/8260_io/fcc_enet.c --- linux-2.5.70-bk10/arch/ppc/8260_io/fcc_enet.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/8260_io/fcc_enet.c 2003-06-06 04:38:20.000000000 -0700 @@ -1328,7 +1328,7 @@ struct net_device *dev; struct fcc_enet_private *cep; fcc_info_t *fip; - int i, np; + int i, np, err; volatile immap_t *immap; volatile iop8260_t *io; @@ -1339,23 +1339,16 @@ fip = fcc_ports; while (np-- > 0) { - - /* Allocate some private information. + /* Create an Ethernet device instance. */ - cep = (struct fcc_enet_private *) - kmalloc(sizeof(*cep), GFP_KERNEL); - if (cep == NULL) + dev = alloc_etherdev(sizeof(*cep)); + if (!dev) return -ENOMEM; - __clear_user(cep,sizeof(*cep)); + cep = dev->priv; spin_lock_init(&cep->lock); cep->fip = fip; - /* Create an Ethernet device instance. - */ - dev = init_etherdev(0, 0); - dev->priv = cep; - init_fcc_shutdown(fip, cep, immap); init_fcc_ioports(fip, io, immap); init_fcc_param(fip, dev, immap); @@ -1376,6 +1369,12 @@ init_fcc_startup(fip, dev); + err = register_netdev(dev); + if (err) { + kfree(dev); + return err; + } + printk("%s: FCC ENET Version 0.3, ", dev->name); for (i=0; i<5; i++) printk("%02x:", dev->dev_addr[i]); diff -urN linux-2.5.70-bk10/arch/ppc/8xx_io/enet.c linux-2.5.70-bk11/arch/ppc/8xx_io/enet.c --- linux-2.5.70-bk10/arch/ppc/8xx_io/enet.c 2003-05-26 18:00:27.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/8xx_io/enet.c 2003-06-06 04:38:20.000000000 -0700 @@ -643,7 +643,7 @@ { struct net_device *dev; struct scc_enet_private *cep; - int i, j, k; + int i, j, k, err; unsigned char *eap, *ba; dma_addr_t mem_addr; bd_t *bd; @@ -659,19 +659,13 @@ bd = (bd_t *)__res; - /* Allocate some private information. - */ - cep = (struct scc_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL); - if (cep == NULL) + dev = alloc_etherdev(sizeof(*cep)); + if (!dev) return -ENOMEM; - __clear_user(cep,sizeof(*cep)); + cep = dev->priv; spin_lock_init(&cep->lock); - /* Create an Ethernet device instance. - */ - dev = init_etherdev(0, 0); - /* Get pointer to SCC area in parameter RAM. */ ep = (scc_enet_t *)(&cp->cp_dparam[PROFF_ENET]); @@ -841,6 +835,7 @@ /* Allocate a page. */ ba = (unsigned char *)consistent_alloc(GFP_KERNEL, PAGE_SIZE, &mem_addr); + /* BUG: no check for failure */ /* Initialize the BD for every fragment in the page. */ @@ -939,7 +934,6 @@ #endif dev->base_addr = (unsigned long)ep; - dev->priv = cep; #if 0 dev->name = "CPM_ENET"; #endif @@ -953,6 +947,12 @@ dev->get_stats = scc_enet_get_stats; dev->set_multicast_list = set_multicast_list; + err = register_netdev(dev); + if (err) { + kfree(dev); + return err; + } + /* And last, enable the transmit and receive processing. */ sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); diff -urN linux-2.5.70-bk10/arch/ppc/8xx_io/fec.c linux-2.5.70-bk11/arch/ppc/8xx_io/fec.c --- linux-2.5.70-bk10/arch/ppc/8xx_io/fec.c 2003-05-26 18:00:58.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/8xx_io/fec.c 2003-06-06 04:38:20.000000000 -0700 @@ -1570,7 +1570,7 @@ { struct net_device *dev; struct fec_enet_private *fep; - int i, j, k; + int i, j, k, err; unsigned char *eap, *iap, *ba; unsigned long mem_addr; volatile cbd_t *bdp; @@ -1586,17 +1586,11 @@ bd = (bd_t *)__res; - /* Allocate some private information. - */ - fep = (struct fec_enet_private *)kmalloc(sizeof(*fep), GFP_KERNEL); - if (fep == NULL) + dev = alloc_etherdev(sizeof(*fep)); + if (!dev) return -ENOMEM; - __clear_user(fep,sizeof(*fep)); - - /* Create an Ethernet device instance. - */ - dev = init_etherdev(0, 0); + fep = dev->priv; fecp = &(immap->im_cpm.cp_fec); @@ -1661,6 +1655,7 @@ /* Allocate a page. */ ba = (unsigned char *)consistent_alloc(GFP_KERNEL, PAGE_SIZE, &mem_addr); + /* BUG: no check for failure */ /* Initialize the BD for every fragment in the page. */ @@ -1715,7 +1710,6 @@ #endif dev->base_addr = (unsigned long)fecp; - dev->priv = fep; /* The FEC Ethernet specific entries in the device structure. */ dev->open = fec_enet_open; @@ -1752,6 +1746,12 @@ fecp->fec_mii_speed = 0; /* turn off MDIO */ #endif /* CONFIG_USE_MDIO */ + err = register_netdev(dev); + if (err) { + kfree(dev); + return err; + } + printk ("%s: FEC ENET Version 0.2, FEC irq %d" #ifdef PHY_INTERRUPT ", MII irq %d" diff -urN linux-2.5.70-bk10/arch/ppc/Kconfig linux-2.5.70-bk11/arch/ppc/Kconfig --- linux-2.5.70-bk10/arch/ppc/Kconfig 2003-05-26 18:01:00.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/Kconfig 2003-06-06 04:38:20.000000000 -0700 @@ -97,32 +97,6 @@ depends on POWER3 default y -config ALL_PPC - bool - depends on ALL_PPC_CH || POWER3 - default y - ---help--- - Linux currently supports several different kinds of PowerPC-based - machines: Apple Power Macintoshes and clones (such as the Motorola - Starmax series), PReP (PowerPC Reference Platform) machines (such - as the Motorola PowerStacks, Motorola cPCI/VME embedded systems, - and some IBM RS/6000 systems), CHRP (Common Hardware Reference - Platform) machines (including all of the recent IBM RS/6000 and - pSeries machines), and several embedded PowerPC systems containing - 4xx, 6xx, 7xx, 8xx, 74xx, and 82xx processors. Currently, the - default option is to build a kernel which works on the first three. - - Select CHRP/PowerMac/PReP if configuring for an IBM RS/6000 or - pSeries machine, a Power Macintosh (including iMacs, iBooks and - Powerbooks), or a PReP machine. - - Select Gemini if configuring for a Synergy Microsystems' Gemini - series Single Board Computer. More information is available at: - . - - Select APUS if configuring for a PowerUP Amiga. More information is - available at: . - config PPC_STD_MMU bool depends on 6xx || POWER3 @@ -424,12 +398,34 @@ bool depends on 8xx || 8260 default y + choice prompt "Machine Type" - depends on 6xx && !8260 - default ALL_PPC_CH + depends on (6xx || POWER3) && !8260 + default PPC_MULTIPLATFORM + ---help--- + Linux currently supports several different kinds of PowerPC-based + machines: Apple Power Macintoshes and clones (such as the Motorola + Starmax series), PReP (PowerPC Reference Platform) machines (such + as the Motorola PowerStacks, Motorola cPCI/VME embedded systems, + and some IBM RS/6000 systems), CHRP (Common Hardware Reference + Platform) machines (including all of the recent IBM RS/6000 and + pSeries machines), and several embedded PowerPC systems containing + 4xx, 6xx, 7xx, 8xx, 74xx, and 82xx processors. Currently, the + default option is to build a kernel which works on the first three. -config ALL_PPC_CH + Select CHRP/PowerMac/PReP if configuring for an IBM RS/6000 or + pSeries machine, a Power Macintosh (including iMacs, iBooks and + Powerbooks), or a PReP machine. + + Select Gemini if configuring for a Synergy Microsystems' Gemini + series Single Board Computer. More information is available at: + . + + Select APUS if configuring for a PowerUP Amiga. More information is + available at: . + +config PPC_MULTIPLATFORM bool "CHRP/PowerMac/PReP" config APUS @@ -499,6 +495,26 @@ endchoice +config PPC_CHRP + bool + depends on PPC_MULTIPLATFORM + default y + +config PPC_PMAC + bool + depends on PPC_MULTIPLATFORM + default y + +config PPC_PREP + bool + depends on PPC_MULTIPLATFORM + default y + +config PPC_OF + bool + depends on PPC_PMAC || PPC_CHRP + default y + config SANDPOINT_X3 bool "Sandpoint X3" depends on SANDPOINT @@ -721,7 +737,7 @@ config ISA bool "Support for ISA-bus hardware" - depends on ALL_PPC + depends on PREP || CHRP help Find out whether you have ISA slots on your motherboard. ISA is the name of a bus system, i.e. the way the CPU talks to the other stuff @@ -851,7 +867,7 @@ config PPC601_SYNC_FIX bool "Workarounds for PPC601 bugs" - depends on ALL_PPC && !POWER3 + depends on 6xx && !POWER3 help Some versions of the PPC601 (the first PowerPC chip) have bugs which mean that extra synchronization instructions are required near @@ -865,7 +881,7 @@ config PROC_DEVICETREE bool "Support for Open Firmware device tree in /proc" - depends on ALL_PPC && PROC_FS + depends on PPC_OF && PROC_FS help This option adds a device-tree directory under /proc which contains an image of the device tree that the kernel copies from Open @@ -873,7 +889,7 @@ config PPC_RTAS bool "Support for RTAS (RunTime Abstraction Services) in /proc" - depends on ALL_PPC && PROC_FS + depends on PPC_OF && PROC_FS ---help--- When you use this option, you will be able to use RTAS from userspace. @@ -906,7 +922,7 @@ config PREP_RESIDUAL bool "Support for PReP Residual Data" - depends on ALL_PPC + depends on PPC_PREP help Some PReP systems have residual data passed to the kernel by the firmware. This allows detection of memory size, devices present and @@ -927,7 +943,7 @@ config PPCBUG_NVRAM bool "Enable reading PPCBUG NVRAM during boot" if PPLUS || LOPEC - default y if ALL_PPC + default y if PPC_PREP config CMDLINE_BOOL bool "Default bootloader kernel arguments" @@ -1156,7 +1172,7 @@ config BOOT_LOAD_BOOL bool "Set the boot link/load address" - depends on ADVANCED_OPTIONS && !ALL_PPC + depends on ADVANCED_OPTIONS && !PPC_MULTIPLATFORM help This option allows you to set the initial load address of the zImage or zImage.initrd file. This can be useful if you are on a board @@ -1292,7 +1308,7 @@ # we want to change this to something like CONFIG_SYSCTRL_CUDA/PMU config ADB_CUDA bool "Support for CUDA based PowerMacs" - depends on ALL_PPC + depends on PPC_PMAC help This provides support for CUDA based Power Macintosh systems. This includes most OldWorld PowerMacs, the first generation iMacs, the @@ -1304,7 +1320,7 @@ config ADB_PMU bool "Support for PMU based PowerMacs" - depends on ALL_PPC + depends on PPC_PMAC help On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the PMU is an embedded microprocessor whose primary function is to @@ -1336,7 +1352,7 @@ config PM bool - depends on ALL_PPC && ADB_PMU && PMAC_PBOOK + depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK default y config PMAC_APM_EMU @@ -1357,14 +1373,14 @@ config MAC_FLOPPY bool "Support for PowerMac floppy" - depends on ALL_PPC + depends on PPC_PMAC help If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple) floppy controller, say Y here. Most commonly found in PowerMacs. config MAC_SERIAL tristate "Support for PowerMac serial ports" - depends on ALL_PPC + depends on PPC_PMAC help If you have Macintosh style serial ports (8 pin mini-DIN), say Y here. If you also have regular serial ports and enable the driver @@ -1372,11 +1388,11 @@ config SERIAL_CONSOLE bool "Support for console on serial port" - depends on ALL_PPC && MAC_SERIAL=y + depends on PPC_PMAC && MAC_SERIAL=y config ADB bool "Apple Desktop Bus (ADB) support" - depends on ALL_PPC + depends on PPC_PMAC help Apple Desktop Bus (ADB) support is for support of devices which are connected to an ADB port. ADB devices tend to have 4 pins. @@ -1610,7 +1626,7 @@ config BOOTX_TEXT bool "Support for early boot text console (BootX or OpenFirmware only)" - depends on ALL_PPC + depends PPC_OF help Say Y here to see progress messages from the boot firmware in text mode. Requires either BootX or Open Firmware. diff -urN linux-2.5.70-bk10/arch/ppc/boot/Makefile linux-2.5.70-bk11/arch/ppc/boot/Makefile --- linux-2.5.70-bk10/arch/ppc/boot/Makefile 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/boot/Makefile 2003-06-06 04:38:20.000000000 -0700 @@ -16,9 +16,10 @@ BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd bootdir-y := simple -bootdir-$(CONFIG_ALL_PPC) := openfirmware prep +bootdir-$(CONFIG_PPC_OF) := openfirmware +bootdir-$(CONFIG_PPC_PREP) += prep subdir-y := lib/ common/ images/ -subdir-$(CONFIG_ALL_PPC) += of1275/ +subdir-$(CONFIG_PPC_OF) += of1275/ # for cleaning subdir- += simple/ openfirmware/ prep/ diff -urN linux-2.5.70-bk10/arch/ppc/boot/common/Makefile linux-2.5.70-bk11/arch/ppc/boot/common/Makefile --- linux-2.5.70-bk10/arch/ppc/boot/common/Makefile 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/boot/common/Makefile 2003-06-06 04:38:20.000000000 -0700 @@ -11,7 +11,7 @@ L_TARGET := lib.a obj-y := string.o util.o misc-common.o -obj-$(CONFIG_ALL_PPC) += mpc10x_memory.o +obj-$(CONFIG_PPC_PREP) += mpc10x_memory.o obj-$(CONFIG_LOPEC) += mpc10x_memory.o obj-$(CONFIG_PAL4) += cpc700_memory.o obj-$(CONFIG_SERIAL_8250_CONSOLE) += ns16550.o diff -urN linux-2.5.70-bk10/arch/ppc/boot/common/misc-common.c linux-2.5.70-bk11/arch/ppc/boot/common/misc-common.c --- linux-2.5.70-bk10/arch/ppc/boot/common/misc-common.c 2003-05-26 18:00:40.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/boot/common/misc-common.c 2003-06-06 04:38:20.000000000 -0700 @@ -20,10 +20,10 @@ #include "zlib.h" #include "nonstdio.h" -/* If we're on a ALL_PPC, assume we have a keyboard controller - * Also note, if we're not ALL_PPC, we assume you are a serial +/* If we're on a PReP, assume we have a keyboard controller + * Also note, if we're not PReP, we assume you are a serial * console - Tom */ -#if defined(CONFIG_ALL_PPC) && defined(CONFIG_VGA_CONSOLE) +#if defined(CONFIG_PPC_PREP) && defined(CONFIG_VGA_CONSOLE) extern void cursor(int x, int y); extern void scroll(void); extern char *vidmem; diff -urN linux-2.5.70-bk10/arch/ppc/boot/common/mpc10x_memory.c linux-2.5.70-bk11/arch/ppc/boot/common/mpc10x_memory.c --- linux-2.5.70-bk10/arch/ppc/boot/common/mpc10x_memory.c 2003-05-26 18:00:28.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/boot/common/mpc10x_memory.c 2003-06-06 04:38:20.000000000 -0700 @@ -50,7 +50,7 @@ /* * Read the memory controller registers to determine the amount of memory in * the system. This assumes that the firmware has correctly set up the memory - * controller registers. On CONFIG_ALL_PPC, we know we are being called + * controller registers. On CONFIG_PPC_PREP, we know we are being called * under a PReP memory map. On all other machines, we assume we are under * a CHRP memory map. */ @@ -62,7 +62,7 @@ int i; unsigned char bank_enables; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PREP config_addr = (unsigned int *)MPC10X_MAPA_CNFG_ADDR; config_data = (unsigned int *)MPC10X_MAPA_CNFG_DATA; #else diff -urN linux-2.5.70-bk10/arch/ppc/kernel/entry.S linux-2.5.70-bk11/arch/ppc/kernel/entry.S --- linux-2.5.70-bk10/arch/ppc/kernel/entry.S 2003-06-06 04:38:11.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/kernel/entry.S 2003-06-06 04:38:20.000000000 -0700 @@ -820,7 +820,7 @@ * here so it's easy to add arch-specific sections later. * -- Cort */ -#if defined(CONFIG_ALL_PPC) +#ifdef CONFIG_PPC_OF /* * On CHRP, the Run-Time Abstraction Services (RTAS) have to be * called with the MMU off. @@ -865,4 +865,4 @@ twi 31,0,0 /* XXX load up BATs and panic */ -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_OF */ diff -urN linux-2.5.70-bk10/arch/ppc/kernel/head.S linux-2.5.70-bk11/arch/ppc/kernel/head.S --- linux-2.5.70-bk10/arch/ppc/kernel/head.S 2003-05-26 18:00:40.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/kernel/head.S 2003-06-06 04:38:20.000000000 -0700 @@ -363,21 +363,21 @@ mtspr SPRG0,r10 mtspr SPRG1,r11 mfcr r10 -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_CHRP mfspr r11,SPRG2 cmpwi 0,r11,0 bne 7f -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_CHRP */ EXCEPTION_PROLOG_1 7: EXCEPTION_PROLOG_2 addi r3,r1,STACK_FRAME_OVERHEAD -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_CHRP mfspr r4,SPRG2 cmpwi cr1,r4,0 bne cr1,1f #endif EXC_XFER_STD(0x200, MachineCheckException) -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_CHRP 1: b machine_check_in_rtas #endif diff -urN linux-2.5.70-bk10/arch/ppc/kernel/pci.c linux-2.5.70-bk11/arch/ppc/kernel/pci.c --- linux-2.5.70-bk10/arch/ppc/kernel/pci.c 2003-06-06 04:38:11.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/kernel/pci.c 2003-06-06 04:38:20.000000000 -0700 @@ -45,8 +45,10 @@ static int reparent_resources(struct resource *parent, struct resource *res); static void fixup_rev1_53c810(struct pci_dev* dev); static void fixup_cpc710_pci64(struct pci_dev* dev); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC static void pcibios_fixup_cardbus(struct pci_dev* dev); +#endif +#ifdef CONFIG_PPC_OF static u8* pci_to_OF_bus_map; #endif @@ -65,10 +67,10 @@ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64}, { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources }, -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_ANY_ID, pcibios_fixup_cardbus }, -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ { 0 } }; @@ -153,7 +155,7 @@ ppc_md.pcibios_fixup_resources(dev); } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC static void pcibios_fixup_cardbus(struct pci_dev* dev) { @@ -188,7 +190,7 @@ pci_write_config_byte(dev, 0x92, val & ~0x06); } } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, @@ -676,7 +678,7 @@ return hose; } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF /* * Functions below are used on OpenFirmware machines. */ @@ -1026,7 +1028,9 @@ prom_add_property(find_path_device("/"), of_prop); } } +#endif /* CONFIG_PPC_OF */ +#ifdef CONFIG_PPC_PMAC /* * This set of routines checks for PCI<->PCI bridges that have closed * IO resources and have child devices. It tries to re-open an IO @@ -1235,7 +1239,7 @@ } } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ static int __init pcibios_init(void) @@ -1277,9 +1281,9 @@ pcibios_allocate_bus_resources(&pci_root_buses); pcibios_allocate_resources(0); pcibios_allocate_resources(1); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC pcibios_fixup_p2p_bridges(); -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ pcibios_assign_resources(); /* Call machine dependent post-init code */ diff -urN linux-2.5.70-bk10/arch/ppc/kernel/ppc_ksyms.c linux-2.5.70-bk11/arch/ppc/kernel/ppc_ksyms.c --- linux-2.5.70-bk10/arch/ppc/kernel/ppc_ksyms.c 2003-05-26 18:00:57.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/kernel/ppc_ksyms.c 2003-06-06 04:38:20.000000000 -0700 @@ -94,7 +94,7 @@ EXPORT_SYMBOL(ISA_DMA_THRESHOLD); EXPORT_SYMBOL_NOVERS(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); -#if defined(CONFIG_ALL_PPC) +#if defined(CONFIG_PPC_PREP) EXPORT_SYMBOL(_prep_type); EXPORT_SYMBOL(ucSystemType); #endif @@ -238,9 +238,14 @@ EXPORT_SYMBOL(set_backlight_enable); EXPORT_SYMBOL(register_backlight_controller); #endif /* CONFIG_PMAC_BACKLIGHT */ -#if defined(CONFIG_ALL_PPC) +#ifdef CONFIG_PPC_MULTIPLATFORM EXPORT_SYMBOL(_machine); +#endif +#ifdef CONFIG_PPC_PMAC EXPORT_SYMBOL_NOVERS(sys_ctrler); +EXPORT_SYMBOL(pmac_newworld); +#endif +#ifdef CONFIG_PPC_OF EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -254,12 +259,11 @@ EXPORT_SYMBOL(pci_busdev_to_OF_node); EXPORT_SYMBOL(pci_device_to_OF_node); EXPORT_SYMBOL(pci_device_from_OF_node); -EXPORT_SYMBOL(pmac_newworld); -#endif /* defined(CONFIG_ALL_PPC) */ +#endif /* CONFIG_PPC_OF */ #if defined(CONFIG_BOOTX_TEXT) EXPORT_SYMBOL(btext_update_display); #endif -#if defined(CONFIG_SCSI) && defined(CONFIG_ALL_PPC) +#if defined(CONFIG_SCSI) && defined(CONFIG_PPC_PMAC) EXPORT_SYMBOL(note_scsi_host); #endif #ifdef CONFIG_VT @@ -337,7 +341,7 @@ EXPORT_SYMBOL(cpm_install_handler); EXPORT_SYMBOL(cpm_free_handler); #endif /* CONFIG_8xx */ -#if defined(CONFIG_8xx) || defined(CONFIG_4xx) +#if defined(CONFIG_8xx) || defined(CONFIG_40x) EXPORT_SYMBOL(__res); #endif #if defined(CONFIG_8xx) @@ -354,7 +358,7 @@ EXPORT_SYMBOL(intercept_table); #endif EXPORT_SYMBOL(cur_cpu_spec); -#if defined(CONFIG_ALL_PPC) +#ifdef CONFIG_PPC_PMAC extern unsigned long agp_special_page; EXPORT_SYMBOL_NOVERS(agp_special_page); -#endif /* defined(CONFIG_ALL_PPC) */ +#endif diff -urN linux-2.5.70-bk10/arch/ppc/kernel/setup.c linux-2.5.70-bk11/arch/ppc/kernel/setup.c --- linux-2.5.70-bk10/arch/ppc/kernel/setup.c 2003-05-26 18:00:58.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/kernel/setup.c 2003-06-06 04:38:20.000000000 -0700 @@ -68,7 +68,7 @@ unsigned long ISA_DMA_THRESHOLD; unsigned long DMA_MODE_READ, DMA_MODE_WRITE; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_MULTIPLATFORM int _machine = 0; extern void prep_init(unsigned long r3, unsigned long r4, @@ -77,7 +77,7 @@ unsigned long r5, unsigned long r6, unsigned long r7); extern void chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ #ifdef CONFIG_MAGIC_SYSRQ unsigned long SYSRQ_KEY = 0x54; @@ -286,7 +286,7 @@ identify_cpu(offset, 0); do_cpu_ftr_fixups(offset); -#if defined(CONFIG_ALL_PPC) +#if defined(CONFIG_PPC_MULTIPLATFORM) reloc_got2(offset); /* If we came here from BootX, clear the screen, @@ -308,7 +308,7 @@ return phys; } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF /* * Assume here that all clock rates are the same in a * smp system. -- Cort @@ -351,9 +351,11 @@ } } } +#endif +#ifdef CONFIG_PPC_MULTIPLATFORM /* - * The ALL_PPC version of platform_init... + * The PPC_MULTIPLATFORM version of platform_init... */ void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, @@ -459,7 +461,7 @@ break; } } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ struct bi_record *find_bootinfo(void) { @@ -501,11 +503,11 @@ initrd_end = data[0] + data[1] + KERNELBASE; break; #endif /* CONFIG_BLK_DEV_INITRD */ -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_MULTIPLATFORM case BI_MACHTYPE: _machine = data[0]; break; -#endif /* CONFIG_ALL_PPC */ +#endif case BI_MEMSIZE: boot_mem_size = data[0]; break; @@ -596,13 +598,13 @@ /* so udelay does something sensible, assume <= 1000 bogomips */ loops_per_jiffy = 500000000 / HZ; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_MULTIPLATFORM /* This could be called "early setup arch", it must be done * now because xmon need it */ if (_machine == _MACH_Pmac) pmac_feature_init(); /* New cool way */ -#endif /* CONFIG_ALL_PPC */ +#endif #ifdef CONFIG_XMON xmon_map_scc(); diff -urN linux-2.5.70-bk10/arch/ppc/kernel/traps.c linux-2.5.70-bk11/arch/ppc/kernel/traps.c --- linux-2.5.70-bk10/arch/ppc/kernel/traps.c 2003-06-06 04:38:11.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/kernel/traps.c 2003-06-06 04:38:20.000000000 -0700 @@ -117,7 +117,7 @@ */ static inline int check_io_access(struct pt_regs *regs) { -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC unsigned long msr = regs->msr; const struct exception_table_entry *entry; unsigned int *nip = (unsigned int *)regs->nip; @@ -150,7 +150,7 @@ return 1; } } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ return 0; } diff -urN linux-2.5.70-bk10/arch/ppc/mm/init.c linux-2.5.70-bk11/arch/ppc/mm/init.c --- linux-2.5.70-bk10/arch/ppc/mm/init.c 2003-05-26 18:00:25.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/mm/init.c 2003-06-06 04:38:20.000000000 -0700 @@ -64,7 +64,7 @@ int mem_init_done; int init_bootmem_done; int boot_mapsize; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC unsigned long agp_special_page; #endif @@ -411,16 +411,18 @@ } #endif /* CONFIG_BLK_DEV_INITRD */ -#if defined(CONFIG_ALL_PPC) +#ifdef CONFIG_PPC_OF /* mark the RTAS pages as reserved */ if ( rtas_data ) for (addr = (ulong)__va(rtas_data); addr < PAGE_ALIGN((ulong)__va(rtas_data)+rtas_size) ; addr += PAGE_SIZE) SetPageReserved(virt_to_page(addr)); +#endif +#ifdef CONFIG_PPC_PMAC if (agp_special_page) SetPageReserved(virt_to_page(agp_special_page)); -#endif /* defined(CONFIG_ALL_PPC) */ +#endif if ( sysmap ) for (addr = (unsigned long)sysmap; addr < PAGE_ALIGN((unsigned long)sysmap+sysmap_size) ; @@ -465,10 +467,10 @@ if (sysmap) printk("System.map loaded at 0x%08x for debugger, size: %ld bytes\n", (unsigned int)sysmap, sysmap_size); -#if defined(CONFIG_ALL_PPC) +#ifdef CONFIG_PPC_PMAC if (agp_special_page) printk(KERN_INFO "AGP special page: 0x%08lx\n", agp_special_page); -#endif /* defined(CONFIG_ALL_PPC) */ +#endif /* Make sure all our pagetable pages have page->mapping and page->index set correctly. */ @@ -521,13 +523,15 @@ initrd_end - initrd_start, 1); } #endif /* CONFIG_BLK_DEV_INITRD */ -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF /* remove the RTAS pages from the available memory */ if (rtas_data) mem_pieces_remove(&phys_avail, rtas_data, rtas_size, 1); +#endif /* remove the sysmap pages from the available memory */ if (sysmap) mem_pieces_remove(&phys_avail, __pa(sysmap), sysmap_size, 1); +#ifdef CONFIG_PPC_PMAC /* Because of some uninorth weirdness, we need a page of * memory as high as possible (it must be outside of the * bus address seen as the AGP aperture). It will be used @@ -542,7 +546,7 @@ mem_pieces_remove(&phys_avail, agp_special_page, PAGE_SIZE, 0); agp_special_page = (unsigned long)__va(agp_special_page); } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ } /* Mark some memory as reserved by removing it from phys_avail. */ diff -urN linux-2.5.70-bk10/arch/ppc/mm/mem_pieces.c linux-2.5.70-bk11/arch/ppc/mm/mem_pieces.c --- linux-2.5.70-bk10/arch/ppc/mm/mem_pieces.c 2003-05-26 18:00:21.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/mm/mem_pieces.c 2003-06-06 04:38:20.000000000 -0700 @@ -120,7 +120,7 @@ printk("\n"); } -#if defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_APUS) || defined(CONFIG_PPC_OF) /* * Add some memory to an array of pieces */ @@ -135,7 +135,7 @@ rp->address = start; rp->size = size; } -#endif /* CONFIG_APUS || CONFIG_ALL_PPC */ +#endif /* CONFIG_APUS || CONFIG_PPC_OF */ void __init mem_pieces_sort(struct mem_pieces *mp) diff -urN linux-2.5.70-bk10/arch/ppc/platforms/Makefile linux-2.5.70-bk11/arch/ppc/platforms/Makefile --- linux-2.5.70-bk10/arch/ppc/platforms/Makefile 2003-05-26 18:01:03.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/platforms/Makefile 2003-06-06 04:38:20.000000000 -0700 @@ -16,17 +16,15 @@ ifeq ($(CONFIG_APUS),y) obj-$(CONFIG_PCI) += apus_pci.o endif -obj-$(CONFIG_ALL_PPC) += pmac_pic.o pmac_setup.o pmac_time.o \ - pmac_feature.o pmac_pci.o chrp_setup.o\ - chrp_time.o chrp_pci.o prep_pci.o \ - prep_time.o prep_setup.o pmac_sleep.o -ifeq ($(CONFIG_ALL_PPC),y) +obj-$(CONFIG_PPC_PMAC) += pmac_pic.o pmac_setup.o pmac_time.o \ + pmac_feature.o pmac_pci.o pmac_sleep.o +obj-$(CONFIG_PPC_CHRP) += chrp_setup.o chrp_time.o chrp_pci.o +obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_time.o prep_setup.o +ifeq ($(CONFIG_PPC_PMAC),y) obj-$(CONFIG_NVRAM) += pmac_nvram.o -endif -obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o -ifeq ($(CONFIG_ALL_PPC),y) obj-$(CONFIG_CPU_FREQ_PMAC) += pmac_cpufreq.o endif +obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o obj-$(CONFIG_PPC_RTAS) += error_log.o proc_rtas.o obj-$(CONFIG_PREP_RESIDUAL) += residual.o obj-$(CONFIG_ADIR) += adir_setup.o adir_pic.o adir_pci.o @@ -50,5 +48,6 @@ obj-$(CONFIG_ZX4500) += zx4500_setup.o zx4500_pci.o ifeq ($(CONFIG_SMP),y) -obj-$(CONFIG_ALL_PPC) += pmac_smp.o chrp_smp.o +obj-$(CONFIG_PPC_PMAC) += pmac_smp.o +obj-$(CONFIG_PPC_CHRP) += chrp_smp.o endif diff -urN linux-2.5.70-bk10/arch/ppc/syslib/Makefile linux-2.5.70-bk11/arch/ppc/syslib/Makefile --- linux-2.5.70-bk10/arch/ppc/syslib/Makefile 2003-05-26 18:00:22.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/syslib/Makefile 2003-06-06 04:38:20.000000000 -0700 @@ -27,8 +27,10 @@ ifeq ($(CONFIG_8xx),y) obj-$(CONFIG_PCI) += qspan_pci.o i8259.o endif -obj-$(CONFIG_ALL_PPC) += prom_init.o prom.o open_pic.o \ - indirect_pci.o i8259.o +obj-$(CONFIG_PPC_OF) += prom_init.o prom.o +obj-$(CONFIG_PPC_PMAC) += open_pic.o indirect_pci.o +obj-$(CONFIG_PPC_CHRP) += open_pic.o indirect_pci.o i8259.o +obj-$(CONFIG_PPC_PREP) += open_pic.o indirect_pci.o i8259.o obj-$(CONFIG_ADIR) += i8259.o indirect_pci.o pci_auto.o \ todc_time.o obj-$(CONFIG_EV64260) += gt64260_common.o gt64260_pic.o \ diff -urN linux-2.5.70-bk10/arch/ppc/xmon/start.c linux-2.5.70-bk11/arch/ppc/xmon/start.c --- linux-2.5.70-bk10/arch/ppc/xmon/start.c 2003-05-26 18:00:20.000000000 -0700 +++ linux-2.5.70-bk11/arch/ppc/xmon/start.c 2003-06-06 04:38:20.000000000 -0700 @@ -52,7 +52,7 @@ extern int adb_init(void); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_CHRP /* * This looks in the "ranges" property for the primary PCI host bridge * to find the physical address of the start of PCI/ISA I/O space. @@ -90,7 +90,7 @@ } return base; } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_CHRP */ #ifdef CONFIG_MAGIC_SYSRQ static void sysrq_handle_xmon(int key, struct pt_regs *regs, @@ -110,7 +110,7 @@ void xmon_map_scc(void) { -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_MULTIPLATFORM volatile unsigned char *base; if (_machine == _MACH_Pmac) { diff -urN linux-2.5.70-bk10/arch/sparc/prom/console.c linux-2.5.70-bk11/arch/sparc/prom/console.c --- linux-2.5.70-bk10/arch/sparc/prom/console.c 2003-05-26 18:00:37.000000000 -0700 +++ linux-2.5.70-bk11/arch/sparc/prom/console.c 2003-06-06 04:38:20.000000000 -0700 @@ -105,7 +105,7 @@ /* Query for input device type */ enum prom_input_device -prom_query_input_device() +prom_query_input_device(void) { unsigned long flags; int st_p; @@ -155,7 +155,7 @@ /* Query for output device type */ enum prom_output_device -prom_query_output_device() +prom_query_output_device(void) { unsigned long flags; int st_p; diff -urN linux-2.5.70-bk10/arch/sparc64/boot/Makefile linux-2.5.70-bk11/arch/sparc64/boot/Makefile --- linux-2.5.70-bk10/arch/sparc64/boot/Makefile 2003-05-26 18:00:20.000000000 -0700 +++ linux-2.5.70-bk11/arch/sparc64/boot/Makefile 2003-06-06 04:38:20.000000000 -0700 @@ -15,7 +15,7 @@ quiet_cmd_piggy = PIGGY $@ cmd_piggy = $(obj)/piggyback $@ System.map $(ROOT_IMG) quiet_cmd_strip = STRIP $@ - cmd_strip = $(STRIP) -R .comment -R .note vmlinux -o $@ + cmd_strip = $(STRIP) -R .comment -R .note -K sun4u_init -K _end -K _start vmlinux -o $@ # Actual linking diff -urN linux-2.5.70-bk10/arch/sparc64/prom/console.c linux-2.5.70-bk11/arch/sparc64/prom/console.c --- linux-2.5.70-bk10/arch/sparc64/prom/console.c 2003-05-26 18:00:58.000000000 -0700 +++ linux-2.5.70-bk11/arch/sparc64/prom/console.c 2003-06-06 04:38:20.000000000 -0700 @@ -76,7 +76,7 @@ /* Query for input device type */ enum prom_input_device -prom_query_input_device() +prom_query_input_device(void) { int st_p; char propb[64]; @@ -111,7 +111,7 @@ /* Query for output device type */ enum prom_output_device -prom_query_output_device() +prom_query_output_device(void) { int st_p; char propb[64]; diff -urN linux-2.5.70-bk10/arch/um/sys-ppc/Makefile linux-2.5.70-bk11/arch/um/sys-ppc/Makefile --- linux-2.5.70-bk10/arch/um/sys-ppc/Makefile 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk11/arch/um/sys-ppc/Makefile 2003-06-06 04:38:20.000000000 -0700 @@ -6,7 +6,7 @@ OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \ ptrace_user.o sysrq.o -EXTRA_AFLAGS := -DCONFIG_ALL_PPC -I. -I$(TOPDIR)/arch/ppc/kernel +EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(TOPDIR)/arch/ppc/kernel all: $(OBJ) diff -urN linux-2.5.70-bk10/drivers/Makefile linux-2.5.70-bk11/drivers/Makefile --- linux-2.5.70-bk10/drivers/Makefile 2003-06-06 04:38:11.000000000 -0700 +++ linux-2.5.70-bk11/drivers/Makefile 2003-06-06 04:38:20.000000000 -0700 @@ -31,7 +31,7 @@ obj-$(CONFIG_DIO) += dio/ obj-$(CONFIG_SBUS) += sbus/ obj-$(CONFIG_ZORRO) += zorro/ -obj-$(CONFIG_ALL_PPC) += macintosh/ +obj-$(CONFIG_PPC_PMAC) += macintosh/ obj-$(CONFIG_MAC) += macintosh/ obj-$(CONFIG_SGI) += sgi/ obj-$(CONFIG_PARIDE) += block/paride/ diff -urN linux-2.5.70-bk10/drivers/base/class.c linux-2.5.70-bk11/drivers/base/class.c --- linux-2.5.70-bk10/drivers/base/class.c 2003-06-06 04:38:12.000000000 -0700 +++ linux-2.5.70-bk11/drivers/base/class.c 2003-06-06 04:38:20.000000000 -0700 @@ -191,7 +191,7 @@ pr_debug("device class '%s': release.\n",cd->class_id); if (cls->release) - cd->release(cd); + cls->release(cd); } static struct kobj_type ktype_class_device = { diff -urN linux-2.5.70-bk10/drivers/base/core.c linux-2.5.70-bk11/drivers/base/core.c --- linux-2.5.70-bk10/drivers/base/core.c 2003-06-06 04:38:12.000000000 -0700 +++ linux-2.5.70-bk11/drivers/base/core.c 2003-06-06 04:38:20.000000000 -0700 @@ -343,11 +343,40 @@ put_device(dev); } +/** + * device_for_each_child - device child iterator. + * @dev: parent struct device. + * @data: data for the callback. + * @fn: function to be called for each device. + * + * Iterate over @dev's child devices, and call @fn for each, + * passing it @data. + * + * We check the return of @fn each time. If it returns anything + * other than 0, we break out and return that value. + */ +int device_for_each_child(struct device * dev, void * data, + int (*fn)(struct device *, void *)) +{ + struct device * child; + int error = 0; + + down_read(&devices_subsys.rwsem); + list_for_each_entry(child,&dev->children,node) { + if((error = fn(child,data))) + break; + } + up_read(&devices_subsys.rwsem); + return error; +} + int __init devices_init(void) { return subsystem_register(&devices_subsys); } +EXPORT_SYMBOL(device_for_each_child); + EXPORT_SYMBOL(device_initialize); EXPORT_SYMBOL(device_add); EXPORT_SYMBOL(device_register); diff -urN linux-2.5.70-bk10/drivers/block/cciss.c linux-2.5.70-bk11/drivers/block/cciss.c --- linux-2.5.70-bk10/drivers/block/cciss.c 2003-05-26 18:00:59.000000000 -0700 +++ linux-2.5.70-bk11/drivers/block/cciss.c 2003-06-06 04:38:20.000000000 -0700 @@ -1961,7 +1961,7 @@ goto queue; startio: - __blk_stop_queue(q); + blk_stop_queue(q); start_io(h); } @@ -2021,8 +2021,8 @@ /* * See if we can queue up some more IO */ - spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); blk_start_queue(&h->queue); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); return IRQ_HANDLED; } /* diff -urN linux-2.5.70-bk10/drivers/block/ll_rw_blk.c linux-2.5.70-bk11/drivers/block/ll_rw_blk.c --- linux-2.5.70-bk10/drivers/block/ll_rw_blk.c 2003-06-06 04:38:12.000000000 -0700 +++ linux-2.5.70-bk11/drivers/block/ll_rw_blk.c 2003-06-06 04:38:20.000000000 -0700 @@ -391,12 +391,6 @@ q->dma_alignment = mask; } -void blk_queue_assign_lock(request_queue_t *q, spinlock_t *lock) -{ - spin_lock_init(lock); - q->queue_lock = lock; -} - /** * blk_queue_find_tag - find a request by its tag and queue * @@ -1076,30 +1070,12 @@ * blk_start_queue() will clear the stop flag on the queue, and call * the request_fn for the queue if it was in a stopped state when * entered. Also see blk_stop_queue(). Must not be called from driver - * request function due to recursion issues. + * request function due to recursion issues. Queue lock must be held. **/ void blk_start_queue(request_queue_t *q) { - if (test_and_clear_bit(QUEUE_FLAG_STOPPED, &q->queue_flags)) { - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - if (!elv_queue_empty(q)) - q->request_fn(q); - spin_unlock_irqrestore(q->queue_lock, flags); - } -} - -/** - * __blk_stop_queue: see blk_stop_queue() - * - * Description: - * Like blk_stop_queue(), but queue_lock must be held - **/ -void __blk_stop_queue(request_queue_t *q) -{ - blk_remove_plug(q); - set_bit(QUEUE_FLAG_STOPPED, &q->queue_flags); + if (test_and_clear_bit(QUEUE_FLAG_STOPPED, &q->queue_flags)) + schedule_work(&q->unplug_work); } /** @@ -1114,15 +1090,12 @@ * or if it simply chooses not to queue more I/O at one point, it can * call this function to prevent the request_fn from being called until * the driver has signalled it's ready to go again. This happens by calling - * blk_start_queue() to restart queue operations. + * blk_start_queue() to restart queue operations. Queue lock must be held. **/ void blk_stop_queue(request_queue_t *q) { - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - __blk_stop_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); + blk_remove_plug(q); + set_bit(QUEUE_FLAG_STOPPED, &q->queue_flags); } /** @@ -2364,7 +2337,6 @@ EXPORT_SYMBOL(blk_nohighio); EXPORT_SYMBOL(blk_dump_rq_flags); EXPORT_SYMBOL(submit_bio); -EXPORT_SYMBOL(blk_queue_assign_lock); EXPORT_SYMBOL(blk_phys_contig_segment); EXPORT_SYMBOL(blk_hw_contig_segment); EXPORT_SYMBOL(blk_get_request); @@ -2383,7 +2355,6 @@ EXPORT_SYMBOL(blk_start_queue); EXPORT_SYMBOL(blk_stop_queue); -EXPORT_SYMBOL(__blk_stop_queue); EXPORT_SYMBOL(blk_run_queue); EXPORT_SYMBOL(blk_run_queues); diff -urN linux-2.5.70-bk10/drivers/char/Kconfig linux-2.5.70-bk11/drivers/char/Kconfig --- linux-2.5.70-bk10/drivers/char/Kconfig 2003-05-26 18:00:21.000000000 -0700 +++ linux-2.5.70-bk11/drivers/char/Kconfig 2003-06-06 04:38:20.000000000 -0700 @@ -94,18 +94,21 @@ two modules called ip2 and ip2main. config ROCKETPORT - tristate "Comtrol Rocketport support" + tristate "Comtrol RocketPort support" depends on SERIAL_NONSTANDARD help - This is a driver for the Comtrol Rocketport cards which provide - multiple serial ports. You would need something like this to connect - more than two modems to your Linux box, for instance in order to - become a dial-in server. + This driver supports Comtrol RocketPort and RocketModem PCI boards. + These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or + modems. For information about the RocketPort/RocketModem boards + and this driver read . If you want to compile this driver as a module, say M here and read . The module will be called rocket. + If you want to compile this driver into the kernel, say Y here. If + you don't have a Comtrol RocketPort/RocketModem card installed, say N. + config CYCLADES tristate "Cyclades async mux support" depends on SERIAL_NONSTANDARD diff -urN linux-2.5.70-bk10/drivers/char/agp/Kconfig linux-2.5.70-bk11/drivers/char/agp/Kconfig --- linux-2.5.70-bk10/drivers/char/agp/Kconfig 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk11/drivers/char/agp/Kconfig 2003-06-06 04:38:20.000000000 -0700 @@ -134,7 +134,7 @@ config AGP_UNINORTH tristate "Apple UniNorth AGP support" - depends on AGP && ALL_PPC + depends on AGP && PPC_PMAC help This option gives you AGP support for Apple machines with a UniNorth bridge. diff -urN linux-2.5.70-bk10/drivers/char/rocket.c linux-2.5.70-bk11/drivers/char/rocket.c --- linux-2.5.70-bk10/drivers/char/rocket.c 2003-06-06 04:38:12.000000000 -0700 +++ linux-2.5.70-bk11/drivers/char/rocket.c 2003-06-06 04:38:21.000000000 -0700 @@ -1,9 +1,9 @@ /* - * Rocketport device driver for Linux + * RocketPort device driver for Linux * - * Written by Theodore Ts'o, 1995, 1996, 1997. + * Written by Theodore Ts'o, 1995, 1996, 1997, 1998, 1999, 2000. * - * Copyright (C) 1995, 1996, 1997 by Comtrol, Inc. + * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2003 by Comtrol, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -21,60 +21,46 @@ */ /* - * Minor number schema: + * Kernel Synchronization: * - * +-------------------------------+ - * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | - * +---+-------+-------+-----------+ - * | C | Board | AIOP | Port # | - * +---+-------+-------+-----------+ + * This driver has 2 kernel control paths - exception handlers (calls into the driver + * from user mode) and the timer bottom half (tasklet). This is a polled driver, interrupts + * are not used. * - * C=0 implements normal POSIX tty. - * C=1 is reserved for the callout device. + * Critical data: + * - rp_table[], accessed through passed "info" pointers, is a global (static) array of + * serial port state information and the xmit_buf circular buffer. Protected by + * a per port spinlock. + * - xmit_flags[], an array of ints indexed by line (port) number, indicating that there + * is data to be transmitted. Protected by atomic bit operations. + * - rp_num_ports, int indicating number of open ports, protected by atomic operations. * - * Normally, the user won't have to worry about the AIOP; as far as - * the user is concerned, the lower 5 bits of the minor number address - * the ports on a particular board (from 0 up to 32). + * rp_write() and rp_write_char() functions use a per port semaphore to protect against + * simultaneous access to the same port by more than one process. */ -/* Kernel includes */ - +/****** Defines ******/ #include #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rocket_int.h" -#ifdef LOCAL_ROCKET_H -#include "rocket.h" -#include "version.h" +#ifdef PCI_NUM_RESOURCES +#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start) #else -#include -#define ROCKET_VERSION "1.14c" -#define ROCKET_DATE "24-Aug-98" -#endif /* LOCAL_ROCKET_H */ +#define PCI_BASE_ADDRESS(dev, r) ((dev)->base_address[r]) +#endif + +#ifndef VERSION_CODE +# define VERSION_CODE(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) ) +#endif + +#if LINUX_VERSION_CODE < VERSION_CODE(2,2,9) /* No version < 2.2 */ +# error "This kernel is too old: not supported by this file" +#endif #define ROCKET_PARANOIA_CHECK -#define ROCKET_SOFT_FLOW +#define ROCKET_DISABLE_SIMUSAGE +#undef ROCKET_SOFT_FLOW #undef ROCKET_DEBUG_OPEN #undef ROCKET_DEBUG_INTR #undef ROCKET_DEBUG_WRITE @@ -83,7 +69,11 @@ #undef ROCKET_DEBUG_WAIT_UNTIL_SENT #undef ROCKET_DEBUG_RECEIVE #undef ROCKET_DEBUG_HANGUP - +#undef REV_PCI_ORDER +#undef ROCKET_DEBUG_IO + +#undef CONFIG_DEVFS_FS + /* CAUTION!!!!! The TIME_STAT Function relies on the Pentium 64 bit * register. For various reasons related to 1.2.13, the test for this @@ -96,46 +86,132 @@ * CPU, there is probably something funny about your CPU. */ -#undef TIME_STAT /* For performing timing statistics on driver. */ +#undef TIME_STAT /* For performing timing statistics on driver. */ /* Produces printks, one every TIME_COUNTER loops, eats */ /* some of your CPU time. Good for testing or */ /* other checking, otherwise, leave it undefed */ /* Doug Ledford */ -#define TIME_STAT_CPU 100 /* This needs to be set to your processor speed */ - /* For example, 100Mhz CPU, set this to 100 */ -#define TIME_COUNTER 180000 /* This is how many iterations to run before */ +#define TIME_STAT_CPU 100 /* This needs to be set to your processor speed */ + /* For example, 100Mhz CPU, set this to 100 */ +#define TIME_COUNTER 180000 /* This is how many iterations to run before */ /* performing the printk statements. */ /* 6000 = 1 minute, 360000 = 1 hour, etc. */ /* Since time_stat is long long, this */ /* Can be really high if you want :) */ -#undef TIME_STAT_VERBOSE /* Undef this if you want a terse log message. */ +#undef TIME_STAT_VERBOSE /* Undef this if you want a terse log message. */ -#define _INLINE_ inline +#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0) +#define TTY_DRIVER_NO_DEVFS 0 +#endif -static struct r_port *rp_table[MAX_RP_PORTS]; -static struct tty_struct *rocket_table[MAX_RP_PORTS]; -static unsigned int xmit_flags[NUM_BOARDS]; +#define POLL_PERIOD HZ/100 /* Polling period .01 seconds (10ms) */ + +/****** Kernel includes ******/ + +#ifdef MODVERSIONS +#if LINUX_VERSION_CODE < VERSION_CODE(2,5,00) +#include +#else +#include +#endif +#endif + +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0) +#include +#else +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/****** RocketPort includes ******/ + +#include "rocket_int.h" +#include "rocket.h" + +#ifdef LOCAL_ROCKET_H +#include "version.h" +#else +#define ROCKET_VERSION "2.08" +#define ROCKET_DATE "02-June-2003" +#endif /* LOCAL_ROCKET_H */ + +/* + * All of the compatibilty code so we can compile serial.c against + * older kernels is hidden in rocket_compat.h + */ +#if defined(LOCAL_ROCKET_H) || (LINUX_VERSION_CODE < VERSION_CODE(2,3,23)) +#include "rocket_compat.h" +#endif + +/****** RocketPort Local Variables ******/ + +static struct tty_struct *rocket_table[MAX_RP_PORTS]; /* TTY required variables */ static struct termios *rocket_termios[MAX_RP_PORTS]; static struct termios *rocket_termios_locked[MAX_RP_PORTS]; -static void rp_wait_until_sent(struct tty_struct *tty, int timeout); -static void rp_flush_buffer(struct tty_struct *tty); - static struct tty_driver rocket_driver; static int rocket_refcount; -static int rp_num_ports_open; +static struct rocket_version driver_version = { + ROCKET_VERSION, ROCKET_DATE +}; +static struct r_port *rp_table[MAX_RP_PORTS]; /* The main repository of serial port state information. */ +static unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */ + /* eg. Bit 0 indicates port 0 has xmit data, ... */ +static atomic_t rp_num_ports_open; /* Number of serial ports open */ static struct timer_list rocket_timer; -unsigned long board1; -unsigned long board2; -unsigned long board3; -unsigned long board4; -unsigned long controller; -unsigned long support_low_speed; -int rp_baud_base = 460800; +static unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */ +static unsigned long board2; +static unsigned long board3; +static unsigned long board4; +static unsigned long controller; +static unsigned long support_low_speed; +static unsigned long modem1; +static unsigned long modem2; +static unsigned long modem3; +static unsigned long modem4; +static unsigned long pc104_1[8]; +static unsigned long pc104_2[8]; +static unsigned long pc104_3[8]; +static unsigned long pc104_4[8]; +static unsigned long *pc104[4] = { pc104_1, pc104_2, pc104_3, pc104_4 }; + +static int rp_baud_base[NUM_BOARDS]; /* Board config info (Someday make a per-board structure) */ static unsigned long rcktpt_io_addr[NUM_BOARDS]; +static int rcktpt_type[NUM_BOARDS]; +static int is_PCI[NUM_BOARDS]; +static rocketModel_t rocketModel[NUM_BOARDS]; static int max_board; + #ifdef TIME_STAT static unsigned long long time_stat; static unsigned long time_stat_short; @@ -143,83 +219,140 @@ static unsigned long time_counter; #endif +/* + * The following arrays define the interrupt bits corresponding to each AIOP. + * These bits are different between the ISA and regular PCI boards and the + * Universal PCI boards. + */ + +static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = { + AIOP_INTR_BIT_0, + AIOP_INTR_BIT_1, + AIOP_INTR_BIT_2, + AIOP_INTR_BIT_3 +}; + +static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = { + UPCI_AIOP_INTR_BIT_0, + UPCI_AIOP_INTR_BIT_1, + UPCI_AIOP_INTR_BIT_2, + UPCI_AIOP_INTR_BIT_3 +}; + +/* + * Line number is the ttySIx number (x), the Minor number. We + * assign them sequentially, starting at zero. The following + * array keeps track of the line number assigned to a given board/aiop/channel. + */ +static unsigned char lineNumbers[MAX_RP_PORTS]; +static unsigned long nextLineNumber; + +/***** RocketPort Static Prototypes *********/ +static int __init init_ISA(int i, int *reserved_controller); +static void rp_wait_until_sent(struct tty_struct *tty, int timeout); +static void rp_flush_buffer(struct tty_struct *tty); +static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model); +static unsigned char GetLineNumber(int ctrl, int aiop, int ch); +static unsigned char SetLineNumber(int ctrl, int aiop, int ch); +static void rp_start(struct tty_struct *tty); + +#ifdef MODULE MODULE_AUTHOR("Theodore Ts'o"); -MODULE_DESCRIPTION("Comtrol Rocketport driver"); -MODULE_LICENSE("GPL"); -MODULE_PARM(board1, "i"); +MODULE_DESCRIPTION("Comtrol RocketPort driver"); +MODULE_PARM(board1, "i"); MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1"); -MODULE_PARM(board2, "i"); +MODULE_PARM(board2, "i"); MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2"); -MODULE_PARM(board3, "i"); +MODULE_PARM(board3, "i"); MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3"); -MODULE_PARM(board4, "i"); +MODULE_PARM(board4, "i"); MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4"); MODULE_PARM(controller, "i"); MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller"); MODULE_PARM(support_low_speed, "i"); -MODULE_PARM_DESC(support_low_speed, "0 means support 50 baud, 1 means support 460400 baud"); +MODULE_PARM_DESC(support_low_speed, "1 means support 50 baud, 0 means support 460400 baud"); +MODULE_PARM(modem1, "i"); +MODULE_PARM_DESC(modem1, "1 means (ISA) board #1 is a RocketModem"); +MODULE_PARM(modem2, "i"); +MODULE_PARM_DESC(modem2, "1 means (ISA) board #2 is a RocketModem"); +MODULE_PARM(modem3, "i"); +MODULE_PARM_DESC(modem3, "1 means (ISA) board #3 is a RocketModem"); +MODULE_PARM(modem4, "i"); +MODULE_PARM_DESC(modem4, "1 means (ISA) board #4 is a RocketModem"); +MODULE_PARM(pc104_1, "1-8i"); +MODULE_PARM_DESC(pc104_1, "set interface types for ISA(PC104) board #1 (e.g. pc104_1=232,232,485,485,..."); +MODULE_PARM(pc104_2, "1-8i"); +MODULE_PARM_DESC(pc104_2, "set interface types for ISA(PC104) board #2 (e.g. pc104_2=232,232,485,485,..."); +MODULE_PARM(pc104_3, "1-8i"); +MODULE_PARM_DESC(pc104_3, "set interface types for ISA(PC104) board #3 (e.g. pc104_3=232,232,485,485,..."); +MODULE_PARM(pc104_4, "1-8i"); +MODULE_PARM_DESC(pc104_4, "set interface types for ISA(PC104) board #4 (e.g. pc104_4=232,232,485,485,..."); + +int rp_init(void); +static void rp_cleanup_module(void); + +module_init(rp_init); +module_exit(rp_cleanup_module); -#include +#endif -/* - * tmp_buf is used as a temporary buffer by rp_write. We need to - * lock it in case the memcpy_fromfs blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static unsigned char *tmp_buf = 0; -static DECLARE_MUTEX(tmp_buf_sem); +#ifdef MODULE_LICENSE +MODULE_LICENSE("Dual BSD/GPL"); +#endif -static void rp_start(struct tty_struct *tty); +/*************************************************************************/ +/* Module code starts here */ static inline int rocket_paranoia_check(struct r_port *info, - char *name, const char *routine) + const char *routine) { #ifdef ROCKET_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for rocketport struct %s in %s\n"; if (!info) return 1; if (info->magic != RPORT_MAGIC) { - printk(badmagic, name, routine); + printk(KERN_INFO "Warning: bad magic number for rocketport struct in %s\n", + routine); return 1; } #endif return 0; } -/* - * Here begins the interrupt/polling routine for the Rocketport! + +/* Serial port receive data function. Called (from timer poll) when an AIOPIC signals + * that receive data is present on a serial port. Pulls data from FIFO, moves it into the + * tty layer. */ -static _INLINE_ void rp_do_receive(struct r_port *info, struct tty_struct *tty, - CHANNEL_t *cp, unsigned int ChanStatus) +static void rp_do_receive(struct r_port *info, + struct tty_struct *tty, + CHANNEL_t * cp, unsigned int ChanStatus) { unsigned int CharNStat; int ToRecv, wRecv, space, count; - unsigned char *cbuf; - char *fbuf; - - ToRecv= sGetRxCnt(cp); - space = 2*TTY_FLIPBUF_SIZE; + unsigned char *cbuf; + char *fbuf; + + ToRecv = sGetRxCnt(cp); + space = tty->ldisc.receive_room(tty); + if (space > 2 * TTY_FLIPBUF_SIZE) + space = 2 * TTY_FLIPBUF_SIZE; cbuf = tty->flip.char_buf; fbuf = tty->flip.flag_buf; count = 0; #ifdef ROCKET_DEBUG_INTR - printk("rp_do_receive(%d, %d)...", ToRecv, space); + printk(KERN_INFO "rp_do_receive(%d, %d)...", ToRecv, space); #endif - if (ToRecv == 0 || (space <= 0)) - return; - + /* * determine how many we can actually read in. If we can't * read any in then we have a software overrun condition. */ if (ToRecv > space) ToRecv = space; - + + if (ToRecv <= 0) + return; + /* * if status indicates there are errored characters in the * FIFO, then enter status mode (a word in FIFO holds @@ -228,7 +361,7 @@ if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) { if (!(ChanStatus & STATMODE)) { #ifdef ROCKET_DEBUG_RECEIVE - printk("Entering STATMODE..."); + printk(KERN_INFO "Entering STATMODE..."); #endif ChanStatus |= STATMODE; sEnRxStatusMode(cp); @@ -242,16 +375,14 @@ */ if (ChanStatus & STATMODE) { #ifdef ROCKET_DEBUG_RECEIVE - printk("Ignore %x, read %x...", info->ignore_status_mask, + printk(KERN_INFO "Ignore %x, read %x...", info->ignore_status_mask, info->read_status_mask); #endif while (ToRecv) { - CharNStat= sInW(sGetTxRxDataIO(cp)); - + CharNStat = sInW(sGetTxRxDataIO(cp)); #ifdef ROCKET_DEBUG_RECEIVE - printk("%x...", CharNStat); + printk(KERN_INFO "%x...", CharNStat); #endif - if (CharNStat & STMBREAKH) CharNStat &= ~(STMFRAMEH | STMPARITYH); if (CharNStat & info->ignore_status_mask) { @@ -259,18 +390,14 @@ continue; } CharNStat &= info->read_status_mask; - if (CharNStat & STMBREAKH) { + if (CharNStat & STMBREAKH) *fbuf++ = TTY_BREAK; -#if 0 - if (info->flags & ROCKET_SAK) - do_SAK(tty); -#endif - } else if (CharNStat & STMPARITYH) + else if (CharNStat & STMPARITYH) *fbuf++ = TTY_PARITY; else if (CharNStat & STMFRAMEH) *fbuf++ = TTY_FRAME; else if (CharNStat & STMRCVROVRH) - *fbuf++ =TTY_OVERRUN; + *fbuf++ = TTY_OVERRUN; else *fbuf++ = 0; *cbuf++ = CharNStat & 0xff; @@ -284,7 +411,7 @@ */ if (sGetRxCnt(cp) == 0) { #ifdef ROCKET_DEBUG_RECEIVE - printk("Status mode off.\n"); + printk(KERN_INFO "Status mode off.\n"); #endif sDisRxStatusMode(cp); } @@ -294,86 +421,93 @@ * characters at time by doing repeated word IO * transfer. */ - wRecv= ToRecv >> 1; + wRecv = ToRecv >> 1; if (wRecv) - sInStrW(sGetTxRxDataIO(cp), cbuf, - wRecv); + sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv); if (ToRecv & 1) - cbuf[ToRecv-1] = sInB(sGetTxRxDataIO(cp)); + cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp)); memset(fbuf, 0, ToRecv); cbuf += ToRecv; fbuf += ToRecv; count += ToRecv; } - tty->ldisc.receive_buf(tty, tty->flip.char_buf, - tty->flip.flag_buf, count); + /* Push the data up to the tty layer */ + tty->ldisc.receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, count); } /* - * This routine is called when a transmit interrupt is found. It's - * responsible for pushing data found in the transmit buffer out to - * the serial card. + * Serial port transmit data function. Called from the timer polling loop as a + * result of a bit set in xmit_flags[], indicating data (from the tty layer) is ready + * to be sent out the serial port. Data is buffered in rp_table[line].xmit_buf, it is + * moved to the port's xmit FIFO. *info is critical data, protected by spinlocks. */ -static _INLINE_ void rp_do_transmit(struct r_port *info) +static void rp_do_transmit(struct r_port *info) { - int c; + int c; CHANNEL_t *cp = &info->channel; struct tty_struct *tty; - + unsigned long flags; + #ifdef ROCKET_DEBUG_INTR - printk("rp_do_transmit "); + printk(KERN_INFO "rp_do_transmit "); #endif if (!info) return; if (!info->tty) { - printk("rp: WARNING rp_do_transmit called with info->tty==NULL\n"); - xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); + printk(KERN_INFO "rp: WARNING rp_do_transmit called with info->tty==NULL\n"); + clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); return; } + + spin_lock_irqsave(&info->slock, flags); tty = info->tty; info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); + + /* Loop sending data to FIFO until done or FIFO full */ while (1) { if (tty->stopped || tty->hw_stopped) break; - c = MIN(info->xmit_fifo_room, - MIN(info->xmit_cnt, - XMIT_BUF_SIZE - info->xmit_tail)); + c = MIN(info->xmit_fifo_room, MIN(info->xmit_cnt, XMIT_BUF_SIZE - info->xmit_tail)); if (c <= 0 || info->xmit_fifo_room <= 0) break; - sOutStrW(sGetTxRxDataIO(cp), - info->xmit_buf + info->xmit_tail, c/2); + sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2); if (c & 1) - sOutB(sGetTxRxDataIO(cp), - info->xmit_buf[info->xmit_tail + c - - 1]); + sOutB(sGetTxRxDataIO(cp), info->xmit_buf[info->xmit_tail + c - 1]); info->xmit_tail += c; - info->xmit_tail &= XMIT_BUF_SIZE-1; + info->xmit_tail &= XMIT_BUF_SIZE - 1; info->xmit_cnt -= c; info->xmit_fifo_room -= c; #ifdef ROCKET_DEBUG_INTR - printk("tx %d chars...", c); + printk(KERN_INFO "tx %d chars...", c); #endif } + if (info->xmit_cnt == 0) - xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); + clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); + if (info->xmit_cnt < WAKEUP_CHARS) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); wake_up_interruptible(&tty->write_wait); +#ifdef ROCKETPORT_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif } + + spin_unlock_irqrestore(&info->slock, flags); + #ifdef ROCKET_DEBUG_INTR - printk("(%d,%d,%d,%d)...", info->xmit_cnt, info->xmit_head, + printk(KERN_INFO "(%d,%d,%d,%d)...", info->xmit_cnt, info->xmit_head, info->xmit_tail, info->xmit_fifo_room); #endif } /* - * This function is called for each port which has signalled an - * interrupt. It checks what interrupts are pending and services - * them. + * Called when a serial port signals it has read data in it's RX FIFO. + * It checks what interrupts are pending and services them, including + * receiving serial data. */ -static _INLINE_ void rp_handle_port(struct r_port *info) +static void rp_handle_port(struct r_port *info) { CHANNEL_t *cp; struct tty_struct *tty; @@ -381,12 +515,13 @@ if (!info) return; - if ( (info->flags & ROCKET_INITIALIZED) == 0 ) { - printk("rp: WARNING: rp_handle_port called with info->flags & NOT_INIT\n"); + + if ((info->flags & ROCKET_INITIALIZED) == 0) { + printk(KERN_INFO "rp: WARNING: rp_handle_port called with info->flags & NOT_INIT\n"); return; } if (!info->tty) { - printk("rp: WARNING: rp_handle_port called with info->tty==NULL\n"); + printk(KERN_INFO "rp: WARNING: rp_handle_port called with info->tty==NULL\n"); return; } cp = &info->channel; @@ -394,25 +529,20 @@ IntMask = sGetChanIntID(cp) & info->intmask; #ifdef ROCKET_DEBUG_INTR - printk("rp_interrupt %02x...", IntMask); + printk(KERN_INFO "rp_interrupt %02x...", IntMask); #endif - ChanStatus= sGetChanStatus(cp); + ChanStatus = sGetChanStatus(cp); if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */ rp_do_receive(info, tty, cp, ChanStatus); } -#if 0 - if (IntMask & SRC_INT) { /* Special receive condition */ - } -#endif if (IntMask & DELTA_CD) { /* CD change */ -#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || \ - defined(ROCKET_DEBUG_HANGUP)) - printk("ttyR%d CD now %s...", info->line, +#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP)) + printk(KERN_INFO "ttyR%d CD now %s...", info->line, (ChanStatus & CD_ACT) ? "on" : "off"); #endif if (!(ChanStatus & CD_ACT) && info->cd_status) { #ifdef ROCKET_DEBUG_HANGUP - printk("CD drop, calling hangup.\n"); + printk(KERN_INFO "CD drop, calling hangup.\n"); #endif tty_hangup(tty); } @@ -421,125 +551,166 @@ } #ifdef ROCKET_DEBUG_INTR if (IntMask & DELTA_CTS) { /* CTS change */ - printk("CTS change...\n"); + printk(KERN_INFO "CTS change...\n"); } if (IntMask & DELTA_DSR) { /* DSR change */ - printk("DSR change...\n"); + printk(KERN_INFO "DSR change...\n"); } #endif } /* - * The top level polling routine. + * The top level polling routine. Repeats every 1/100 HZ (10ms). */ static void rp_do_poll(unsigned long dummy) { CONTROLLER_t *ctlp; - int ctrl, aiop, ch, line; + int ctrl, aiop, ch, line, i; unsigned int xmitmask; - unsigned char CtlMask, AiopMask; + unsigned int CtlMask; + unsigned char AiopMask; + Word_t bit; #ifdef TIME_STAT - unsigned long loop_time; - unsigned long long time_stat_tmp=0, time_stat_tmp2=0; + unsigned long low = 0, high = 0, loop_time; + unsigned long long time_stat_tmp = 0, time_stat_tmp2 = 0; - rdtscll(time_stat_tmp); -#endif /* TIME_STAT */ + __asm__(".byte 0x0f,0x31":"=a"(low), "=d"(high)); + time_stat_tmp = high; + time_stat_tmp <<= 32; + time_stat_tmp += low; +#endif /* TIME_STAT */ - for (ctrl=0; ctrl < max_board; ctrl++) { + /* Walk through all the boards (ctrl's) */ + for (ctrl = 0; ctrl < max_board; ctrl++) { if (rcktpt_io_addr[ctrl] <= 0) continue; - ctlp= sCtlNumToCtlPtr(ctrl); + /* Get a ptr to the board's control struct */ + ctlp = sCtlNumToCtlPtr(ctrl); + + /* Get the interupt status from the board */ #ifdef CONFIG_PCI - if(ctlp->BusType == isPCI) - CtlMask= sPCIGetControllerIntStatus(ctlp); + if (ctlp->BusType == isPCI) + CtlMask = sPCIGetControllerIntStatus(ctlp); else #endif - CtlMask= sGetControllerIntStatus(ctlp); - for (aiop=0; CtlMask; CtlMask >>= 1, aiop++) { - if (CtlMask & 1) { - AiopMask= sGetAiopIntStatus(ctlp, aiop); - for (ch=0; AiopMask; AiopMask >>= 1, ch++) { + CtlMask = sGetControllerIntStatus(ctlp); + + /* Check if any AIOP read bits are set */ + for (aiop = 0; CtlMask; aiop++) { + bit = ctlp->AiopIntrBits[aiop]; + if (CtlMask & bit) { + CtlMask &= ~bit; + AiopMask = sGetAiopIntStatus(ctlp, aiop); + + /* Check if any port read bits are set */ + for (ch = 0; AiopMask; AiopMask >>= 1, ch++) { if (AiopMask & 1) { - line = (ctrl << 5) | - (aiop << 3) | ch; + + /* Get the line number (/dev/ttyRx number). */ + /* Read the data from the port. */ + line = GetLineNumber(ctrl, aiop, ch); rp_handle_port(rp_table[line]); } } } } + xmitmask = xmit_flags[ctrl]; - for (line = ctrl << 5; xmitmask; xmitmask >>= 1, line++) { - if (xmitmask & 1) - rp_do_transmit(rp_table[line]); + + /* + * xmit_flags contains bit-significant flags, indicating there is data + * to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port + * 1, ... (32 total possible). The variable i has the aiop and ch + * numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc). + */ + if (xmitmask) { + for (i = 0; i < rocketModel[ctrl].numPorts; i++) { + if (xmitmask & (1 << i)) { + aiop = (i & 0x18) >> 3; + ch = i & 0x07; + line = GetLineNumber(ctrl, aiop, ch); + rp_do_transmit(rp_table[line]); + } + } } } /* - * Reset the timer so we get called at the next clock tick. + * Reset the timer so we get called at the next clock tick (10ms). */ - if (rp_num_ports_open) { - mod_timer(&rocket_timer, jiffies + 1); - } + if (atomic_read(&rp_num_ports_open)) + mod_timer(&rocket_timer, jiffies + POLL_PERIOD); + #ifdef TIME_STAT - rdtscll(time_stat_tmp2); + __asm__(".byte 0x0f,0x31":"=a"(low), "=d"(high)); + time_stat_tmp2 = high; + time_stat_tmp2 <<= 32; + time_stat_tmp2 += low; time_stat_tmp2 -= time_stat_tmp; time_stat += time_stat_tmp2; - if (time_counter == 0) + if (time_counter == 0) time_stat_short = time_stat_long = time_stat_tmp2; else { - if ( time_stat_tmp2 < time_stat_short ) + if (time_stat_tmp2 < time_stat_short) time_stat_short = time_stat_tmp2; - else if ( time_stat_tmp2 > time_stat_long ) + else if (time_stat_tmp2 > time_stat_long) time_stat_long = time_stat_tmp2; } - if ( ++time_counter == TIME_COUNTER ) { - loop_time = (unsigned long) ( ((unsigned long)(time_stat >> 32) * ( (unsigned long)(0xffffffff)/(TIME_STAT_CPU * TIME_COUNTER) ) ) + ((unsigned long)time_stat/(TIME_STAT_CPU*TIME_COUNTER))); + if (++time_counter == TIME_COUNTER) { + loop_time = + (unsigned + long) (((unsigned long) (time_stat >> 32) * + ((unsigned long) (0xffffffff) / + (TIME_STAT_CPU * TIME_COUNTER))) + + ((unsigned long) time_stat / + (TIME_STAT_CPU * TIME_COUNTER))); #ifdef TIME_STAT_VERBOSE - printk("rp_do_poll: Interrupt Timings\n"); - printk(" %5ld iterations; %ld us min,\n", - (long)TIME_COUNTER, (time_stat_short/TIME_STAT_CPU)); - printk(" %5ld us max, %ld us average per iteration.\n", - (time_stat_long/TIME_STAT_CPU), loop_time); - printk("We want to use < 5,000 us for an iteration.\n"); -#else /* TIME_STAT_VERBOSE */ - printk("rp: %ld loops: %ld min, %ld max, %ld us/loop.\n", - (long)TIME_COUNTER, (time_stat_short/TIME_STAT_CPU), - (time_stat_long/TIME_STAT_CPU), loop_time); -#endif /* TIME_STAT_VERBOSE */ + printk(KERN_INFO "rp_do_poll: Interrupt Timings\n"); + printk(KERN_INFO " %5ld iterations; %ld us min,\n", + (long) TIME_COUNTER, + (time_stat_short / TIME_STAT_CPU)); + printk(KERN_INFO " %5ld us max, %ld us average per iteration.\n", + (time_stat_long / TIME_STAT_CPU), loop_time); + printk(KERN_INFO "We want to use < 5,000 us for an iteration.\n"); +#else /* TIME_STAT_VERBOSE */ + printk(KERN_INFO "rp: %ld loops: %ld min, %ld max, %ld us/loop.\n", + (long) TIME_COUNTER, + (time_stat_short / TIME_STAT_CPU), + (time_stat_long / TIME_STAT_CPU), loop_time); +#endif /* TIME_STAT_VERBOSE */ time_counter = time_stat = 0; time_stat_short = time_stat_long = 0; } -#endif /* TIME_STAT */ +#endif /* TIME_STAT */ } -/* - * Here ends the interrupt/polling routine. - */ - /* - * This function initializes the r_port structure, as well as enabling - * the port on the RocketPort board. + * Initializes the r_port structure for a port, as well as enabling the port on + * the board. + * Inputs: board, aiop, chan numbers */ -static void init_r_port(int board, int aiop, int chan) +static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) { + unsigned rocketMode; struct r_port *info; int line; CONTROLLER_T *ctlp; - CHANNEL_t *cp; - - line = (board << 5) | (aiop << 3) | chan; - ctlp= sCtlNumToCtlPtr(board); + /* Get the next available line number */ + line = SetLineNumber(board, aiop, chan); - info = kmalloc(sizeof(struct r_port), GFP_KERNEL); + ctlp = sCtlNumToCtlPtr(board); + + /* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */ + info = kmalloc(sizeof (struct r_port), GFP_KERNEL); if (!info) { - printk("Couldn't allocate info struct for line #%d\n", line); + printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line); return; } - memset(info, 0, sizeof(struct r_port)); - + memset(info, 0, sizeof (struct r_port)); + info->magic = RPORT_MAGIC; info->line = line; info->ctlp = ctlp; @@ -551,31 +722,73 @@ info->normal_termios = rocket_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); + info->flags &= ~ROCKET_MODE_MASK; + switch (pc104[board][line]) { + case 422: + info->flags |= ROCKET_MODE_RS422; + break; + case 485: + info->flags |= ROCKET_MODE_RS485; + break; + case 232: + default: + info->flags |= ROCKET_MODE_RS232; + break; + } - info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | - DELTA_CTS | DELTA_DSR; + info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR; if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) { - printk("Rocketport sInitChan(%d, %d, %d) failed!\n", - board, aiop, chan); + printk(KERN_INFO "RocketPort sInitChan(%d, %d, %d) failed!\n", board, aiop, chan); kfree(info); return; } - cp = &info->channel; + + rocketMode = info->flags & ROCKET_MODE_MASK; + + if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485)) + sEnRTSToggle(&info->channel); + else + sDisRTSToggle(&info->channel); + + if (ctlp->boardType == ROCKET_TYPE_PC104) { + switch (rocketMode) { + case ROCKET_MODE_RS485: + sSetInterfaceMode(&info->channel, InterfaceModeRS485); + break; + case ROCKET_MODE_RS422: + sSetInterfaceMode(&info->channel, InterfaceModeRS422); + break; + case ROCKET_MODE_RS232: + default: + if (info->flags & ROCKET_RTS_TOGGLE) + sSetInterfaceMode(&info->channel, InterfaceModeRS232T); + else + sSetInterfaceMode(&info->channel, InterfaceModeRS232); + break; + } + } + spin_lock_init(&info->slock); + sema_init(&info->write_sem, 1); rp_table[line] = info; +#if LINUX_VERSION_CODE > VERSION_CODE(2,5,0) + if (pci_dev) + tty_register_device(&rocket_driver, line, &pci_dev->dev); +#endif } - /* - * This routine configures a rocketport port so according to its - * termio settings. + * Configures a rocketport port according to its termio settings. Called from + * user mode into the driver (exception handler). *info CD manipulation is spinlock protected. */ -static void configure_r_port(struct r_port *info) +static void configure_r_port(struct r_port *info, + struct termios *old_termios) { unsigned cflag; - unsigned long flags; - int bits, baud; - CHANNEL_t *cp; - + unsigned long flags; + unsigned rocketMode; + int bits, baud, divisor; + CHANNEL_t *cp; + if (!info->tty || !info->tty->termios) return; cp = &info->channel; @@ -589,13 +802,13 @@ sSetData7(cp); bits = 9; } - if (cflag & CSTOPB) { + if (cflag & CSTOPB) { sSetStop2(cp); bits++; } else { sSetStop1(cp); } - + if (cflag & PARENB) { sEnParity(cp); bits++; @@ -607,14 +820,28 @@ } else { sDisParity(cp); } - + /* baud rate */ baud = tty_get_baud_rate(info->tty); if (!baud) baud = 9600; + divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1; + if ((divisor >= 8192 || divisor < 0) && old_termios) { + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= + (old_termios->c_cflag & CBAUD); + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; + divisor = (rp_baud_base[info->board] / baud) - 1; + } + if (divisor >= 8192 || divisor < 0) { + baud = 9600; + divisor = (rp_baud_base[info->board] / baud) - 1; + } info->cps = baud / bits; - sSetBaud(cp, (rp_baud_base/baud) - 1); - + sSetBaud(cp, divisor); + if (cflag & CRTSCTS) { info->intmask |= DELTA_CTS; sEnCTSFlowCtl(cp); @@ -622,17 +849,16 @@ info->intmask &= ~DELTA_CTS; sDisCTSFlowCtl(cp); } - sSetRTS(&info->channel); - if (cflag & CLOCAL) + if (cflag & CLOCAL) { info->intmask &= ~DELTA_CD; - else { - save_flags(flags); cli(); + } else { + spin_lock_irqsave(&info->slock, flags); if (sGetChanStatus(cp) & CD_ACT) info->cd_status = 1; else info->cd_status = 0; info->intmask |= DELTA_CD; - restore_flags(flags); + spin_unlock_irqrestore(&info->slock, flags); } /* @@ -654,7 +880,7 @@ sClrTxXOFF(cp); } #endif - + /* * Set up ignore/read mask words */ @@ -679,263 +905,281 @@ if (I_IGNPAR(info->tty)) info->ignore_status_mask |= STMRCVROVRH; } + + rocketMode = info->flags & ROCKET_MODE_MASK; + + if ((info->flags & ROCKET_RTS_TOGGLE) + || (rocketMode == ROCKET_MODE_RS485)) + sEnRTSToggle(cp); + else + sDisRTSToggle(cp); + + sSetRTS(&info->channel); + + if (cp->CtlP->boardType == ROCKET_TYPE_PC104) { + switch (rocketMode) { + case ROCKET_MODE_RS485: + sSetInterfaceMode(cp, InterfaceModeRS485); + break; + case ROCKET_MODE_RS422: + sSetInterfaceMode(cp, InterfaceModeRS422); + break; + case ROCKET_MODE_RS232: + default: + if (info->flags & ROCKET_RTS_TOGGLE) + sSetInterfaceMode(cp, InterfaceModeRS232T); + else + sSetInterfaceMode(cp, InterfaceModeRS232); + break; + } + } } -static int block_til_ready(struct tty_struct *tty, struct file * filp, +/* info->count is considered critical, protected by spinlocks. */ +static int block_til_ready(struct tty_struct *tty, struct file *filp, struct r_port *info) { DECLARE_WAITQUEUE(wait, current); - int retval; - int do_clocal = 0, extra_count = 0; - unsigned long flags; + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; /* * If the device is in the middle of being closed, then block * until it's done, and then try again. */ if (tty_hung_up_p(filp)) - return ((info->flags & ROCKET_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); + return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); if (info->flags & ROCKET_CLOSING) { interruptible_sleep_on(&info->close_wait); - return ((info->flags & ROCKET_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); + return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); } /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { + if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { info->flags |= ROCKET_NORMAL_ACTIVE; return 0; } - if (tty->termios->c_cflag & CLOCAL) do_clocal = 1; /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that - * rp_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. + * Block waiting for the carrier detect and the line to become free. While we are in + * this loop, info->count is dropped by one, so that rp_close() knows when to free things. + * We restore it upon exit, either normal or abnormal. */ retval = 0; add_wait_queue(&info->open_wait, &wait); #ifdef ROCKET_DEBUG_OPEN - printk("block_til_ready before block: ttyR%d, count = %d\n", - info->line, info->count); + printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, info->count); #endif - save_flags(flags); cli(); + spin_lock_irqsave(&info->slock, flags); + +#ifdef ROCKET_DISABLE_SIMUSAGE + info->flags |= ROCKET_NORMAL_ACTIVE; +#else if (!tty_hung_up_p(filp)) { extra_count = 1; info->count--; } - restore_flags(flags); +#endif info->blocked_open++; + + spin_unlock_irqrestore(&info->slock, flags); + while (1) { - if ((tty->termios->c_cflag & CBAUD)) { + if (tty->termios->c_cflag & CBAUD) { sSetDTR(&info->channel); sSetRTS(&info->channel); } set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(info->flags & ROCKET_INITIALIZED)) { + if (tty_hung_up_p(filp) || !(info->flags & ROCKET_INITIALIZED)) { if (info->flags & ROCKET_HUP_NOTIFY) retval = -EAGAIN; else - retval = -ERESTARTSYS; + retval = -ERESTARTSYS; break; } - if (!(info->flags & ROCKET_CLOSING) && - (do_clocal || (sGetChanStatusLo(&info->channel) & - CD_ACT))) + if (!(info->flags & ROCKET_CLOSING) && (do_clocal || (sGetChanStatusLo(&info->channel) & CD_ACT))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; break; } #ifdef ROCKET_DEBUG_OPEN - printk("block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n", - info->line, info->count, info->flags); + printk(KERN_INFO "block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n", + info->line, info->count, info->flags); #endif - schedule(); + schedule(); /* Don't hold spinlock here, will hang PC */ } current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); - cli(); + + spin_lock_irqsave(&info->slock, flags); + if (extra_count) info->count++; - restore_flags(flags); info->blocked_open--; + + spin_unlock_irqrestore(&info->slock, flags); + #ifdef ROCKET_DEBUG_OPEN - printk("block_til_ready after blocking: ttyR%d, count = %d\n", + printk(KERN_INFO "block_til_ready after blocking: ttyR%d, count = %d\n", info->line, info->count); #endif if (retval) return retval; info->flags |= ROCKET_NORMAL_ACTIVE; return 0; -} +} /* - * This routine is called whenever a rocketport board is opened. + * Exception handler that opens a serial port. Creates xmit_buf storage, fills in + * port's r_port struct. Initializes the port hardware. */ -static int rp_open(struct tty_struct *tty, struct file * filp) +static int rp_open(struct tty_struct *tty, struct file *filp) { struct r_port *info; - int line, retval; - CHANNEL_t *cp; + int line = 0, retval; + CHANNEL_t *cp; unsigned long page; - - line = tty->index; - if ((line < 0) || (line >= MAX_RP_PORTS)) - return -ENODEV; - if (!tmp_buf) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; - } - page = get_zeroed_page(GFP_KERNEL); + +#if LINUX_VERSION_CODE > VERSION_CODE(2,5,0) + line = TTY_GET_LINE(tty); +#else + line = MINOR(tty->device) - TTY_DRIVER_MINOR_START(tty); +#endif + + if ((line < 0) || (line >= MAX_RP_PORTS) || ((info = rp_table[line]) == NULL)) + return -ENXIO; + + page = __get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; - tty->driver_data = info = rp_table[line]; - if (info->flags & ROCKET_CLOSING) { interruptible_sleep_on(&info->close_wait); free_page(page); - return ((info->flags & ROCKET_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); + return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); } - + /* - * We must not sleep from here until the port is marked fully - * in use. + * We must not sleep from here until the port is marked fully in use. */ - if (rp_table[line] == NULL) { - tty->flags = (1 << TTY_IO_ERROR); - free_page(page); - return 0; - } - if (!info) { - printk("rp_open: rp_table[%d] is NULL!\n", line); - free_page(page); - return -EIO; - } if (info->xmit_buf) free_page(page); else info->xmit_buf = (unsigned char *) page; - info->tty = tty; - if (info->flags & ROCKET_CLOSING) { - interruptible_sleep_on(&info->close_wait); - return ((info->flags & ROCKET_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); - } + tty->driver_data = info; + info->tty = tty; if (info->count++ == 0) { - rp_num_ports_open++; +#if ((LINUX_VERSION_CODE < VERSION_CODE(2,5,0)) && defined(MODULE)) + MOD_INC_USE_COUNT; +#endif + atomic_inc(&rp_num_ports_open); + #ifdef ROCKET_DEBUG_OPEN - printk("rocket mod++ = %d...", rp_num_ports_open); + printk(KERN_INFO "rocket mod++ = %d...", atomic_read(&rp_num_ports_open)); #endif } #ifdef ROCKET_DEBUG_OPEN - printk("rp_open ttyR%d, count=%d\n", info->line, info->count); + printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->count); #endif + /* * Info->count is now 1; so it's safe to sleep now. */ - - cp = &info->channel; - sSetRxTrigger(cp, TRIG_1); - if (sGetChanStatus(cp) & CD_ACT) - info->cd_status = 1; - else - info->cd_status = 0; - sDisRxStatusMode(cp); - sFlushRxFIFO(cp); - sFlushTxFIFO(cp); - - sEnInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); - sSetRxTrigger(cp, TRIG_1); + info->session = current->session; + info->pgrp = current->pgrp; - sGetChanStatus(cp); - sDisRxStatusMode(cp); - sClrTxXOFF(cp); - - sDisCTSFlowCtl(cp); - sDisTxSoftFlowCtl(cp); - - sEnRxFIFO(cp); - sEnTransmit(cp); + if ((info->flags & ROCKET_INITIALIZED) == 0) { + cp = &info->channel; + sSetRxTrigger(cp, TRIG_1); + if (sGetChanStatus(cp) & CD_ACT) + info->cd_status = 1; + else + info->cd_status = 0; + sDisRxStatusMode(cp); + sFlushRxFIFO(cp); + sFlushTxFIFO(cp); - info->flags |= ROCKET_INITIALIZED; + sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); + sSetRxTrigger(cp, TRIG_1); - /* - * Set up the tty->alt_speed kludge - */ - if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) - info->tty->alt_speed = 57600; - if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) - info->tty->alt_speed = 115200; - if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) - info->tty->alt_speed = 230400; - if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) - info->tty->alt_speed = 460800; + sGetChanStatus(cp); + sDisRxStatusMode(cp); + sClrTxXOFF(cp); - configure_r_port(info); - if (tty->termios->c_cflag & CBAUD) { - sSetDTR(cp); - sSetRTS(cp); + sDisCTSFlowCtl(cp); + sDisTxSoftFlowCtl(cp); + + sEnRxFIFO(cp); + sEnTransmit(cp); + + info->flags |= ROCKET_INITIALIZED; + + /* + * Set up the tty->alt_speed kludge + */ + if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) + info->tty->alt_speed = 460800; + + configure_r_port(info, NULL); + if (tty->termios->c_cflag & CBAUD) { + sSetDTR(cp); + sSetRTS(cp); + } } - - mod_timer(&rocket_timer, jiffies + 1); + /* Starts (or resets) the maint polling loop */ + mod_timer(&rocket_timer, jiffies + POLL_PERIOD); retval = block_til_ready(tty, filp, info); if (retval) { #ifdef ROCKET_DEBUG_OPEN - printk("rp_open returning after block_til_ready with %d\n", - retval); + printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval); #endif return retval; } if ((info->count == 1) && (info->flags & ROCKET_SPLIT_TERMIOS)) { *tty->termios = info->normal_termios; - configure_r_port(info); + configure_r_port(info, NULL); } - return 0; } -static void rp_close(struct tty_struct *tty, struct file * filp) +/* + * Exception handler that closes a serial port. info->count is considered critical. + */ +static void rp_close(struct tty_struct *tty, struct file *filp) { - struct r_port * info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; unsigned long flags; int timeout; - CHANNEL_t *cp; + CHANNEL_t *cp; - if (rocket_paranoia_check(info, tty->name, "rp_close")) + if (rocket_paranoia_check(info, "rp_close")) return; #ifdef ROCKET_DEBUG_OPEN - printk("rp_close ttyR%d, count = %d\n", info->line, info->count); + printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->count); #endif - - save_flags(flags); cli(); - - if (tty_hung_up_p(filp)) { - restore_flags(flags); + + if (tty_hung_up_p(filp)) return; - } + spin_lock_irqsave(&info->slock, flags); + if ((tty->count == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty @@ -944,27 +1188,23 @@ * one, we've got real problems, since it means the * serial port won't be shutdown. */ - printk("rp_close: bad serial port count; tty->count is 1, " + printk(KERN_INFO "rp_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { - printk("rp_close: bad serial port count for ttyR%d: %d\n", + printk(KERN_INFO "rp_close: bad serial port count for ttyR%d: %d\n", info->line, info->count); info->count = 0; } if (info->count) { - restore_flags(flags); + spin_unlock_irqrestore(&info->slock, flags); return; } info->flags |= ROCKET_CLOSING; - /* - * Save the termios structure, since this port may have - * separate termios for callout and dialin. - */ - if (info->flags & ROCKET_NORMAL_ACTIVE) - info->normal_termios = *tty->termios; - + spin_unlock_irqrestore(&info->slock, flags); + + info->normal_termios = *tty->termios; cp = &info->channel; /* @@ -989,29 +1229,30 @@ * has completely drained; this is especially * important if there is a transmit FIFO! */ - timeout = (sGetTxCnt(cp)+1) * HZ / info->cps; + timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps; if (timeout == 0) timeout = 1; rp_wait_until_sent(tty, timeout); - - xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); + clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); + sDisTransmit(cp); - sDisInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); + sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); sDisCTSFlowCtl(cp); sDisTxSoftFlowCtl(cp); sClrTxXOFF(cp); - sFlushRxFIFO(cp); + sFlushRxFIFO(cp); sFlushTxFIFO(cp); sClrRTS(cp); - if (C_HUPCL(tty)) { + if (C_HUPCL(tty)) sClrDTR(cp); - } - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + + if (TTY_DRIVER_FLUSH_BUFFER_EXISTS(tty)) + TTY_DRIVER_FLUSH_BUFFER(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); - xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); + clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); + if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; @@ -1027,27 +1268,27 @@ info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | ROCKET_NORMAL_ACTIVE); tty->closing = 0; wake_up_interruptible(&info->close_wait); - - rp_num_ports_open--; -#ifdef ROCKET_DEBUG_OPEN - printk("rocket mod-- = %d...", rp_num_ports_open); + +#if ((LINUX_VERSION_CODE < VERSION_CODE(2,5,0)) && defined(MODULE)) + MOD_DEC_USE_COUNT; #endif - restore_flags(flags); - + atomic_dec(&rp_num_ports_open); + #ifdef ROCKET_DEBUG_OPEN - printk("rp_close ttyR%d complete shutdown\n", info->line); + printk(KERN_INFO "rocket mod-- = %d...", atomic_read(&rp_num_ports_open)); + printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line); #endif - + } -static void rp_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void rp_set_termios(struct tty_struct *tty, + struct termios *old_termios) { - struct r_port * info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; unsigned cflag; - - if (rocket_paranoia_check(info, tty->name, "rp_set_termios")) + if (rocket_paranoia_check(info, "rp_set_termios")) return; cflag = tty->termios->c_cflag; @@ -1058,88 +1299,103 @@ /* * This driver doesn't support CS5 or CS6 */ - if (((cflag & CSIZE) == CS5) || - ((cflag & CSIZE) == CS6)) - tty->termios->c_cflag = ((cflag & ~CSIZE) | - (old_termios->c_cflag & CSIZE)); + if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6)) + tty->termios->c_cflag = + ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE)); - configure_r_port(info); + configure_r_port(info, old_termios); cp = &info->channel; /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && - !(tty->termios->c_cflag & CBAUD)) { + if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) { sClrDTR(cp); sClrRTS(cp); } - + /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - (tty->termios->c_cflag & CBAUD)) { - if (!tty->hw_stopped || - !(tty->termios->c_cflag & CRTSCTS)) { + if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) { + if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS)) sSetRTS(cp); - } sSetDTR(cp); } - - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + + if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; rp_start(tty); } } -/* - * Here are the routines used by rp_ioctl - */ static void rp_break(struct tty_struct *tty, int break_state) { - struct r_port * info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; unsigned long flags; - - if (rocket_paranoia_check(info, tty->name, "rp_break")) + + if (rocket_paranoia_check(info, "rp_break")) return; - save_flags(flags); cli(); - if (break_state == -1) { + spin_lock_irqsave(&info->slock, flags); + if (break_state == -1) sSendBreak(&info->channel); - } else { + else sClrBreak(&info->channel); - } - restore_flags(flags); + spin_unlock_irqrestore(&info->slock, flags); +} + +/* + * sGetChanRI used to be a macro in rocket_int.h. When the functionality for + * the UPCI boards was added, it was decided to make this a function because + * the macro was getting too complicated. All cases except the first one + * (UPCIRingInd) are taken directly from the original macro. + */ +static int sGetChanRI(CHANNEL_T * ChP) +{ + CONTROLLER_t *CtlP = ChP->CtlP; + int ChanNum = ChP->ChanNum; + int RingInd = 0; + + if (CtlP->UPCIRingInd) + RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]); + else if (CtlP->AltChanRingIndicator) + RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT; + else if (CtlP->boardType == ROCKET_TYPE_PC104) + RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]); + + return RingInd; } -static int get_modem_info(struct r_port * info, unsigned int *value) +/********************************************************************************************/ +/* Here are the routines used by rp_ioctl. These are all called from exception handlers. */ + +static int get_modem_info(struct r_port *info, unsigned int *value) { unsigned int control, result, ChanStatus; ChanStatus = sGetChanStatusLo(&info->channel); - + control = info->channel.TxControl[3]; - result = ((control & SET_RTS) ? TIOCM_RTS : 0) - | ((control & SET_DTR) ? TIOCM_DTR : 0) - | ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) - /* TIOCM_RNG not supported */ - | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) - | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0); + result = ((control & SET_RTS) ? TIOCM_RTS : 0) | + ((control & SET_DTR) ? TIOCM_DTR : 0) | + ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) | + (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) | + ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) | + ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0); - if (copy_to_user(value, &result, sizeof(int))) + if (copy_to_user(value, &result, sizeof (int))) return -EFAULT; return 0; } -static int set_modem_info(struct r_port * info, unsigned int cmd, +static int set_modem_info(struct r_port *info, unsigned int cmd, unsigned int *value) { unsigned int arg; - if (copy_from_user(&arg, value, sizeof(int))) + if (copy_from_user(&arg, value, sizeof (int))) return -EFAULT; switch (cmd) { - case TIOCMBIS: + case TIOCMBIS: if (arg & TIOCM_RTS) info->channel.TxControl[3] |= SET_RTS; if (arg & TIOCM_DTR) @@ -1152,59 +1408,103 @@ info->channel.TxControl[3] &= ~SET_DTR; break; case TIOCMSET: - info->channel.TxControl[3] = - ((info->channel.TxControl[3] & ~(SET_RTS | SET_DTR)) - | ((arg & TIOCM_RTS) ? SET_RTS : 0) - | ((arg & TIOCM_DTR) ? SET_DTR : 0)); + info->channel.TxControl[3] = ((info->channel.TxControl[3] & ~(SET_RTS | SET_DTR)) | + ((arg & TIOCM_RTS) ? SET_RTS : 0) | + ((arg & TIOCM_DTR) ? SET_DTR : 0)); break; default: return -EINVAL; } - sOutDW(info->channel.IndexAddr, - *(DWord_t *) &(info->channel.TxControl[0])); - + sOutDW(info->channel.IndexAddr, *(DWord_t *) & (info->channel.TxControl[0])); + return 0; +} + +#if LINUX_VERSION_CODE > VERSION_CODE(2,5,0) + +/* + * Returns the state of the serial modem control lines. These next 2 functions + * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs. + */ +static int rp_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct r_port *info = (struct r_port *)tty->driver_data; + unsigned int control, result, ChanStatus; + + ChanStatus = sGetChanStatusLo(&info->channel); + control = info->channel.TxControl[3]; + result = ((control & SET_RTS) ? TIOCM_RTS : 0) | + ((control & SET_DTR) ? TIOCM_DTR : 0) | + ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) | + (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) | + ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) | + ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0); + + return result; +} + +/* + * Sets the modem control lines + */ +static int rp_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct r_port *info = (struct r_port *)tty->driver_data; + + if (set & TIOCM_RTS) + info->channel.TxControl[3] |= SET_RTS; + if (set & TIOCM_DTR) + info->channel.TxControl[3] |= SET_DTR; + if (clear & TIOCM_RTS) + info->channel.TxControl[3] &= ~SET_RTS; + if (clear & TIOCM_DTR) + info->channel.TxControl[3] &= ~SET_DTR; + + sOutDW(info->channel.IndexAddr, *(DWord_t *) & (info->channel.TxControl[0])); return 0; } -static int get_config(struct r_port * info, struct rocket_config * retinfo) +#endif /* Linux > 2.5 */ + +static int get_config(struct r_port *info, struct rocket_config *retinfo) { struct rocket_config tmp; - + if (!retinfo) return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); + memset(&tmp, 0, sizeof (tmp)); tmp.line = info->line; tmp.flags = info->flags; tmp.close_delay = info->close_delay; tmp.closing_wait = info->closing_wait; tmp.port = rcktpt_io_addr[(info->line >> 5) & 3]; - - if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + + if (copy_to_user(retinfo, &tmp, sizeof (*retinfo))) return -EFAULT; return 0; } -static int set_config(struct r_port * info, struct rocket_config * new_info) +static int set_config(struct r_port *info, struct rocket_config *new_info) { struct rocket_config new_serial; - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) + if (copy_from_user(&new_serial, new_info, sizeof (new_serial))) return -EFAULT; +#ifdef CAP_SYS_ADMIN if (!capable(CAP_SYS_ADMIN)) +#else + if (!suser()) +#endif { - if ((new_serial.flags & ~ROCKET_USR_MASK) != - (info->flags & ~ROCKET_USR_MASK)) + if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) return -EPERM; - info->flags = ((info->flags & ~ROCKET_USR_MASK) | - (new_serial.flags & ROCKET_USR_MASK)); - configure_r_port(info); + info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK)); + configure_r_port(info, 0); return 0; } - - info->flags = ((info->flags & ~ROCKET_FLAGS) | - (new_serial.flags & ROCKET_FLAGS)); + + info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS)); info->close_delay = new_serial.close_delay; info->closing_wait = new_serial.closing_wait; @@ -1216,117 +1516,162 @@ info->tty->alt_speed = 230400; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) info->tty->alt_speed = 460800; - - configure_r_port(info); + + configure_r_port(info, 0); return 0; } -static int get_ports(struct r_port * info, struct rocket_ports * retports) +/* + * This function fills in a rocket_ports struct with information + * about what boards/ports are in the system. This info is passed + * to user space. See setrocket.c where the info is used to create + * the /dev/ttyRx ports. + */ +static int get_ports(struct r_port *info, struct rocket_ports *retports) { struct rocket_ports tmp; - int board, port, index; - + int board; + if (!retports) return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); + memset(&tmp, 0, sizeof (tmp)); tmp.tty_major = rocket_driver.major; - tmp.callout_major = 0; + for (board = 0; board < 4; board++) { - index = board << 5; - for (port = 0; port < 32; port++, index++) { - if (rp_table[index]) - tmp.port_bitmap[board] |= 1 << port; - } + tmp.rocketModel[board].model = rocketModel[board].model; + strcpy(tmp.rocketModel[board].modelString, rocketModel[board].modelString); + tmp.rocketModel[board].numPorts = rocketModel[board].numPorts; + tmp.rocketModel[board].loadrm2 = rocketModel[board].loadrm2; + tmp.rocketModel[board].startingPortNumber = rocketModel[board].startingPortNumber; } - if (copy_to_user(retports,&tmp,sizeof(*retports))) + if (copy_to_user(retports, &tmp, sizeof (*retports))) return -EFAULT; return 0; } -static int rp_ioctl(struct tty_struct *tty, struct file * file, +static int reset_rm2(struct r_port *info, unsigned long arg) +{ + int reset; + + if (copy_from_user(&reset, (void *) arg, sizeof (int))) + return -EFAULT; + if (reset) + reset = 1; + + if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII && + rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII) + return -EINVAL; + + if (info->ctlp->BusType == isISA) + sModemReset(info->ctlp, info->chan, reset); + else + sPCIModemReset(info->ctlp, info->chan, reset); + + return 0; +} + +static int get_version(struct r_port *info, struct rocket_version *retvers) +{ + if (copy_to_user(retvers, &driver_version, sizeof (*retvers))) + return -EFAULT; + return 0; +} + +/* IOCTL call handler into the driver */ +static int rp_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct r_port * info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; - if (cmd != RCKP_GET_PORTS && - rocket_paranoia_check(info, tty->name, "rp_ioctl")) - return -ENODEV; + if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl")) + return -ENXIO; switch (cmd) { - - case TIOCMGET: - return get_modem_info(info, (unsigned int *) arg); - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - return set_modem_info(info, cmd, (unsigned int *) arg); - case RCKP_GET_STRUCT: - if (copy_to_user((void *) arg, info, - sizeof(struct r_port))) - return -EFAULT; - return 0; - - case RCKP_GET_CONFIG: - return get_config(info, (struct rocket_config *) arg); - case RCKP_SET_CONFIG: - return set_config(info, (struct rocket_config *) arg); - - case RCKP_GET_PORTS: - return get_ports(info, (struct rocket_ports *) arg); - default: - return -ENOIOCTLCMD; - } + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + case RCKP_GET_STRUCT: + if (copy_to_user((void *) arg, info, sizeof (struct r_port))) + return -EFAULT; + return 0; + case RCKP_GET_CONFIG: + return get_config(info, (struct rocket_config *) arg); + case RCKP_SET_CONFIG: + return set_config(info, (struct rocket_config *) arg); + case RCKP_GET_PORTS: + return get_ports(info, (struct rocket_ports *) arg); + case RCKP_RESET_RM2: + return reset_rm2(info, arg); + case RCKP_GET_VERSION: + return get_version(info, (struct rocket_version *) arg); + default: + return -ENOIOCTLCMD; + } return 0; } +#if (defined(ROCKET_DEBUG_FLOW) || defined(ROCKET_DEBUG_THROTTLE)) +static char *rp_tty_name(struct tty_struct *tty, char *buf) +{ + if (tty) + sprintf(buf, "%s%d", TTY_DRIVER_NAME(tty), MINOR(tty->device) - TTY_DRIVER_MINOR_START(tty) + TTY_DRIVER_NAME_BASE); + else + strcpy(buf, "NULL tty"); + return buf; +} +#endif + static void rp_send_xchar(struct tty_struct *tty, char ch) { - struct r_port *info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; - if (rocket_paranoia_check(info, tty->name, "rp_send_xchar")) + if (rocket_paranoia_check(info, "rp_send_xchar")) return; cp = &info->channel; - if (sGetTxCnt(cp)) + if (sGetTxCnt(cp)) sWriteTxPrioByte(cp, ch); else sWriteTxByte(sGetTxRxDataIO(cp), ch); } -static void rp_throttle(struct tty_struct * tty) +static void rp_throttle(struct tty_struct *tty) { - struct r_port *info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; #ifdef ROCKET_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", tty->name, + char buf[64]; + + printk(KERN_INFO "throttle %s: %d....\n", rp_tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif - if (rocket_paranoia_check(info, tty->name, "rp_throttle")) + if (rocket_paranoia_check(info, "rp_throttle")) return; cp = &info->channel; if (I_IXOFF(tty)) rp_send_xchar(tty, STOP_CHAR(tty)); - + sClrRTS(&info->channel); } -static void rp_unthrottle(struct tty_struct * tty) +static void rp_unthrottle(struct tty_struct *tty) { - struct r_port *info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; #ifdef ROCKET_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", tty->name, + char buf[64]; + + printk(KERN_INFO "unthrottle %s: %d....\n", rp_tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif - if (rocket_paranoia_check(info, tty->name, "rp_throttle")) + if (rocket_paranoia_check(info, "rp_throttle")) return; cp = &info->channel; @@ -1346,15 +1691,15 @@ */ static void rp_stop(struct tty_struct *tty) { - struct r_port * info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; #ifdef ROCKET_DEBUG_FLOW - char buf[64]; - - printk("stop %s: %d %d....\n", tty->name, + char buf[64]; + + printk(KERN_INFO "stop %s: %d %d....\n", rp_tty_name(tty, buf), info->xmit_cnt, info->xmit_fifo_room); #endif - if (rocket_paranoia_check(info, tty->name, "rp_stop")) + if (rocket_paranoia_check(info, "rp_stop")) return; if (sGetTxCnt(&info->channel)) @@ -1363,19 +1708,20 @@ static void rp_start(struct tty_struct *tty) { - struct r_port * info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; #ifdef ROCKET_DEBUG_FLOW - char buf[64]; - - printk("start %s: %d %d....\n", tty->name, + char buf[64]; + + printk(KERN_INFO "start %s: %d %d....\n", rp_tty_name(tty, buf), info->xmit_cnt, info->xmit_fifo_room); #endif - if (rocket_paranoia_check(info, tty->name, "rp_stop")) + if (rocket_paranoia_check(info, "rp_stop")) return; sEnTransmit(&info->channel); - xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f)); + set_bit((info->aiop * 8) + info->chan, + (void *) &xmit_flags[info->board]); } /* @@ -1383,21 +1729,22 @@ */ static void rp_wait_until_sent(struct tty_struct *tty, int timeout) { - struct r_port *info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; unsigned long orig_jiffies; int check_time, exit_time; int txcnt; - - if (rocket_paranoia_check(info, tty->name, "rp_wait_until_sent")) + + if (rocket_paranoia_check(info, "rp_wait_until_sent")) return; cp = &info->channel; orig_jiffies = jiffies; #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT - printk("In RP_wait_until_sent(%d) (jiff=%lu)...", timeout, jiffies); - printk("cps=%d...", info->cps); + printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...", timeout, + jiffies); + printk(KERN_INFO "cps=%d...", info->cps); #endif while (1) { txcnt = sGetTxCnt(cp); @@ -1405,8 +1752,9 @@ if (sGetChanStatusLo(cp) & TXSHRMT) break; check_time = (HZ / info->cps) / 5; - } else + } else { check_time = HZ * txcnt / info->cps; + } if (timeout) { exit_time = orig_jiffies + timeout - jiffies; if (exit_time <= 0) @@ -1417,8 +1765,7 @@ if (check_time == 0) check_time = 1; #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT - printk("txcnt = %d (jiff=%lu,check=%d)...", txcnt, - jiffies, check_time); + printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...", txcnt, jiffies, check_time); #endif current->state = TASK_INTERRUPTIBLE; schedule_timeout(check_time); @@ -1427,7 +1774,7 @@ } current->state = TASK_RUNNING; #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT - printk("txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies); + printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies); #endif } @@ -1436,32 +1783,26 @@ */ static void rp_hangup(struct tty_struct *tty) { - CHANNEL_t *cp; - struct r_port * info = (struct r_port *)tty->driver_data; - - if (rocket_paranoia_check(info, tty->name, "rp_hangup")) + CHANNEL_t *cp; + struct r_port *info = (struct r_port *) tty->driver_data; + + if (rocket_paranoia_check(info, "rp_hangup")) return; #if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP)) - printk("rp_hangup of ttyR%d...", info->line); + printk(KERN_INFO "rp_hangup of ttyR%d...", info->line); #endif - /* - * If the port is in the process of being closed, just force - * the transmit buffer to be empty, and let rp_close handle - * the clean up. - */ - if (info->flags & ROCKET_CLOSING) { - cli(); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - sti(); - wake_up_interruptible(&tty->write_wait); + rp_flush_buffer(tty); + if (info->flags & ROCKET_CLOSING) return; - } if (info->count) { - rp_num_ports_open--; +#if ((LINUX_VERSION_CODE < VERSION_CODE(2,5,0)) && defined(MODULE)) + MOD_DEC_USE_COUNT; +#endif + atomic_dec(&rp_num_ports_open); } - - xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); + clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); + info->count = 0; info->flags &= ~ROCKET_NORMAL_ACTIVE; info->tty = 0; @@ -1469,149 +1810,168 @@ cp = &info->channel; sDisRxFIFO(cp); sDisTransmit(cp); - sDisInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); + sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); sDisCTSFlowCtl(cp); sDisTxSoftFlowCtl(cp); sClrTxXOFF(cp); info->flags &= ~ROCKET_INITIALIZED; - + wake_up_interruptible(&info->open_wait); } /* - * The Rocketport write routines. The Rocketport driver uses a - * double-buffering strategy, with the twist that if the in-memory CPU - * buffer is empty, and there's space in the transmit FIFO, the - * writing routines will write directly to transmit FIFO. - * - * This gets a little tricky, but I'm pretty sure I got it all right. + * Exception handler - write char routine. The RocketPort driver uses a + * double-buffering strategy, with the twist that if the in-memory CPU + * buffer is empty, and there's space in the transmit FIFO, the + * writing routines will write directly to transmit FIFO. + * Write buffer and counters protected by spinlocks */ static void rp_put_char(struct tty_struct *tty, unsigned char ch) { - struct r_port * info = (struct r_port *)tty->driver_data; - CHANNEL_t *cp; + struct r_port *info = (struct r_port *) tty->driver_data; + CHANNEL_t *cp; + unsigned long flags; - if (rocket_paranoia_check(info, tty->name, "rp_put_char")) + if (rocket_paranoia_check(info, "rp_put_char")) return; + /* Grab the port write semaphore, locking out other processes that try to write to this port */ + down(&info->write_sem); + #ifdef ROCKET_DEBUG_WRITE - printk("rp_put_char %c...", ch); + printk(KERN_INFO "rp_put_char %c...", ch); #endif - + + spin_lock_irqsave(&info->slock, flags); cp = &info->channel; if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0) info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); - if (tty->stopped || tty->hw_stopped || - info->xmit_fifo_room == 0 || info->xmit_cnt != 0) { + if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) { info->xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= XMIT_BUF_SIZE-1; + info->xmit_head &= XMIT_BUF_SIZE - 1; info->xmit_cnt++; - xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f)); + set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); } else { sOutB(sGetTxRxDataIO(cp), ch); info->xmit_fifo_room--; } + spin_unlock_irqrestore(&info->slock, flags); + up(&info->write_sem); } -static int rp_write(struct tty_struct * tty, int from_user, +/* + * Exception handler - write routine, called when user app writes to the device. + * A per port write semaphore is used to protect from another process writing to + * this port at the same time. This other process could be running on the other CPU + * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out). + * Spinlocks protect the info xmit members. + */ +static int rp_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) { - struct r_port * info = (struct r_port *)tty->driver_data; - CHANNEL_t *cp; - const unsigned char *b; - int c, retval = 0; - unsigned long flags; + struct r_port *info = (struct r_port *) tty->driver_data; + CHANNEL_t *cp; + const unsigned char *b; + int c, retval = 0; + unsigned long flags; - if (count <= 0 || rocket_paranoia_check(info, tty->name, "rp_write")) + if (count <= 0 || rocket_paranoia_check(info, "rp_write")) return 0; + down_interruptible(&info->write_sem); + #ifdef ROCKET_DEBUG_WRITE - printk("rp_write %d chars...", count); + printk(KERN_INFO "rp_write %d chars...", count); #endif cp = &info->channel; - if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0) + if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count) info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); - if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 - && info->xmit_fifo_room >= 0) { + /* + * If the write queue for the port is empty, and there is FIFO space, stuff bytes + * into FIFO. Use the write queue for temp storage. + */ + if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) { c = MIN(count, info->xmit_fifo_room); b = buf; if (from_user) { - down(&tmp_buf_sem); - c -= copy_from_user(tmp_buf, buf, c); - b = tmp_buf; - up(&tmp_buf_sem); - /* In case we got pre-empted */ - if (!c) { + if (copy_from_user(info->xmit_buf, buf, c)) { retval = -EFAULT; goto end; } if (info->tty == 0) goto end; + b = info->xmit_buf; c = MIN(c, info->xmit_fifo_room); } - sOutStrW(sGetTxRxDataIO(cp), b, c/2); + + /* Push data into FIFO, 2 bytes at a time */ + sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2); + + /* If there is a byte remaining, write it */ if (c & 1) - sOutB(sGetTxRxDataIO(cp), b[c-1]); + sOutB(sGetTxRxDataIO(cp), b[c - 1]); + retval += c; buf += c; count -= c; + + spin_lock_irqsave(&info->slock, flags); info->xmit_fifo_room -= c; + spin_unlock_irqrestore(&info->slock, flags); } + + /* If count is zero, we wrote it all and are done */ if (!count) goto end; - - save_flags(flags); + + /* Write remaining data into the port's xmit_buf */ while (1) { - if (info->tty == 0) { - restore_flags(flags); + if (info->tty == 0) /* Seemingly obligatory check... */ goto end; - } - c = MIN(count, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1, - XMIT_BUF_SIZE - info->xmit_head)); + + c = MIN(count, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head)); if (c <= 0) break; b = buf; if (from_user) { - down(&tmp_buf_sem); - c -= copy_from_user(tmp_buf, buf, c); - b = tmp_buf; - up(&tmp_buf_sem); - if (!c) { - if (retval == 0) - retval = -EFAULT; + if (copy_from_user(info->xmit_buf + info->xmit_head, b, c)) { + retval = -EFAULT; goto end_intr; + } else { + memcpy(info->xmit_buf + info->xmit_head, b, c); } - /* In case we got pre-empted */ - if (info->tty == 0) - goto end_intr; } - cli(); - c = MIN(c, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1, - XMIT_BUF_SIZE - info->xmit_head)); - memcpy(info->xmit_buf + info->xmit_head, b, c); - info->xmit_head = (info->xmit_head + c) & (XMIT_BUF_SIZE-1); + + spin_lock_irqsave(&info->slock, flags); + info->xmit_head = + (info->xmit_head + c) & (XMIT_BUF_SIZE - 1); info->xmit_cnt += c; - restore_flags(flags); + spin_unlock_irqrestore(&info->slock, flags); + buf += c; count -= c; retval += c; } + end_intr: if ((retval > 0) && !tty->stopped && !tty->hw_stopped) - xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f)); - restore_flags(flags); + set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); + end: - if (info->xmit_cnt < WAKEUP_CHARS) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + if (info->xmit_cnt < WAKEUP_CHARS) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); wake_up_interruptible(&tty->write_wait); +#ifdef ROCKETPORT_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif } + up(&info->write_sem); return retval; } @@ -1622,17 +1982,17 @@ */ static int rp_write_room(struct tty_struct *tty) { - struct r_port * info = (struct r_port *)tty->driver_data; - int ret; + struct r_port *info = (struct r_port *) tty->driver_data; + int ret; - if (rocket_paranoia_check(info, tty->name, "rp_write_room")) + if (rocket_paranoia_check(info, "rp_write_room")) return 0; ret = XMIT_BUF_SIZE - info->xmit_cnt - 1; if (ret < 0) ret = 0; #ifdef ROCKET_DEBUG_WRITE - printk("rp_write_room returns %d...", ret); + printk(KERN_INFO "rp_write_room returns %d...", ret); #endif return ret; } @@ -1643,332 +2003,655 @@ */ static int rp_chars_in_buffer(struct tty_struct *tty) { - struct r_port * info = (struct r_port *)tty->driver_data; - CHANNEL_t *cp; + struct r_port *info = (struct r_port *) tty->driver_data; + CHANNEL_t *cp; - if (rocket_paranoia_check(info, tty->name, "rp_chars_in_buffer")) + if (rocket_paranoia_check(info, "rp_chars_in_buffer")) return 0; cp = &info->channel; #ifdef ROCKET_DEBUG_WRITE - printk("rp_chars_in_buffer returns %d...", info->xmit_cnt); + printk(KERN_INFO "rp_chars_in_buffer returns %d...", info->xmit_cnt); #endif return info->xmit_cnt; } +/* + * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the + * r_port struct for the port. Note that spinlock are used to protect info members, + * do not call this function if the spinlock is already held. + */ static void rp_flush_buffer(struct tty_struct *tty) { - struct r_port * info = (struct r_port *)tty->driver_data; - CHANNEL_t *cp; + struct r_port *info = (struct r_port *) tty->driver_data; + CHANNEL_t *cp; + unsigned long flags; - if (rocket_paranoia_check(info, tty->name, "rp_flush_buffer")) + if (rocket_paranoia_check(info, "rp_flush_buffer")) return; - cli(); + spin_lock_irqsave(&info->slock, flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - sti(); + spin_unlock_irqrestore(&info->slock, flags); + wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - +#ifdef ROCKETPORT_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); + cp = &info->channel; - sFlushTxFIFO(cp); } #ifdef CONFIG_PCI - -int __init register_PCI(int i, unsigned int bus, unsigned int device_fn) + +/* + * Called when a PCI card is found. Retrieves and stores model information, + * init's aiopic and serial port hardware. + * Inputs: i is the board number (0-n) + */ +__init int register_PCI(int i, struct pci_dev *dev) { - int num_aiops, aiop, max_num_aiops, num_chan, chan; - unsigned int aiopio[MAX_AIOPS_PER_BOARD]; - char *str; - CONTROLLER_t *ctlp; - struct pci_dev *dev = pci_find_slot(bus, device_fn); + int num_aiops, aiop, max_num_aiops, num_chan, chan; + unsigned int aiopio[MAX_AIOPS_PER_BOARD]; + char *str, *board_type; + CONTROLLER_t *ctlp; - if (!dev) + int fast_clock = 0; + int altChanRingIndicator = 0; + int ports_per_aiop = 8; + int ret; + unsigned int class_rev; + WordIO_t ConfigIO = 0; + ByteIO_t UPCIRingInd = 0; + + if (!dev || pci_enable_device(dev)) return 0; - if (pci_enable_device(dev)) + rcktpt_io_addr[i] = pci_resource_start(dev, 0); + ret = pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + + if (ret) { + printk(KERN_INFO " Error during register_PCI(), unable to read config dword \n"); return 0; + } + + rcktpt_type[i] = ROCKET_TYPE_NORMAL; + rocketModel[i].loadrm2 = 0; + rocketModel[i].startingPortNumber = nextLineNumber; - rcktpt_io_addr[i] = pci_resource_start (dev, 0); - switch(dev->device) { + /* Depending on the model, set up some config variables */ + switch (dev->device) { case PCI_DEVICE_ID_RP4QUAD: str = "Quadcable"; max_num_aiops = 1; + ports_per_aiop = 4; + rocketModel[i].model = MODEL_RP4QUAD; + strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable"); + rocketModel[i].numPorts = 4; break; case PCI_DEVICE_ID_RP8OCTA: str = "Octacable"; max_num_aiops = 1; + rocketModel[i].model = MODEL_RP8OCTA; + strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable"); + rocketModel[i].numPorts = 8; + break; + case PCI_DEVICE_ID_URP8OCTA: + str = "Octacable"; + max_num_aiops = 1; + rocketModel[i].model = MODEL_UPCI_RP8OCTA; + strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable"); + rocketModel[i].numPorts = 8; break; case PCI_DEVICE_ID_RP8INTF: str = "8"; max_num_aiops = 1; + rocketModel[i].model = MODEL_RP8INTF; + strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F"); + rocketModel[i].numPorts = 8; + break; + case PCI_DEVICE_ID_URP8INTF: + str = "8"; + max_num_aiops = 1; + rocketModel[i].model = MODEL_UPCI_RP8INTF; + strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F"); + rocketModel[i].numPorts = 8; break; case PCI_DEVICE_ID_RP8J: str = "8J"; max_num_aiops = 1; + rocketModel[i].model = MODEL_RP8J; + strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors"); + rocketModel[i].numPorts = 8; + break; + case PCI_DEVICE_ID_RP4J: + str = "4J"; + max_num_aiops = 1; + ports_per_aiop = 4; + rocketModel[i].model = MODEL_RP4J; + strcpy(rocketModel[i].modelString, "RocketPort 4 port w/RJ45 connectors"); + rocketModel[i].numPorts = 4; + break; + case PCI_DEVICE_ID_RP8SNI: + str = "8 (DB78 Custom)"; + max_num_aiops = 1; + rocketModel[i].model = MODEL_RP8SNI; + strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78"); + rocketModel[i].numPorts = 8; + break; + case PCI_DEVICE_ID_RP16SNI: + str = "16 (DB78 Custom)"; + max_num_aiops = 2; + rocketModel[i].model = MODEL_RP16SNI; + strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78"); + rocketModel[i].numPorts = 16; + break; + case PCI_DEVICE_ID_RP16INTF: + str = "16"; + max_num_aiops = 2; + rocketModel[i].model = MODEL_RP16INTF; + strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F"); + rocketModel[i].numPorts = 16; + break; + case PCI_DEVICE_ID_URP16INTF: + str = "16"; + max_num_aiops = 2; + rocketModel[i].model = MODEL_UPCI_RP16INTF; + strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F"); + rocketModel[i].numPorts = 16; + break; + case PCI_DEVICE_ID_CRP16INTF: + str = "16"; + max_num_aiops = 2; + rocketModel[i].model = MODEL_CPCI_RP16INTF; + strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F"); + rocketModel[i].numPorts = 16; + break; + case PCI_DEVICE_ID_RP32INTF: + str = "32"; + max_num_aiops = 4; + rocketModel[i].model = MODEL_RP32INTF; + strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F"); + rocketModel[i].numPorts = 32; + break; + case PCI_DEVICE_ID_URP32INTF: + str = "32"; + max_num_aiops = 4; + rocketModel[i].model = MODEL_UPCI_RP32INTF; + strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F"); + rocketModel[i].numPorts = 32; + break; + case PCI_DEVICE_ID_RPP4: + str = "Plus Quadcable"; + max_num_aiops = 1; + ports_per_aiop = 4; + altChanRingIndicator++; + fast_clock++; + rocketModel[i].model = MODEL_RPP4; + strcpy(rocketModel[i].modelString, "RocketPort Plus 4 port"); + rocketModel[i].numPorts = 4; + break; + case PCI_DEVICE_ID_RPP8: + str = "Plus Octacable"; + max_num_aiops = 2; + ports_per_aiop = 4; + altChanRingIndicator++; + fast_clock++; + rocketModel[i].model = MODEL_RPP8; + strcpy(rocketModel[i].modelString, "RocketPort Plus 8 port"); + rocketModel[i].numPorts = 8; + break; + case PCI_DEVICE_ID_RP2_232: + str = "Plus 2 (RS-232)"; + max_num_aiops = 1; + ports_per_aiop = 2; + altChanRingIndicator++; + fast_clock++; + rocketModel[i].model = MODEL_RP2_232; + strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS232"); + rocketModel[i].numPorts = 2; + break; + case PCI_DEVICE_ID_RP2_422: + str = "Plus 2 (RS-422)"; + max_num_aiops = 1; + ports_per_aiop = 2; + altChanRingIndicator++; + fast_clock++; + rocketModel[i].model = MODEL_RP2_422; + strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS422"); + rocketModel[i].numPorts = 2; + break; + case PCI_DEVICE_ID_RP6M: + + max_num_aiops = 1; + ports_per_aiop = 6; + str = "6-port"; + + /* If class_rev is 1, the rocketmodem flash must be loaded. If it is 2 it is a "socketed" version. */ + if ((class_rev & 0xFF) == 1) { + rcktpt_type[i] = ROCKET_TYPE_MODEMII; + rocketModel[i].loadrm2 = 1; + } else { + rcktpt_type[i] = ROCKET_TYPE_MODEM; + } + + rocketModel[i].model = MODEL_RP6M; + strcpy(rocketModel[i].modelString, "RocketModem 6 port"); + rocketModel[i].numPorts = 6; + break; + case PCI_DEVICE_ID_RP4M: + max_num_aiops = 1; + ports_per_aiop = 4; + str = "4-port"; + if ((class_rev & 0xFF) == 1) { + rcktpt_type[i] = ROCKET_TYPE_MODEMII; + rocketModel[i].loadrm2 = 1; + } else { + rcktpt_type[i] = ROCKET_TYPE_MODEM; + } + + rocketModel[i].model = MODEL_RP4M; + strcpy(rocketModel[i].modelString, "RocketModem 4 port"); + rocketModel[i].numPorts = 4; break; - case PCI_DEVICE_ID_RP16INTF: - str = "16"; - max_num_aiops = 2; + default: + str = "(unknown/unsupported)"; + max_num_aiops = 0; break; - case PCI_DEVICE_ID_RP32INTF: - str = "32"; - max_num_aiops = 4; + } + + /* + * Check for UPCI boards. + */ + + switch (dev->device) { + case PCI_DEVICE_ID_URP32INTF: + case PCI_DEVICE_ID_URP8INTF: + case PCI_DEVICE_ID_URP16INTF: + case PCI_DEVICE_ID_CRP16INTF: + case PCI_DEVICE_ID_URP8OCTA: + rcktpt_io_addr[i] = pci_resource_start(dev, 2); + ConfigIO = pci_resource_start(dev, 1); + if (dev->device == PCI_DEVICE_ID_URP8OCTA) { + UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; + + /* + * Check for octa or quad cable. + */ + if (! + (sInW(ConfigIO + _PCI_9030_GPIO_CTRL) & + PCI_GPIO_CTRL_8PORT)) { + str = "Quadcable"; + ports_per_aiop = 4; + rocketModel[i].numPorts = 4; + } + } break; - case PCI_DEVICE_ID_RPP4: - str = "Plus Quadcable"; + case PCI_DEVICE_ID_UPCI_RM3_8PORT: + str = "8 ports"; max_num_aiops = 1; + rocketModel[i].model = MODEL_UPCI_RM3_8PORT; + strcpy(rocketModel[i].modelString, "RocketModem III 8 port"); + rocketModel[i].numPorts = 8; + rcktpt_io_addr[i] = pci_resource_start(dev, 2); + UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; + ConfigIO = pci_resource_start(dev, 1); + rcktpt_type[i] = ROCKET_TYPE_MODEMIII; break; - case PCI_DEVICE_ID_RPP8: - str = "Plus Octacable"; + case PCI_DEVICE_ID_UPCI_RM3_4PORT: + str = "4 ports"; max_num_aiops = 1; + rocketModel[i].model = MODEL_UPCI_RM3_4PORT; + strcpy(rocketModel[i].modelString, "RocketModem III 4 port"); + rocketModel[i].numPorts = 4; + rcktpt_io_addr[i] = pci_resource_start(dev, 2); + UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; + ConfigIO = pci_resource_start(dev, 1); + rcktpt_type[i] = ROCKET_TYPE_MODEMIII; break; - case PCI_DEVICE_ID_RP8M: - str = "8-port Modem"; - max_num_aiops = 1; + default: break; - case 0x8: - str = "mysterious 8 port"; - max_num_aiops = 1; + } + + switch (rcktpt_type[i]) { + case ROCKET_TYPE_MODEM: + board_type = "RocketModem"; + break; + case ROCKET_TYPE_MODEMII: + board_type = "RocketModem II"; + break; + case ROCKET_TYPE_MODEMIII: + board_type = "RocketModem III"; break; default: - str = "(unknown/unsupported)"; - max_num_aiops = 0; + board_type = "RocketPort"; break; } - for(aiop=0;aiop < max_num_aiops;aiop++) + + if (fast_clock) { + sClockPrescale = 0x12; /* mod 2 (divide by 3) */ + rp_baud_base[i] = 921600; + } else { + /* + * If support_low_speed is set, use the slow clock + * prescale, which supports 50 bps + */ + if (support_low_speed) { + /* mod 9 (divide by 10) prescale */ + sClockPrescale = 0x19; + rp_baud_base[i] = 230400; + } else { + /* mod 4 (devide by 5) prescale */ + sClockPrescale = 0x14; + rp_baud_base[i] = 460800; + } + } + + for (aiop = 0; aiop < max_num_aiops; aiop++) aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40); ctlp = sCtlNumToCtlPtr(i); - num_aiops = sPCIInitController(ctlp, i, - aiopio, max_num_aiops, 0, - FREQ_DIS, 0); - printk("Rocketport controller #%d found at %02x:%02x, " - "%d AIOP(s) (PCI Rocketport %s)\n", i, bus, device_fn, - num_aiops, str); - if(num_aiops <= 0) { + num_aiops = sPCIInitController(ctlp, i, aiopio, max_num_aiops, ConfigIO, 0, FREQ_DIS, 0, altChanRingIndicator, UPCIRingInd); + for (aiop = 0; aiop < max_num_aiops; aiop++) + ctlp->AiopNumChan[aiop] = ports_per_aiop; + +#if LINUX_VERSION_CODE < VERSION_CODE(2,3,99) + printk(KERN_INFO "Comtrol PCI controller #%d ID 0x%x found at 0x%lx, " + "%d AIOP(s) (%s)\n", i, dev->device, rcktpt_io_addr[i], + num_aiops, rocketModel[i].modelString); +#else + printk + ("Comtrol PCI controller #%d ID 0x%x found in bus:slot:fn %s at address %04lx, " + "%d AIOP(s) (%s)\n", i, dev->device, dev->slot_name, + rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString); +#endif + + printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n", + rocketModel[i].modelString, + rocketModel[i].startingPortNumber, + rocketModel[i].startingPortNumber + + rocketModel[i].numPorts - 1); + + if (num_aiops <= 0) { rcktpt_io_addr[i] = 0; - return(0); + return (0); } - for(aiop = 0;aiop < num_aiops; aiop++) { + is_PCI[i] = 1; + + /* Reset the AIOPIC, init the serial ports */ + for (aiop = 0; aiop < num_aiops; aiop++) { sResetAiopByNum(ctlp, aiop); - sEnAiop(ctlp, aiop); - num_chan = sGetAiopNumChan(ctlp, aiop); - for(chan=0;chan < num_chan; chan++) - init_r_port(i, aiop, chan); + num_chan = ports_per_aiop; + for (chan = 0; chan < num_chan; chan++) + init_r_port(i, aiop, chan, dev); + } + + /* Rocket modems must be reset */ + if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || + (rcktpt_type[i] == ROCKET_TYPE_MODEMII) || + (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) { + num_chan = ports_per_aiop; + for (chan = 0; chan < num_chan; chan++) + sPCIModemReset(ctlp, chan, 1); + mdelay(500); + for (chan = 0; chan < num_chan; chan++) + sPCIModemReset(ctlp, chan, 0); + mdelay(500); + rmSpeakerReset(ctlp, rocketModel[i].model); } - return(1); + return (1); } +#if LINUX_VERSION_CODE > VERSION_CODE(2,3,99) /* Linux version 2.4 and greater */ + + +/* + * Probes for PCI cards, inits them if found + * Input: board_found = number of ISA boards already found, or the + * starting board number + * Returns: Number of PCI boards found + */ static int __init init_PCI(int boards_found) { - unsigned char bus, device_fn; - int i, count = 0; + struct pci_dev *dev = NULL; + int count = 0; - for(i=0; i < (NUM_BOARDS - boards_found); i++) { - if (!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP4QUAD, i, &bus, &device_fn)) - if (register_PCI(count+boards_found, bus, device_fn)) - count++; - if (!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP8J, i, &bus, &device_fn)) - if (register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP8OCTA, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP8INTF, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP16INTF, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP32INTF, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP4QUAD, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP8J, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RPP4, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RPP8, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP8M, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - 0x8, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; + /* Work through the PCI device list, pulling out ours */ + while ((dev = pci_find_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) { + if (register_PCI(count + boards_found, dev)) + count++; } - return(count); + return (count); +} + +#else /* Linux version 2.2 */ + +/* + * Linux 2.2 pci_find_device() does not allow a search of all devices for a certain vendor, + * you have to try each device ID. Comtrol device ID's are 0x0000 -0x000F for the original + * boards. Newer board are 0x08xx (see upci_ids[]). + */ +static int __init init_PCI(int boards_found) +{ + int j, count = 0; + struct pci_dev *dev = NULL; + + static int upci_ids[] = { + PCI_DEVICE_ID_URP32INTF, + PCI_DEVICE_ID_URP8INTF, + PCI_DEVICE_ID_URP16INTF, + PCI_DEVICE_ID_CRP16INTF, + PCI_DEVICE_ID_URP8OCTA, + PCI_DEVICE_ID_UPCI_RM3_8PORT, + PCI_DEVICE_ID_UPCI_RM3_4PORT + }; + +#define NUM_UPCI_IDS (sizeof(upci_ids) / sizeof(upci_ids[0])) + + /* Try finding devices with PCI ID's 0x0000 - 0x000F */ + for (j = 0; j < 16; j++) { + while ((dev = pci_find_device(PCI_VENDOR_ID_RP, j, dev))) { + register_PCI(count + boards_found, dev); + count++; + } + } + + /* Now try finding the UPCI devices, which have PCI ID's 0x0800 - 0x080F */ + for (j = 0; j < NUM_UPCI_IDS; j++) { + while ((dev = + pci_find_device(PCI_VENDOR_ID_RP, upci_ids[j], dev))) { + register_PCI(count + boards_found, dev); + count++; + } + } + return (count); } -#endif +#endif /* Linux version 2.2/2.4 */ + +#endif /* CONFIG_PCI */ + +/* + * Probes for ISA cards + * Input: i = the board number to look for + * Returns: 1 if board found, 0 else + */ static int __init init_ISA(int i, int *reserved_controller) { - int num_aiops, num_chan; - int aiop, chan; - int extent = 0; - unsigned int aiopio[MAX_AIOPS_PER_BOARD]; - CONTROLLER_t *ctlp; + int num_aiops, num_chan = 0, total_num_chan = 0; + int aiop, chan; + unsigned int aiopio[MAX_AIOPS_PER_BOARD]; + CONTROLLER_t *ctlp; + char *type_string; - if (rcktpt_io_addr[i] == 0) - return(0); + if (rcktpt_io_addr[i] == 0 || controller == 0) + return (0); + if (check_region(rcktpt_io_addr[i], 64)) { + printk(KERN_INFO "RocketPort board address 0x%lx in use...\n", rcktpt_io_addr[i]); + rcktpt_io_addr[i] = 0; + return (0); + } if (rcktpt_io_addr[i] + 0x40 == controller) { *reserved_controller = 1; - extent = 68; + request_region(rcktpt_io_addr[i], 68, "Comtrol RocketPort"); } else { - extent = 64; + request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort"); } - if (!request_region(rcktpt_io_addr[i], extent, - "Comtrol Rocketport")) { - printk("RocketPort board address 0x%lx in use...\n", - rcktpt_io_addr[i]); - rcktpt_io_addr[i] = 0; - return(0); + + ctlp = sCtlNumToCtlPtr(i); + + ctlp->boardType = rcktpt_type[i]; + + switch (rcktpt_type[i]) { + case ROCKET_TYPE_PC104: + type_string = "(PC104)"; + break; + case ROCKET_TYPE_MODEM: + type_string = "(RocketModem)"; + break; + case ROCKET_TYPE_MODEMII: + type_string = "(RocketModem II)"; + break; + default: + type_string = ""; + break; } - - for (aiop=0; aiopboardType == ROCKET_TYPE_PC104) { + sEnAiop(ctlp, 2); /* only one AIOPIC, but these */ + sEnAiop(ctlp, 3); /* CSels used for other stuff */ + } + if (num_aiops <= 0) { - release_region(rcktpt_io_addr[i], extent); + if (rcktpt_io_addr[i] + 0x40 == controller) { + *reserved_controller = 0; + release_region(rcktpt_io_addr[i], 68); + } else { + release_region(rcktpt_io_addr[i], 64); + } rcktpt_io_addr[i] = 0; - return(0); + return (0); } for (aiop = 0; aiop < num_aiops; aiop++) { sResetAiopByNum(ctlp, aiop); sEnAiop(ctlp, aiop); - num_chan = sGetAiopNumChan(ctlp,aiop); - for (chan=0; chan < num_chan; chan++) - init_r_port(i, aiop, chan); - } - printk("Rocketport controller #%d found at 0x%lx, " - "%d AIOPs\n", i, rcktpt_io_addr[i], - num_aiops); - return(1); -} + num_chan = sGetAiopNumChan(ctlp, aiop); + total_num_chan += num_chan; + for (chan = 0; chan < num_chan; chan++) + init_r_port(i, aiop, chan, NULL); + } + is_PCI[i] = 0; + if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII)) { + num_chan = sGetAiopNumChan(ctlp, 0); + total_num_chan = num_chan; + for (chan = 0; chan < num_chan; chan++) + sModemReset(ctlp, chan, 1); + mdelay(500); + for (chan = 0; chan < num_chan; chan++) + sModemReset(ctlp, chan, 0); + mdelay(500); + strcpy(rocketModel[i].modelString, "RocketModem ISA"); + } else { + strcpy(rocketModel[i].modelString, "RocketPort ISA"); + } + rocketModel[i].numPorts = total_num_chan; + rocketModel[i].model = MODEL_ISA; + + printk(KERN_INFO "Comtrol ISA controller #%d found at 0x%lx, " + "%d AIOPs %s\n", i, rcktpt_io_addr[i], num_aiops, + type_string); + printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n", + rocketModel[i].modelString, + rocketModel[i].startingPortNumber, + rocketModel[i].startingPortNumber + + rocketModel[i].numPorts - 1); + return (1); +} /* * The module "startup" routine; it's run when the module is loaded. */ int __init rp_init(void) { - int i, retval, pci_boards_found, isa_boards_found; - int reserved_controller = 0; + int retval, pci_boards_found, isa_boards_found, i; + int reserved_controller = 0; - printk("Rocketport device driver module, version %s, %s\n", + printk(KERN_INFO "RocketPort device driver module, version %s, %s\n", ROCKET_VERSION, ROCKET_DATE); /* - * Set up the timer channel. If it is already in use by - * some other driver, give up. + * Set up the timer channel. */ - if (rocket_timer.function) { - printk("rocket.o: Timer already in use!\n"); - return -EBUSY; - } init_timer(&rocket_timer); rocket_timer.function = rp_do_poll; - + /* * Initialize the array of pointers to our own internal state * structures. */ - memset(rp_table, 0, sizeof(rp_table)); - memset(xmit_flags, 0, sizeof(xmit_flags)); + memset(rp_table, 0, sizeof (rp_table)); + memset(xmit_flags, 0, sizeof (xmit_flags)); + + for (i = 0; i < MAX_RP_PORTS; i++) + lineNumbers[i] = 0; + nextLineNumber = 0; + memset(rocketModel, 0, sizeof (rocketModel)); - if (board1 == 0) - board1 = 0x180; - if (controller == 0) + if (board1 && controller == 0) controller = board1 + 0x40; - if (check_region(controller, 4)) { - printk("Controller IO addresses in use, unloading driver.\n"); + if (controller && check_region(controller, 4)) { + printk(KERN_INFO "Controller IO addresses in use, unloading driver.\n"); return -EBUSY; } - + + /* Store ISA variable retrieved from command line or .conf file. */ rcktpt_io_addr[0] = board1; rcktpt_io_addr[1] = board2; rcktpt_io_addr[2] = board3; rcktpt_io_addr[3] = board4; - /* - * If support_low_speed is set, use the slow clock prescale, - * which supports 50 bps - */ - if (support_low_speed) { - sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */ - rp_baud_base = 230400; - } else { - sClockPrescale = 0x14; /* mod 4 (devide by 5) prescale */ - rp_baud_base = 460800; - } - - /* - * OK, let's probe each of the controllers looking for boards. - */ - isa_boards_found = 0; - pci_boards_found = 0; - for (i=0; i < NUM_BOARDS; i++) { - if(init_ISA(i, &reserved_controller)) - isa_boards_found++; - } -#ifdef CONFIG_PCI - if (pci_present()) { - if(isa_boards_found < NUM_BOARDS) - pci_boards_found = init_PCI(isa_boards_found); - } else { - printk("No PCI BIOS found\n"); - } -#endif - max_board = pci_boards_found + isa_boards_found; - - if (max_board == 0) { - printk("No rocketport ports found; unloading driver.\n"); - rocket_timer.function = 0; - return -ENODEV; - } - - if (reserved_controller == 0) - request_region(controller, 4, "Comtrol Rocketport"); + rcktpt_type[0] = modem1 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; + rcktpt_type[0] = pc104_1[0] ? ROCKET_TYPE_PC104 : rcktpt_type[0]; + rcktpt_type[1] = modem2 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; + rcktpt_type[1] = pc104_2[0] ? ROCKET_TYPE_PC104 : rcktpt_type[1]; + rcktpt_type[2] = modem3 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; + rcktpt_type[2] = pc104_3[0] ? ROCKET_TYPE_PC104 : rcktpt_type[2]; + rcktpt_type[3] = modem4 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; + rcktpt_type[3] = pc104_4[0] ? ROCKET_TYPE_PC104 : rcktpt_type[3]; /* * Set up the tty driver structure and then register this * driver with the tty layer. */ - memset(&rocket_driver, 0, sizeof(struct tty_driver)); + memset(&rocket_driver, 0, sizeof (struct tty_driver)); rocket_driver.magic = TTY_DRIVER_MAGIC; - rocket_driver.owner = THIS_MODULE; -#ifdef CONFIG_DEVFS_FS - rocket_driver.name = "tts/R"; -#else + rocket_driver.flags = TTY_DRIVER_NO_DEVFS; rocket_driver.name = "ttyR"; -#endif + rocket_driver.driver_name = "Comtrol RocketPort"; rocket_driver.major = TTY_ROCKET_MAJOR; rocket_driver.minor_start = 0; rocket_driver.num = MAX_RP_PORTS; @@ -1976,8 +2659,10 @@ rocket_driver.subtype = SERIAL_TYPE_NORMAL; rocket_driver.init_termios = tty_std_termios; rocket_driver.init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - rocket_driver.flags = TTY_DRIVER_REAL_RAW; + B9600 | CS8 | CREAD | HUPCL | CLOCAL; +#ifdef ROCKET_SOFT_FLOW + rocket_driver.flags |= TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; +#endif rocket_driver.refcount = &rocket_refcount; rocket_driver.table = rocket_table; rocket_driver.termios = rocket_termios; @@ -2001,58 +2686,93 @@ rocket_driver.send_xchar = rp_send_xchar; rocket_driver.wait_until_sent = rp_wait_until_sent; +#if (LINUX_VERSION_CODE > VERSION_CODE(2,5,0)) + rocket_driver.owner = THIS_MODULE; + rocket_driver.tiocmget = rp_tiocmget; + rocket_driver.tiocmset = rp_tiocmset; +#endif /* Kernel > 2.5 */ + retval = tty_register_driver(&rocket_driver); if (retval < 0) { - printk("Couldn't install tty Rocketport driver " - "(error %d)\n", -retval); - release_region(controller, 4); + printk(KERN_INFO "Couldn't install tty RocketPort driver (error %d)\n", -retval); return -1; } + #ifdef ROCKET_DEBUG_OPEN - printk("Rocketport driver is major %d\n", - rocket_driver.major); + printk(KERN_INFO "RocketPort driver is major %d\n", rocket_driver.major); +#endif + + /* + * OK, let's probe each of the controllers looking for boards. Any boards found + * will be initialized here. + */ + isa_boards_found = 0; + pci_boards_found = 0; + + for (i = 0; i < NUM_BOARDS; i++) { + if (init_ISA(i, &reserved_controller)) + isa_boards_found++; + } + +#ifdef CONFIG_PCI + if (pci_present()) { + if (isa_boards_found < NUM_BOARDS) + pci_boards_found = init_PCI(isa_boards_found); + } else { + printk(KERN_INFO "No PCI BIOS found\n"); + } #endif + max_board = pci_boards_found + isa_boards_found; + + if (max_board == 0) { + printk(KERN_INFO "No rocketport ports found; unloading driver.\n"); + del_timer_sync(&rocket_timer); + return -ENXIO; + } + + if (isa_boards_found) { + if (reserved_controller == 0) + request_region(controller, 4, "Comtrol RocketPort"); + } else { + controller = 0; + } + return 0; } #ifdef MODULE -int init_module(void) -{ - return rp_init(); -} -void -cleanup_module( void) { - int retval; - int i; - int released_controller = 0; +static void rp_cleanup_module(void) +{ + int retval; + int i; + int released_controller = 0; del_timer_sync(&rocket_timer); retval = tty_unregister_driver(&rocket_driver); - if (retval) { - printk("Error %d while trying to unregister " + if (retval) + printk(KERN_INFO "Error %d while trying to unregister " "rocketport driver\n", -retval); - } + for (i = 0; i < MAX_RP_PORTS; i++) { if (rp_table[i]) kfree(rp_table[i]); } - for (i=0; i < NUM_BOARDS; i++) { - if (rcktpt_io_addr[i] <= 0) + + for (i = 0; i < NUM_BOARDS; i++) { + if (rcktpt_io_addr[i] <= 0 || is_PCI[i]) continue; if (rcktpt_io_addr[i] + 0x40 == controller) { released_controller++; release_region(rcktpt_io_addr[i], 68); - } else + } else { release_region(rcktpt_io_addr[i], 64); - if (released_controller == 0) - release_region(controller, 4); + } } - if (tmp_buf) - free_page((unsigned long) tmp_buf); - rocket_timer.function = 0; + if (controller && released_controller == 0) + release_region(controller, 4); } #endif @@ -2088,69 +2808,60 @@ #define FALSE 0 #endif -static Byte_t RData[RDATASIZE] = -{ - 0x00, 0x09, 0xf6, 0x82, - 0x02, 0x09, 0x86, 0xfb, - 0x04, 0x09, 0x00, 0x0a, - 0x06, 0x09, 0x01, 0x0a, - 0x08, 0x09, 0x8a, 0x13, - 0x0a, 0x09, 0xc5, 0x11, - 0x0c, 0x09, 0x86, 0x85, - 0x0e, 0x09, 0x20, 0x0a, - 0x10, 0x09, 0x21, 0x0a, - 0x12, 0x09, 0x41, 0xff, - 0x14, 0x09, 0x82, 0x00, - 0x16, 0x09, 0x82, 0x7b, - 0x18, 0x09, 0x8a, 0x7d, - 0x1a, 0x09, 0x88, 0x81, - 0x1c, 0x09, 0x86, 0x7a, - 0x1e, 0x09, 0x84, 0x81, - 0x20, 0x09, 0x82, 0x7c, - 0x22, 0x09, 0x0a, 0x0a -}; - -static Byte_t RRegData[RREGDATASIZE]= -{ - 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ - 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ - 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ - 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ - 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ - 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ - 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ - 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ - 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ - 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ - 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ - 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ - 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ +static Byte_t RData[RDATASIZE] = { + 0x00, 0x09, 0xf6, 0x82, + 0x02, 0x09, 0x86, 0xfb, + 0x04, 0x09, 0x00, 0x0a, + 0x06, 0x09, 0x01, 0x0a, + 0x08, 0x09, 0x8a, 0x13, + 0x0a, 0x09, 0xc5, 0x11, + 0x0c, 0x09, 0x86, 0x85, + 0x0e, 0x09, 0x20, 0x0a, + 0x10, 0x09, 0x21, 0x0a, + 0x12, 0x09, 0x41, 0xff, + 0x14, 0x09, 0x82, 0x00, + 0x16, 0x09, 0x82, 0x7b, + 0x18, 0x09, 0x8a, 0x7d, + 0x1a, 0x09, 0x88, 0x81, + 0x1c, 0x09, 0x86, 0x7a, + 0x1e, 0x09, 0x84, 0x81, + 0x20, 0x09, 0x82, 0x7c, + 0x22, 0x09, 0x0a, 0x0a }; -CONTROLLER_T sController[CTL_SIZE] = -{ - {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}}, - {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}}, - {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}}, - {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}} +static Byte_t RRegData[RREGDATASIZE] = { + 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ + 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ + 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ + 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ + 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ + 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ + 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ + 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ + 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ + 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ + 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ + 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ + 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ }; -#if 0 -/* IRQ number to MUDBAC register 2 mapping */ -Byte_t sIRQMap[16] = -{ - 0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80 +CONTROLLER_T sController[CTL_SIZE] = { + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}} }; -#endif -Byte_t sBitMapClrTbl[8] = -{ - 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f +Byte_t sBitMapClrTbl[8] = { + 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; -Byte_t sBitMapSetTbl[8] = -{ - 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 +Byte_t sBitMapSetTbl[8] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; int sClockPrescale = 0x14; @@ -2225,76 +2936,68 @@ After this function all AIOPs on the controller are disabled, they can be enabled with sEnAiop(). */ -int sInitController( CONTROLLER_T *CtlP, - int CtlNum, - ByteIO_t MudbacIO, - ByteIO_t *AiopIOList, - int AiopIOListSize, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly) -{ - int i; - ByteIO_t io; - - CtlP->CtlNum = CtlNum; - CtlP->CtlID = CTLID_0001; /* controller release 1 */ - CtlP->BusType = isISA; - CtlP->MBaseIO = MudbacIO; - CtlP->MReg1IO = MudbacIO + 1; - CtlP->MReg2IO = MudbacIO + 2; - CtlP->MReg3IO = MudbacIO + 3; +int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, + ByteIO_t * AiopIOList, int AiopIOListSize, int IRQNum, + Byte_t Frequency, int PeriodicOnly) +{ + int i; + ByteIO_t io; + int done; + + CtlP->AiopIntrBits = aiop_intr_bits; + CtlP->AltChanRingIndicator = 0; + CtlP->CtlNum = CtlNum; + CtlP->CtlID = CTLID_0001; /* controller release 1 */ + CtlP->BusType = isISA; + CtlP->MBaseIO = MudbacIO; + CtlP->MReg1IO = MudbacIO + 1; + CtlP->MReg2IO = MudbacIO + 2; + CtlP->MReg3IO = MudbacIO + 3; #if 1 - CtlP->MReg2 = 0; /* interrupt disable */ - CtlP->MReg3 = 0; /* no periodic interrupts */ + CtlP->MReg2 = 0; /* interrupt disable */ + CtlP->MReg3 = 0; /* no periodic interrupts */ #else - if(sIRQMap[IRQNum] == 0) /* interrupts globally disabled */ - { - CtlP->MReg2 = 0; /* interrupt disable */ - CtlP->MReg3 = 0; /* no periodic interrupts */ - } - else - { - CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */ - CtlP->MReg3 = Frequency; /* set frequency */ - if(PeriodicOnly) /* periodic interrupt only */ - { - CtlP->MReg3 |= PERIODIC_ONLY; - } - } -#endif - sOutB(CtlP->MReg2IO,CtlP->MReg2); - sOutB(CtlP->MReg3IO,CtlP->MReg3); - sControllerEOI(CtlP); /* clear EOI if warm init */ - /* Init AIOPs */ - CtlP->NumAiop = 0; - for(i=0; i < AiopIOListSize; i++) - { - io = AiopIOList[i]; - CtlP->AiopIO[i] = (WordIO_t)io; - CtlP->AiopIntChanIO[i] = io + _INT_CHAN; - sOutB(CtlP->MReg2IO,CtlP->MReg2 | (i & 0x03)); /* AIOP index */ - sOutB(MudbacIO,(Byte_t)(io >> 6)); /* set up AIOP I/O in MUDBAC */ - sEnAiop(CtlP,i); /* enable the AIOP */ - - CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ - if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ - { - sDisAiop(CtlP,i); /* disable AIOP */ - break; /* done looking for AIOPs */ - } - - CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t)io); /* num channels in AIOP */ - sOutW((WordIO_t)io + _INDX_ADDR,_CLK_PRE); /* clock prescaler */ - sOutB(io + _INDX_DATA,sClockPrescale); - CtlP->NumAiop++; /* bump count of AIOPs */ - sDisAiop(CtlP,i); /* disable AIOP */ - } - - if(CtlP->NumAiop == 0) - return(-1); - else - return(CtlP->NumAiop); + if (sIRQMap[IRQNum] == 0) { /* interrupts globally disabled */ + CtlP->MReg2 = 0; /* interrupt disable */ + CtlP->MReg3 = 0; /* no periodic interrupts */ + } else { + CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */ + CtlP->MReg3 = Frequency; /* set frequency */ + if (PeriodicOnly) { /* periodic interrupt only */ + CtlP->MReg3 |= PERIODIC_ONLY; + } + } +#endif + sOutB(CtlP->MReg2IO, CtlP->MReg2); + sOutB(CtlP->MReg3IO, CtlP->MReg3); + sControllerEOI(CtlP); /* clear EOI if warm init */ + /* Init AIOPs */ + CtlP->NumAiop = 0; + for (i = done = 0; i < AiopIOListSize; i++) { + io = AiopIOList[i]; + CtlP->AiopIO[i] = (WordIO_t) io; + CtlP->AiopIntChanIO[i] = io + _INT_CHAN; + sOutB(CtlP->MReg2IO, CtlP->MReg2 | (i & 0x03)); /* AIOP index */ + sOutB(MudbacIO, (Byte_t) (io >> 6)); /* set up AIOP I/O in MUDBAC */ + if (done) + continue; + sEnAiop(CtlP, i); /* enable the AIOP */ + CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ + if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ + done = 1; /* done looking for AIOPs */ + else { + CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ + sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ + sOutB(io + _INDX_DATA, sClockPrescale); + CtlP->NumAiop++; /* bump count of AIOPs */ + } + sDisAiop(CtlP, i); /* disable AIOP */ + } + + if (CtlP->NumAiop == 0) + return (-1); + else + return (CtlP->NumAiop); } /*************************************************************************** @@ -2366,46 +3069,55 @@ After this function all AIOPs on the controller are disabled, they can be enabled with sEnAiop(). */ -int sPCIInitController( CONTROLLER_T *CtlP, - int CtlNum, - ByteIO_t *AiopIOList, - int AiopIOListSize, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly) -{ - int i; - ByteIO_t io; - - CtlP->CtlNum = CtlNum; - CtlP->CtlID = CTLID_0001; /* controller release 1 */ - CtlP->BusType = isPCI; /* controller release 1 */ - - CtlP->PCIIO = (WordIO_t)((ByteIO_t)AiopIOList[0] + _PCI_INT_FUNC); - - sPCIControllerEOI(CtlP); /* clear EOI if warm init */ - /* Init AIOPs */ - CtlP->NumAiop = 0; - for(i=0; i < AiopIOListSize; i++) - { - io = AiopIOList[i]; - CtlP->AiopIO[i] = (WordIO_t)io; - CtlP->AiopIntChanIO[i] = io + _INT_CHAN; - - CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ - if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ - break; /* done looking for AIOPs */ - - CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t)io); /* num channels in AIOP */ - sOutW((WordIO_t)io + _INDX_ADDR,_CLK_PRE); /* clock prescaler */ - sOutB(io + _INDX_DATA,sClockPrescale); - CtlP->NumAiop++; /* bump count of AIOPs */ - } - - if(CtlP->NumAiop == 0) - return(-1); - else - return(CtlP->NumAiop); +int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, + ByteIO_t * AiopIOList, int AiopIOListSize, + WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, + int PeriodicOnly, int altChanRingIndicator, + int UPCIRingInd) +{ + int i; + ByteIO_t io; + + CtlP->AltChanRingIndicator = altChanRingIndicator; + CtlP->UPCIRingInd = UPCIRingInd; + CtlP->CtlNum = CtlNum; + CtlP->CtlID = CTLID_0001; /* controller release 1 */ + CtlP->BusType = isPCI; /* controller release 1 */ + + if (ConfigIO) { + CtlP->isUPCI = 1; + CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL; + CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL; + CtlP->AiopIntrBits = upci_aiop_intr_bits; + } else { + CtlP->isUPCI = 0; + CtlP->PCIIO = + (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC); + CtlP->AiopIntrBits = aiop_intr_bits; + } + + sPCIControllerEOI(CtlP); /* clear EOI if warm init */ + /* Init AIOPs */ + CtlP->NumAiop = 0; + for (i = 0; i < AiopIOListSize; i++) { + io = AiopIOList[i]; + CtlP->AiopIO[i] = (WordIO_t) io; + CtlP->AiopIntChanIO[i] = io + _INT_CHAN; + + CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ + if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ + break; /* done looking for AIOPs */ + + CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ + sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ + sOutB(io + _INDX_DATA, sClockPrescale); + CtlP->NumAiop++; /* bump count of AIOPs */ + } + + if (CtlP->NumAiop == 0) + return (-1); + else + return (CtlP->NumAiop); } /*************************************************************************** @@ -2421,15 +3133,15 @@ */ int sReadAiopID(ByteIO_t io) { - Byte_t AiopID; /* ID byte from AIOP */ + Byte_t AiopID; /* ID byte from AIOP */ - sOutB(io + _CMD_REG,RESET_ALL); /* reset AIOP */ - sOutB(io + _CMD_REG,0x0); - AiopID = sInB(io + _CHN_STAT0) & 0x07; - if(AiopID == 0x06) - return(1); - else /* AIOP does not exist */ - return(-1); + sOutB(io + _CMD_REG, RESET_ALL); /* reset AIOP */ + sOutB(io + _CMD_REG, 0x0); + AiopID = sInW(io + _CHN_STAT0) & 0x07; + if (AiopID == 0x06) + return (1); + else /* AIOP does not exist */ + return (-1); } /*************************************************************************** @@ -2447,16 +3159,18 @@ */ int sReadAiopNumChan(WordIO_t io) { - Word_t x; + Word_t x; + static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 }; - sOutDW((DWordIO_t)io + _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */ - sOutW(io + _INDX_ADDR,0); /* read from SRAM, chan 0 */ - x = sInW(io + _INDX_DATA); - sOutW(io + _INDX_ADDR,0x4000); /* read from SRAM, chan 4 */ - if(x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */ - return(8); - else - return(4); + /* write to chan 0 SRAM */ + sOutDW((DWordIO_t) io + _INDX_ADDR, *((DWord_t *) & R[0])); + sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */ + x = sInW(io + _INDX_DATA); + sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */ + if (x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */ + return (8); + else + return (4); } /*************************************************************************** @@ -2474,138 +3188,134 @@ No context switches are allowed while executing this function. */ -int sInitChan( CONTROLLER_T *CtlP, - CHANNEL_T *ChP, - int AiopNum, - int ChanNum) -{ - int i; - WordIO_t AiopIO; - WordIO_t ChIOOff; - Byte_t *ChR; - Word_t ChOff; - static Byte_t R[4]; - int brd9600; - - if(ChanNum >= CtlP->AiopNumChan[AiopNum]) - return(FALSE); /* exceeds num chans in AIOP */ - - /* Channel, AIOP, and controller identifiers */ - ChP->CtlP = CtlP; - ChP->ChanID = CtlP->AiopID[AiopNum]; - ChP->AiopNum = AiopNum; - ChP->ChanNum = ChanNum; - - /* Global direct addresses */ - AiopIO = CtlP->AiopIO[AiopNum]; - ChP->Cmd = (ByteIO_t)AiopIO + _CMD_REG; - ChP->IntChan = (ByteIO_t)AiopIO + _INT_CHAN; - ChP->IntMask = (ByteIO_t)AiopIO + _INT_MASK; - ChP->IndexAddr = (DWordIO_t)AiopIO + _INDX_ADDR; - ChP->IndexData = AiopIO + _INDX_DATA; - - /* Channel direct addresses */ - ChIOOff = AiopIO + ChP->ChanNum * 2; - ChP->TxRxData = ChIOOff + _TD0; - ChP->ChanStat = ChIOOff + _CHN_STAT0; - ChP->TxRxCount = ChIOOff + _FIFO_CNT0; - ChP->IntID = (ByteIO_t)AiopIO + ChP->ChanNum + _INT_ID0; - - /* Initialize the channel from the RData array */ - for(i=0; i < RDATASIZE; i+=4) - { - R[0] = RData[i]; - R[1] = RData[i+1] + 0x10 * ChanNum; - R[2] = RData[i+2]; - R[3] = RData[i+3]; - sOutDW(ChP->IndexAddr,*((DWord_t *)&R[0])); - } - - ChR = ChP->R; - for(i=0; i < RREGDATASIZE; i+=4) - { - ChR[i] = RRegData[i]; - ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum; - ChR[i+2] = RRegData[i+2]; - ChR[i+3] = RRegData[i+3]; - } - - /* Indexed registers */ - ChOff = (Word_t)ChanNum * 0x1000; - - if (sClockPrescale == 0x14) - brd9600 = 47; - else - brd9600 = 23; - - ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD); - ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8); - ChP->BaudDiv[2] = (Byte_t)brd9600; - ChP->BaudDiv[3] = (Byte_t)(brd9600 >> 8); - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->BaudDiv[0]); - - ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL); - ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8); - ChP->TxControl[2] = 0; - ChP->TxControl[3] = 0; - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]); - - ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL); - ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8); - ChP->RxControl[2] = 0; - ChP->RxControl[3] = 0; - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]); - - ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS); - ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8); - ChP->TxEnables[2] = 0; - ChP->TxEnables[3] = 0; - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxEnables[0]); - - ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1); - ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8); - ChP->TxCompare[2] = 0; - ChP->TxCompare[3] = 0; - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxCompare[0]); - - ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1); - ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8); - ChP->TxReplace1[2] = 0; - ChP->TxReplace1[3] = 0; - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxReplace1[0]); - - ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2); - ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8); - ChP->TxReplace2[2] = 0; - ChP->TxReplace2[3] = 0; - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxReplace2[0]); - - ChP->TxFIFOPtrs = ChOff + _TXF_OUTP; - ChP->TxFIFO = ChOff + _TX_FIFO; - - sOutB(ChP->Cmd,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */ - sOutB(ChP->Cmd,(Byte_t)ChanNum); /* remove reset Tx FIFO count */ - sOutW((WordIO_t)ChP->IndexAddr,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ - sOutW(ChP->IndexData,0); - ChP->RxFIFOPtrs = ChOff + _RXF_OUTP; - ChP->RxFIFO = ChOff + _RX_FIFO; - - sOutB(ChP->Cmd,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */ - sOutB(ChP->Cmd,(Byte_t)ChanNum); /* remove reset Rx FIFO count */ - sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs); /* clear Rx out ptr */ - sOutW(ChP->IndexData,0); - sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ - sOutW(ChP->IndexData,0); - ChP->TxPrioCnt = ChOff + _TXP_CNT; - sOutW((WordIO_t)ChP->IndexAddr,ChP->TxPrioCnt); - sOutB(ChP->IndexData,0); - ChP->TxPrioPtr = ChOff + _TXP_PNTR; - sOutW((WordIO_t)ChP->IndexAddr,ChP->TxPrioPtr); - sOutB(ChP->IndexData,0); - ChP->TxPrioBuf = ChOff + _TXP_BUF; - sEnRxProcessor(ChP); /* start the Rx processor */ +int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, + int ChanNum) +{ + int i; + WordIO_t AiopIO; + WordIO_t ChIOOff; + Byte_t *ChR; + Word_t ChOff; + static Byte_t R[4]; + int brd9600; + + if (ChanNum >= CtlP->AiopNumChan[AiopNum]) + return (FALSE); /* exceeds num chans in AIOP */ + + /* Channel, AIOP, and controller identifiers */ + ChP->CtlP = CtlP; + ChP->ChanID = CtlP->AiopID[AiopNum]; + ChP->AiopNum = AiopNum; + ChP->ChanNum = ChanNum; + + /* Global direct addresses */ + AiopIO = CtlP->AiopIO[AiopNum]; + ChP->Cmd = (ByteIO_t) AiopIO + _CMD_REG; + ChP->IntChan = (ByteIO_t) AiopIO + _INT_CHAN; + ChP->IntMask = (ByteIO_t) AiopIO + _INT_MASK; + ChP->IndexAddr = (DWordIO_t) AiopIO + _INDX_ADDR; + ChP->IndexData = AiopIO + _INDX_DATA; + + /* Channel direct addresses */ + ChIOOff = AiopIO + ChP->ChanNum * 2; + ChP->TxRxData = ChIOOff + _TD0; + ChP->ChanStat = ChIOOff + _CHN_STAT0; + ChP->TxRxCount = ChIOOff + _FIFO_CNT0; + ChP->IntID = (ByteIO_t) AiopIO + ChP->ChanNum + _INT_ID0; + + /* Initialize the channel from the RData array */ + for (i = 0; i < RDATASIZE; i += 4) { + R[0] = RData[i]; + R[1] = RData[i + 1] + 0x10 * ChanNum; + R[2] = RData[i + 2]; + R[3] = RData[i + 3]; + sOutDW(ChP->IndexAddr, *((DWord_t *) & R[0])); + } + + ChR = ChP->R; + for (i = 0; i < RREGDATASIZE; i += 4) { + ChR[i] = RRegData[i]; + ChR[i + 1] = RRegData[i + 1] + 0x10 * ChanNum; + ChR[i + 2] = RRegData[i + 2]; + ChR[i + 3] = RRegData[i + 3]; + } + + /* Indexed registers */ + ChOff = (Word_t) ChanNum *0x1000; + + if (sClockPrescale == 0x14) + brd9600 = 47; + else + brd9600 = 23; + + ChP->BaudDiv[0] = (Byte_t) (ChOff + _BAUD); + ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8); + ChP->BaudDiv[2] = (Byte_t) brd9600; + ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8); + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->BaudDiv[0]); + + ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL); + ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8); + ChP->TxControl[2] = 0; + ChP->TxControl[3] = 0; + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxControl[0]); + + ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL); + ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8); + ChP->RxControl[2] = 0; + ChP->RxControl[3] = 0; + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->RxControl[0]); + + ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS); + ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8); + ChP->TxEnables[2] = 0; + ChP->TxEnables[3] = 0; + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxEnables[0]); + + ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1); + ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8); + ChP->TxCompare[2] = 0; + ChP->TxCompare[3] = 0; + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxCompare[0]); + + ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1); + ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8); + ChP->TxReplace1[2] = 0; + ChP->TxReplace1[3] = 0; + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxReplace1[0]); + + ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2); + ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8); + ChP->TxReplace2[2] = 0; + ChP->TxReplace2[3] = 0; + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxReplace2[0]); + + ChP->TxFIFOPtrs = ChOff + _TXF_OUTP; + ChP->TxFIFO = ChOff + _TX_FIFO; + + sOutB(ChP->Cmd, (Byte_t) ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */ + sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Tx FIFO count */ + sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ + sOutW(ChP->IndexData, 0); + ChP->RxFIFOPtrs = ChOff + _RXF_OUTP; + ChP->RxFIFO = ChOff + _RX_FIFO; + + sOutB(ChP->Cmd, (Byte_t) ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */ + sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Rx FIFO count */ + sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */ + sOutW(ChP->IndexData, 0); + sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ + sOutW(ChP->IndexData, 0); + ChP->TxPrioCnt = ChOff + _TXP_CNT; + sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioCnt); + sOutB(ChP->IndexData, 0); + ChP->TxPrioPtr = ChOff + _TXP_PNTR; + sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioPtr); + sOutB(ChP->IndexData, 0); + ChP->TxPrioBuf = ChOff + _TXP_BUF; + sEnRxProcessor(ChP); /* start the Rx processor */ - return(TRUE); + return (TRUE); } /*************************************************************************** @@ -2626,15 +3336,15 @@ After calling this function a delay of 4 uS is required to ensure that the receive processor is no longer processing this channel. */ -void sStopRxProcessor(CHANNEL_T *ChP) +void sStopRxProcessor(CHANNEL_T * ChP) { - Byte_t R[4]; + Byte_t R[4]; - R[0] = ChP->R[0]; - R[1] = ChP->R[1]; - R[2] = 0x0a; - R[3] = ChP->R[3]; - sOutDW(ChP->IndexAddr,*(DWord_t *)&R[0]); + R[0] = ChP->R[0]; + R[1] = ChP->R[1]; + R[2] = 0x0a; + R[3] = ChP->R[3]; + sOutDW(ChP->IndexAddr, *(DWord_t *) & R[0]); } /*************************************************************************** @@ -2651,33 +3361,32 @@ this function. Warnings: No context switches are allowed while executing this function. */ -void sFlushRxFIFO(CHANNEL_T *ChP) +void sFlushRxFIFO(CHANNEL_T * ChP) { - int i; - Byte_t Ch; /* channel number within AIOP */ - int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */ - - if(sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ - return; /* don't need to flush */ - - RxFIFOEnabled = FALSE; - if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */ - { - RxFIFOEnabled = TRUE; - sDisRxFIFO(ChP); /* disable it */ - for(i=0; i < 2000/200; i++) /* delay 2 uS to allow proc to disable FIFO*/ - sInB(ChP->IntChan); /* depends on bus i/o timing */ - } - sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */ - Ch = (Byte_t)sGetChanNum(ChP); - sOutB(ChP->Cmd,Ch | RESRXFCNT); /* apply reset Rx FIFO count */ - sOutB(ChP->Cmd,Ch); /* remove reset Rx FIFO count */ - sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs); /* clear Rx out ptr */ - sOutW(ChP->IndexData,0); - sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ - sOutW(ChP->IndexData,0); - if(RxFIFOEnabled) - sEnRxFIFO(ChP); /* enable Rx FIFO */ + int i; + Byte_t Ch; /* channel number within AIOP */ + int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */ + + if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ + return; /* don't need to flush */ + + RxFIFOEnabled = FALSE; + if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */ + RxFIFOEnabled = TRUE; + sDisRxFIFO(ChP); /* disable it */ + for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */ + sInB(ChP->IntChan); /* depends on bus i/o timing */ + } + sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */ + Ch = (Byte_t) sGetChanNum(ChP); + sOutB(ChP->Cmd, Ch | RESRXFCNT); /* apply reset Rx FIFO count */ + sOutB(ChP->Cmd, Ch); /* remove reset Rx FIFO count */ + sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */ + sOutW(ChP->IndexData, 0); + sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ + sOutW(ChP->IndexData, 0); + if (RxFIFOEnabled) + sEnRxFIFO(ChP); /* enable Rx FIFO */ } /*************************************************************************** @@ -2694,32 +3403,31 @@ this function. Warnings: No context switches are allowed while executing this function. */ -void sFlushTxFIFO(CHANNEL_T *ChP) +void sFlushTxFIFO(CHANNEL_T * ChP) { - int i; - Byte_t Ch; /* channel number within AIOP */ - int TxEnabled; /* TRUE if transmitter enabled */ - - if(sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ - return; /* don't need to flush */ - - TxEnabled = FALSE; - if(ChP->TxControl[3] & TX_ENABLE) - { - TxEnabled = TRUE; - sDisTransmit(ChP); /* disable transmitter */ - } - sStopRxProcessor(ChP); /* stop Rx processor */ - for(i = 0; i < 4000/200; i++) /* delay 4 uS to allow proc to stop */ - sInB(ChP->IntChan); /* depends on bus i/o timing */ - Ch = (Byte_t)sGetChanNum(ChP); - sOutB(ChP->Cmd,Ch | RESTXFCNT); /* apply reset Tx FIFO count */ - sOutB(ChP->Cmd,Ch); /* remove reset Tx FIFO count */ - sOutW((WordIO_t)ChP->IndexAddr,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ - sOutW(ChP->IndexData,0); - if(TxEnabled) - sEnTransmit(ChP); /* enable transmitter */ - sStartRxProcessor(ChP); /* restart Rx processor */ + int i; + Byte_t Ch; /* channel number within AIOP */ + int TxEnabled; /* TRUE if transmitter enabled */ + + if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ + return; /* don't need to flush */ + + TxEnabled = FALSE; + if (ChP->TxControl[3] & TX_ENABLE) { + TxEnabled = TRUE; + sDisTransmit(ChP); /* disable transmitter */ + } + sStopRxProcessor(ChP); /* stop Rx processor */ + for (i = 0; i < 4000 / 200; i++) /* delay 4 uS to allow proc to stop */ + sInB(ChP->IntChan); /* depends on bus i/o timing */ + Ch = (Byte_t) sGetChanNum(ChP); + sOutB(ChP->Cmd, Ch | RESTXFCNT); /* apply reset Tx FIFO count */ + sOutB(ChP->Cmd, Ch); /* remove reset Tx FIFO count */ + sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ + sOutW(ChP->IndexData, 0); + if (TxEnabled) + sEnTransmit(ChP); /* enable transmitter */ + sStartRxProcessor(ChP); /* restart Rx processor */ } /*************************************************************************** @@ -2735,36 +3443,34 @@ Warnings: No context switches are allowed while executing this function. */ -int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data) +int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data) { - Byte_t DWBuf[4]; /* buffer for double word writes */ - Word_t *WordPtr; /* must be far because Win SS != DS */ - register DWordIO_t IndexAddr; - - if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */ - { - IndexAddr = ChP->IndexAddr; - sOutW((WordIO_t)IndexAddr,ChP->TxPrioCnt); /* get priority buffer status */ - if(sInB((ByteIO_t)ChP->IndexData) & PRI_PEND) /* priority buffer busy */ - return(0); /* nothing sent */ - - WordPtr = (Word_t *)(&DWBuf[0]); - *WordPtr = ChP->TxPrioBuf; /* data byte address */ - - DWBuf[2] = Data; /* data byte value */ - sOutDW(IndexAddr,*((DWord_t *)(&DWBuf[0]))); /* write it out */ - - *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */ - - DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */ - DWBuf[3] = 0; /* priority buffer pointer */ - sOutDW(IndexAddr,*((DWord_t *)(&DWBuf[0]))); /* write it out */ - } - else /* write it to Tx FIFO */ - { - sWriteTxByte(sGetTxRxDataIO(ChP),Data); - } - return(1); /* 1 byte sent */ + Byte_t DWBuf[4]; /* buffer for double word writes */ + Word_t *WordPtr; /* must be far because Win SS != DS */ + register DWordIO_t IndexAddr; + + if (sGetTxCnt(ChP) > 1) { /* write it to Tx priority buffer */ + IndexAddr = ChP->IndexAddr; + sOutW((WordIO_t) IndexAddr, ChP->TxPrioCnt); /* get priority buffer status */ + if (sInB((ByteIO_t) ChP->IndexData) & PRI_PEND) /* priority buffer busy */ + return (0); /* nothing sent */ + + WordPtr = (Word_t *) (&DWBuf[0]); + *WordPtr = ChP->TxPrioBuf; /* data byte address */ + + DWBuf[2] = Data; /* data byte value */ + sOutDW(IndexAddr, *((DWord_t *) (&DWBuf[0]))); /* write it out */ + + *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */ + + DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */ + DWBuf[3] = 0; /* priority buffer pointer */ + sOutDW(IndexAddr, *((DWord_t *) (&DWBuf[0]))); /* write it out */ + } else { /* write it to Tx FIFO */ + + sWriteTxByte(sGetTxRxDataIO(ChP), Data); + } + return (1); /* 1 byte sent */ } /*************************************************************************** @@ -2799,24 +3505,23 @@ enable channel interrupts. This would allow the global interrupt status register to be used to determine which AIOPs need service. */ -void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags) +void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags) { - Byte_t Mask; /* Interrupt Mask Register */ + Byte_t Mask; /* Interrupt Mask Register */ - ChP->RxControl[2] |= - ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); + ChP->RxControl[2] |= + ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]); + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->RxControl[0]); - ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN); + ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN); - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]); + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxControl[0]); - if(Flags & CHANINT_EN) - { - Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum]; - sOutB(ChP->IntMask,Mask); - } + if (Flags & CHANINT_EN) { + Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum]; + sOutB(ChP->IntMask, Mask); + } } /*************************************************************************** @@ -2844,19 +3549,98 @@ this channel's bit from being set in the AIOP's Interrupt Channel Register. */ -void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags) +void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) { - Byte_t Mask; /* Interrupt Mask Register */ + Byte_t Mask; /* Interrupt Mask Register */ - ChP->RxControl[2] &= - ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]); - ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN); - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]); - - if(Flags & CHANINT_EN) - { - Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum]; - sOutB(ChP->IntMask,Mask); - } + ChP->RxControl[2] &= + ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->RxControl[0]); + ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN); + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxControl[0]); + + if (Flags & CHANINT_EN) { + Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum]; + sOutB(ChP->IntMask, Mask); + } +} + +void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) +{ + sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum); +} + +/* + * Not an official SSCI function, but how to reset RocketModems. + * ISA bus version + */ +void sModemReset(CONTROLLER_T * CtlP, int chan, int on) +{ + ByteIO_t addr; + Byte_t val; + + addr = CtlP->AiopIO[0] + 0x400; + val = sInB(CtlP->MReg3IO); + /* if AIOP[1] is not enabled, enable it */ + if ((val & 2) == 0) { + val = sInB(CtlP->MReg2IO); + sOutB(CtlP->MReg2IO, (val & 0xfc) | (1 & 0x03)); + sOutB(CtlP->MBaseIO, (unsigned char) (addr >> 6)); + } + + sEnAiop(CtlP, 1); + if (!on) + addr += 8; + sOutB(addr + chan, 0); /* apply or remove reset */ + sDisAiop(CtlP, 1); +} + +/* + * Not an official SSCI function, but how to reset RocketModems. + * PCI bus version + */ +void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on) +{ + ByteIO_t addr; + + addr = CtlP->AiopIO[0] + 0x40; /* 2nd AIOP */ + if (!on) + addr += 8; + sOutB(addr + chan, 0); /* apply or remove reset */ +} + +/* Resets the speaker controller on RocketModem II and III devices */ +static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model) +{ + ByteIO_t addr; + + /* RocketModem II speaker control is at the 8th port location of offset 0x40 */ + if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) { + addr = CtlP->AiopIO[0] + 0x4F; + sOutB(addr, 0); + } + + /* RocketModem III speaker control is at the 1st port location of offset 0x80 */ + if ((model == MODEL_UPCI_RM3_8PORT) + || (model == MODEL_UPCI_RM3_4PORT)) { + addr = CtlP->AiopIO[0] + 0x88; + sOutB(addr, 0); + } +} + +/* Returns the line number given the controller (board), aiop and channel number */ +static unsigned char GetLineNumber(int ctrl, int aiop, int ch) +{ + return lineNumbers[(ctrl << 5) | (aiop << 3) | ch]; +} + +/* + * Stores the line number associated with a given controller (board), aiop + * and channel number. + * Returns: The line number assigned + */ +static unsigned char SetLineNumber(int ctrl, int aiop, int ch) +{ + lineNumbers[(ctrl << 5) | (aiop << 3) | ch] = nextLineNumber++; + return (nextLineNumber - 1); } diff -urN linux-2.5.70-bk10/drivers/char/rocket.h linux-2.5.70-bk11/drivers/char/rocket.h --- linux-2.5.70-bk10/drivers/char/rocket.h 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk11/drivers/char/rocket.h 2003-06-06 04:38:21.000000000 -0700 @@ -0,0 +1,131 @@ +/* + * rocket.h --- the exported interface of the rocket driver to + * its configuration program. + * + * Written by Theodore Ts'o, Copyright 1997. + * + * Copyright 1994, 1997, 2003 Comtrol Corporation. All Rights Reserved. + * + * The following source code is subject to Comtrol Corporation's + * Developer's License Agreement. + * + * This source code is protected by United States copyright law and + * international copyright treaties. + * + * This source code may only be used to develop software products that + * will operate with Comtrol brand hardware. + * + * You may not reproduce nor distribute this source code in its original + * form but must produce a derivative work which includes portions of + * this source code only. + * + * The portions of this source code which you use in your derivative + * work must bear Comtrol's copyright notice: + * + * Copyright 1994 Comtrol Corporation. + * + */ + +/* Model Information Struct */ +typedef struct { + unsigned long model; + char modelString[80]; + unsigned long numPorts; + int loadrm2; + int startingPortNumber; +} rocketModel_t; + +struct rocket_config { + int line; + int flags; + int closing_wait; + int close_delay; + int port; + int reserved[32]; +}; + +struct rocket_ports { + int tty_major; + int callout_major; + rocketModel_t rocketModel[8]; +}; + +struct rocket_version { + char rocket_version[32]; + char rocket_date[32]; + char reserved[64]; +}; + +/* + * Rocketport flags + */ +#define ROCKET_CALLOUT_NOHUP 0x00000001 +#define ROCKET_FORCE_CD 0x00000002 +#define ROCKET_HUP_NOTIFY 0x00000004 +#define ROCKET_SPLIT_TERMIOS 0x00000008 +#define ROCKET_SPD_MASK 0x00000070 +#define ROCKET_SPD_HI 0x00000010 /* Use 56000 instead of 38400 bps */ +#define ROCKET_SPD_VHI 0x00000020 /* Use 115200 instead of 38400 bps */ +#define ROCKET_SPD_SHI 0x00000030 /* Use 230400 instead of 38400 bps */ +#define ROCKET_SPD_WARP 0x00000040 /* Use 460800 instead of 38400 bps */ +#define ROCKET_SAK 0x00000080 +#define ROCKET_SESSION_LOCKOUT 0x00000100 +#define ROCKET_PGRP_LOCKOUT 0x00000200 +#define ROCKET_RTS_TOGGLE 0x00000400 +#define ROCKET_MODE_MASK 0x00003000 +#define ROCKET_MODE_RS232 0x00000000 +#define ROCKET_MODE_RS485 0x00001000 +#define ROCKET_MODE_RS422 0x00002000 +#define ROCKET_FLAGS 0x00003FFF + +#define ROCKET_USR_MASK 0x0071 /* Legal flags that non-privileged + * users can set or reset */ + +/* + * For closing_wait and closing_wait2 + */ +#define ROCKET_CLOSING_WAIT_NONE 65535 +#define ROCKET_CLOSING_WAIT_INF 0 + +/* + * Rocketport ioctls -- "RP" + */ +#define RCKP_GET_STRUCT 0x00525001 +#define RCKP_GET_CONFIG 0x00525002 +#define RCKP_SET_CONFIG 0x00525003 +#define RCKP_GET_PORTS 0x00525004 +#define RCKP_RESET_RM2 0x00525005 +#define RCKP_GET_VERSION 0x00525006 + +/* Rocketport Models */ +#define MODEL_RP32INTF 0x0001 /* RP 32 port w/external I/F */ +#define MODEL_RP8INTF 0x0002 /* RP 8 port w/external I/F */ +#define MODEL_RP16INTF 0x0003 /* RP 16 port w/external I/F */ +#define MODEL_RP8OCTA 0x0005 /* RP 8 port w/octa cable */ +#define MODEL_RP4QUAD 0x0004 /* RP 4 port w/quad cable */ +#define MODEL_RP8J 0x0006 /* RP 8 port w/RJ11 connectors */ +#define MODEL_RP4J 0x0007 /* RP 4 port w/RJ45 connectors */ +#define MODEL_RP8SNI 0x0008 /* RP 8 port w/ DB78 SNI connector */ +#define MODEL_RP16SNI 0x0009 /* RP 16 port w/ DB78 SNI connector */ +#define MODEL_RPP4 0x000A /* RP Plus 4 port */ +#define MODEL_RPP8 0x000B /* RP Plus 8 port */ +#define MODEL_RP2_232 0x000E /* RP Plus 2 port RS232 */ +#define MODEL_RP2_422 0x000F /* RP Plus 2 port RS232 */ + +/* Rocketmodem II Models */ +#define MODEL_RP6M 0x000C /* RM 6 port */ +#define MODEL_RP4M 0x000D /* RM 4 port */ + +/* Universal PCI boards */ +#define MODEL_UPCI_RP32INTF 0x0801 /* RP UPCI 32 port w/external I/F */ +#define MODEL_UPCI_RP8INTF 0x0802 /* RP UPCI 8 port w/external I/F */ +#define MODEL_UPCI_RP16INTF 0x0803 /* RP UPCI 16 port w/external I/F */ +#define MODEL_UPCI_RP8OCTA 0x0805 /* RP UPCI 8 port w/octa cable */ +#define MODEL_UPCI_RM3_8PORT 0x080C /* RP UPCI Rocketmodem III 8 port */ +#define MODEL_UPCI_RM3_4PORT 0x080C /* RP UPCI Rocketmodem III 4 port */ + +/* Compact PCI 16 port */ +#define MODEL_CPCI_RP16INTF 0x0903 /* RP Compact PCI 16 port w/external I/F */ + +/* All ISA boards */ +#define MODEL_ISA 0x1000 diff -urN linux-2.5.70-bk10/drivers/char/rocket_int.h linux-2.5.70-bk11/drivers/char/rocket_int.h --- linux-2.5.70-bk10/drivers/char/rocket_int.h 2003-06-06 04:38:12.000000000 -0700 +++ linux-2.5.70-bk11/drivers/char/rocket_int.h 2003-06-06 04:38:21.000000000 -0700 @@ -3,9 +3,7 @@ * * Written by Theodore Ts'o, Copyright 1997. * - * Portions of this file are.... - * - * Copyright 1994 Comtrol Corporation. All Rights Reserved. + * Copyright 1994, 1997, 2003 Comtrol Corporation. All Rights Reserved. * * The following source code is subject to Comtrol Corporation's * Developer's License Agreement. @@ -28,23 +26,16 @@ */ /* - * Begin Comtrol-provided headers, et. al. + * Definition of the types in rcktpt_type */ - -/* - user definitions for Rocket Toolkit - - The following typedefs and defines must be established - depending on the platform the toolkit is being used - with. - -*/ - -/************************************************************ -The following sets up the world for use with Linux -************************************************************/ +#define ROCKET_TYPE_NORMAL 0 +#define ROCKET_TYPE_MODEM 1 +#define ROCKET_TYPE_MODEMII 2 +#define ROCKET_TYPE_MODEMIII 3 +#define ROCKET_TYPE_PC104 4 #include +#include typedef unsigned char Byte_t; typedef unsigned int ByteIO_t; @@ -55,17 +46,71 @@ typedef unsigned long DWord_t; typedef unsigned int DWordIO_t; +/* + * Note! Normally the Linux I/O macros already take care of + * byte-swapping the I/O instructions. However, all accesses using + * sOutDW aren't really 32-bit accesses, but should be handled in byte + * order. Hence the use of the cpu_to_le32() macro to byte-swap + * things to no-op the byte swapping done by the big-endian outl() + * instruction. + */ + +#ifdef ROCKET_DEBUG_IO +static inline void sOutB(unsigned short port, unsigned char value) +{ +#ifdef ROCKET_DEBUG_IO + printk("sOutB(%x, %x)...", port, value); +#endif + outb_p(value, port); +} + +static inline void sOutW(unsigned short port, unsigned short value) +{ +#ifdef ROCKET_DEBUG_IO + printk("sOutW(%x, %x)...", port, value); +#endif + outw_p(value, port); +} + +static inline void sOutDW(unsigned short port, unsigned long value) +{ +#ifdef ROCKET_DEBUG_IO + printk("sOutDW(%x, %lx)...", port, value); +#endif + outl_p(cpu_to_le32(value), port); +} + +static inline unsigned char sInB(unsigned short port) +{ + return inb_p(port); +} + +static inline unsigned short sInW(unsigned short port) +{ + return inw_p(port); +} + +#else /* !ROCKET_DEBUG_IO */ #define sOutB(a, b) outb_p(b, a) #define sOutW(a, b) outw_p(b, a) -#define sOutDW(a, b) outl_p(b, a) +#define sOutDW(port, value) outl_p(cpu_to_le32(value), port) #define sInB(a) (inb_p(a)) #define sInW(a) (inw_p(a)) +#endif /* ROCKET_DEBUG_IO */ -#define sOutStrW(port, addr, count) outsw(port, addr, count) +/* This is used to move arrays of bytes so byte swapping isn't + * appropriate. On Linux 2.3 and above outsw is the same as + * outsw_ns, but we use the old form for compatibility with + * old kernels. */ +#if defined(__BIG_ENDIAN) && (LINUX_VERSION_CODE < VERSION_CODE(2,3,0)) +#define sOutStrW(port, addr, count) if (count) outsw_ns(port, addr, count) +#define sInStrW(port, addr, count) if (count) insw_ns(port, addr, count) +#else +#define sOutStrW(port, addr, count) if (count) outsw(port, addr, count) +#define sInStrW(port, addr, count) if (count) insw(port, addr, count) +#endif -#define sInStrW(port, addr, count) insw(port, addr, count) - -#define CTL_SIZE 4 +#define CTL_SIZE 8 #define AIOP_CTL_SIZE 4 #define CHAN_AIOP_SIZE 8 #define MAX_PORTS_PER_AIOP 8 @@ -78,219 +123,159 @@ #define isMC 2 /* Controller ID numbers */ -#define CTLID_NULL -1 /* no controller exists */ -#define CTLID_0001 0x0001 /* controller release 1 */ +#define CTLID_NULL -1 /* no controller exists */ +#define CTLID_0001 0x0001 /* controller release 1 */ /* AIOP ID numbers, identifies AIOP type implementing channel */ -#define AIOPID_NULL -1 /* no AIOP or channel exists */ -#define AIOPID_0001 0x0001 /* AIOP release 1 */ +#define AIOPID_NULL -1 /* no AIOP or channel exists */ +#define AIOPID_0001 0x0001 /* AIOP release 1 */ -#define NULLDEV -1 /* identifies non-existant device */ -#define NULLCTL -1 /* identifies non-existant controller */ -#define NULLCTLPTR (CONTROLLER_T *)0 /* identifies non-existant controller */ -#define NULLAIOP -1 /* identifies non-existant AIOP */ -#define NULLCHAN -1 /* identifies non-existant channel */ +#define NULLDEV -1 /* identifies non-existant device */ +#define NULLCTL -1 /* identifies non-existant controller */ +#define NULLCTLPTR (CONTROLLER_T *)0 /* identifies non-existant controller */ +#define NULLAIOP -1 /* identifies non-existant AIOP */ +#define NULLCHAN -1 /* identifies non-existant channel */ /************************************************************************ Global Register Offsets - Direct Access - Fixed values ************************************************************************/ -#define _CMD_REG 0x38 /* Command Register 8 Write */ -#define _INT_CHAN 0x39 /* Interrupt Channel Register 8 Read */ -#define _INT_MASK 0x3A /* Interrupt Mask Register 8 Read / Write */ -#define _UNUSED 0x3B /* Unused 8 */ -#define _INDX_ADDR 0x3C /* Index Register Address 16 Write */ -#define _INDX_DATA 0x3E /* Index Register Data 8/16 Read / Write */ +#define _CMD_REG 0x38 /* Command Register 8 Write */ +#define _INT_CHAN 0x39 /* Interrupt Channel Register 8 Read */ +#define _INT_MASK 0x3A /* Interrupt Mask Register 8 Read / Write */ +#define _UNUSED 0x3B /* Unused 8 */ +#define _INDX_ADDR 0x3C /* Index Register Address 16 Write */ +#define _INDX_DATA 0x3E /* Index Register Data 8/16 Read / Write */ /************************************************************************ Channel Register Offsets for 1st channel in AIOP - Direct Access ************************************************************************/ -#define _TD0 0x00 /* Transmit Data 16 Write */ -#define _RD0 0x00 /* Receive Data 16 Read */ -#define _CHN_STAT0 0x20 /* Channel Status 8/16 Read / Write */ -#define _FIFO_CNT0 0x10 /* Transmit/Receive FIFO Count 16 Read */ -#define _INT_ID0 0x30 /* Interrupt Identification 8 Read */ +#define _TD0 0x00 /* Transmit Data 16 Write */ +#define _RD0 0x00 /* Receive Data 16 Read */ +#define _CHN_STAT0 0x20 /* Channel Status 8/16 Read / Write */ +#define _FIFO_CNT0 0x10 /* Transmit/Receive FIFO Count 16 Read */ +#define _INT_ID0 0x30 /* Interrupt Identification 8 Read */ /************************************************************************ Tx Control Register Offsets - Indexed - External - Fixed ************************************************************************/ -#define _TX_ENBLS 0x980 /* Tx Processor Enables Register 8 Read / Write */ -#define _TXCMP1 0x988 /* Transmit Compare Value #1 8 Read / Write */ -#define _TXCMP2 0x989 /* Transmit Compare Value #2 8 Read / Write */ -#define _TXREP1B1 0x98A /* Tx Replace Value #1 - Byte 1 8 Read / Write */ -#define _TXREP1B2 0x98B /* Tx Replace Value #1 - Byte 2 8 Read / Write */ -#define _TXREP2 0x98C /* Transmit Replace Value #2 8 Read / Write */ +#define _TX_ENBLS 0x980 /* Tx Processor Enables Register 8 Read / Write */ +#define _TXCMP1 0x988 /* Transmit Compare Value #1 8 Read / Write */ +#define _TXCMP2 0x989 /* Transmit Compare Value #2 8 Read / Write */ +#define _TXREP1B1 0x98A /* Tx Replace Value #1 - Byte 1 8 Read / Write */ +#define _TXREP1B2 0x98B /* Tx Replace Value #1 - Byte 2 8 Read / Write */ +#define _TXREP2 0x98C /* Transmit Replace Value #2 8 Read / Write */ /************************************************************************ Memory Controller Register Offsets - Indexed - External - Fixed ************************************************************************/ -#define _RX_FIFO 0x000 /* Rx FIFO */ -#define _TX_FIFO 0x800 /* Tx FIFO */ -#define _RXF_OUTP 0x990 /* Rx FIFO OUT pointer 16 Read / Write */ -#define _RXF_INP 0x992 /* Rx FIFO IN pointer 16 Read / Write */ -#define _TXF_OUTP 0x994 /* Tx FIFO OUT pointer 8 Read / Write */ -#define _TXF_INP 0x995 /* Tx FIFO IN pointer 8 Read / Write */ -#define _TXP_CNT 0x996 /* Tx Priority Count 8 Read / Write */ -#define _TXP_PNTR 0x997 /* Tx Priority Pointer 8 Read / Write */ - -#define PRI_PEND 0x80 /* Priority data pending (bit7, Tx pri cnt) */ -#define TXFIFO_SIZE 255 /* size of Tx FIFO */ -#define RXFIFO_SIZE 1023 /* size of Rx FIFO */ +#define _RX_FIFO 0x000 /* Rx FIFO */ +#define _TX_FIFO 0x800 /* Tx FIFO */ +#define _RXF_OUTP 0x990 /* Rx FIFO OUT pointer 16 Read / Write */ +#define _RXF_INP 0x992 /* Rx FIFO IN pointer 16 Read / Write */ +#define _TXF_OUTP 0x994 /* Tx FIFO OUT pointer 8 Read / Write */ +#define _TXF_INP 0x995 /* Tx FIFO IN pointer 8 Read / Write */ +#define _TXP_CNT 0x996 /* Tx Priority Count 8 Read / Write */ +#define _TXP_PNTR 0x997 /* Tx Priority Pointer 8 Read / Write */ + +#define PRI_PEND 0x80 /* Priority data pending (bit7, Tx pri cnt) */ +#define TXFIFO_SIZE 255 /* size of Tx FIFO */ +#define RXFIFO_SIZE 1023 /* size of Rx FIFO */ /************************************************************************ Tx Priority Buffer - Indexed - External - Fixed ************************************************************************/ -#define _TXP_BUF 0x9C0 /* Tx Priority Buffer 32 Bytes Read / Write */ -#define TXP_SIZE 0x20 /* 32 bytes */ +#define _TXP_BUF 0x9C0 /* Tx Priority Buffer 32 Bytes Read / Write */ +#define TXP_SIZE 0x20 /* 32 bytes */ /************************************************************************ Channel Register Offsets - Indexed - Internal - Fixed ************************************************************************/ -#define _TX_CTRL 0xFF0 /* Transmit Control 16 Write */ -#define _RX_CTRL 0xFF2 /* Receive Control 8 Write */ -#define _BAUD 0xFF4 /* Baud Rate 16 Write */ -#define _CLK_PRE 0xFF6 /* Clock Prescaler 8 Write */ - -#if 0 -#define CLOCK_PRESC 0x14 /* ?????? new mod 4 (divide by 5) prescale */ - -#define BRD50 9215 -#define BRD75 6143 -#define BRD110 4188 -#define BRD134 3438 -#define BRD150 3071 -#define BRD200 2303 -#define BRD300 1535 -#define BRD600 767 -#define BRD1200 383 -#define BRD1800 255 -#define BRD2000 229 -#define BRD2400 191 -#define BRD3600 127 -#define BRD4800 95 -#define BRD7200 63 -#define BRD9600 47 -#define BRD14400 31 -#define BRD19200 23 -#define BRD38400 11 -#define BRD57600 7 -#define BRD76800 5 -#define BRD115200 3 -#define BRD230400 1 -#define BRD460800 0 -#endif - -#if 0 - -/* Old clock prescale definition and baud rates associated with it */ - -#define CLOCK_PRESC 0x19 /* mod 9 (divide by 10) prescale */ -#define BRD50 4607 -#define BRD75 3071 -#define BRD110 2094 -#define BRD134 1712 -#define BRD150 1535 -#define BRD200 1151 -#define BRD300 767 -#define BRD600 383 -#define BRD1200 191 -#define BRD1800 127 -#define BRD2000 114 -#define BRD2400 95 -#define BRD3600 64 -#define BRD4800 47 -#define BRD7200 31 -#define BRD9600 23 -#define BRD14400 15 -#define BRD19200 11 -#define BRD38400 5 -#define BRD57600 3 -#define BRD76800 2 -#define BRD115200 1 -#define BRD230400 0 - -#endif - -#define STMBREAK 0x08 /* BREAK */ -#define STMFRAME 0x04 /* framing error */ -#define STMRCVROVR 0x02 /* receiver over run error */ -#define STMPARITY 0x01 /* parity error */ +#define _TX_CTRL 0xFF0 /* Transmit Control 16 Write */ +#define _RX_CTRL 0xFF2 /* Receive Control 8 Write */ +#define _BAUD 0xFF4 /* Baud Rate 16 Write */ +#define _CLK_PRE 0xFF6 /* Clock Prescaler 8 Write */ + +#define STMBREAK 0x08 /* BREAK */ +#define STMFRAME 0x04 /* framing error */ +#define STMRCVROVR 0x02 /* receiver over run error */ +#define STMPARITY 0x01 /* parity error */ #define STMERROR (STMBREAK | STMFRAME | STMPARITY) -#define STMBREAKH 0x800 /* BREAK */ -#define STMFRAMEH 0x400 /* framing error */ -#define STMRCVROVRH 0x200 /* receiver over run error */ -#define STMPARITYH 0x100 /* parity error */ +#define STMBREAKH 0x800 /* BREAK */ +#define STMFRAMEH 0x400 /* framing error */ +#define STMRCVROVRH 0x200 /* receiver over run error */ +#define STMPARITYH 0x100 /* parity error */ #define STMERRORH (STMBREAKH | STMFRAMEH | STMPARITYH) -#define CTS_ACT 0x20 /* CTS input asserted */ -#define DSR_ACT 0x10 /* DSR input asserted */ -#define CD_ACT 0x08 /* CD input asserted */ -#define TXFIFOMT 0x04 /* Tx FIFO is empty */ -#define TXSHRMT 0x02 /* Tx shift register is empty */ -#define RDA 0x01 /* Rx data available */ -#define DRAINED (TXFIFOMT | TXSHRMT) /* indicates Tx is drained */ - -#define STATMODE 0x8000 /* status mode enable bit */ -#define RXFOVERFL 0x2000 /* receive FIFO overflow */ -#define RX2MATCH 0x1000 /* receive compare byte 2 match */ -#define RX1MATCH 0x0800 /* receive compare byte 1 match */ -#define RXBREAK 0x0400 /* received BREAK */ -#define RXFRAME 0x0200 /* received framing error */ -#define RXPARITY 0x0100 /* received parity error */ +#define CTS_ACT 0x20 /* CTS input asserted */ +#define DSR_ACT 0x10 /* DSR input asserted */ +#define CD_ACT 0x08 /* CD input asserted */ +#define TXFIFOMT 0x04 /* Tx FIFO is empty */ +#define TXSHRMT 0x02 /* Tx shift register is empty */ +#define RDA 0x01 /* Rx data available */ +#define DRAINED (TXFIFOMT | TXSHRMT) /* indicates Tx is drained */ + +#define STATMODE 0x8000 /* status mode enable bit */ +#define RXFOVERFL 0x2000 /* receive FIFO overflow */ +#define RX2MATCH 0x1000 /* receive compare byte 2 match */ +#define RX1MATCH 0x0800 /* receive compare byte 1 match */ +#define RXBREAK 0x0400 /* received BREAK */ +#define RXFRAME 0x0200 /* received framing error */ +#define RXPARITY 0x0100 /* received parity error */ #define STATERROR (RXBREAK | RXFRAME | RXPARITY) -#define CTSFC_EN 0x80 /* CTS flow control enable bit */ -#define RTSTOG_EN 0x40 /* RTS toggle enable bit */ -#define TXINT_EN 0x10 /* transmit interrupt enable */ -#define STOP2 0x08 /* enable 2 stop bits (0 = 1 stop) */ -#define PARITY_EN 0x04 /* enable parity (0 = no parity) */ -#define EVEN_PAR 0x02 /* even parity (0 = odd parity) */ -#define DATA8BIT 0x01 /* 8 bit data (0 = 7 bit data) */ - -#define SETBREAK 0x10 /* send break condition (must clear) */ -#define LOCALLOOP 0x08 /* local loopback set for test */ -#define SET_DTR 0x04 /* assert DTR */ -#define SET_RTS 0x02 /* assert RTS */ -#define TX_ENABLE 0x01 /* enable transmitter */ - -#define RTSFC_EN 0x40 /* RTS flow control enable */ -#define RXPROC_EN 0x20 /* receive processor enable */ -#define TRIG_NO 0x00 /* Rx FIFO trigger level 0 (no trigger) */ -#define TRIG_1 0x08 /* trigger level 1 char */ -#define TRIG_1_2 0x10 /* trigger level 1/2 */ -#define TRIG_7_8 0x18 /* trigger level 7/8 */ -#define TRIG_MASK 0x18 /* trigger level mask */ -#define SRCINT_EN 0x04 /* special Rx condition interrupt enable */ -#define RXINT_EN 0x02 /* Rx interrupt enable */ -#define MCINT_EN 0x01 /* modem change interrupt enable */ - -#define RXF_TRIG 0x20 /* Rx FIFO trigger level interrupt */ -#define TXFIFO_MT 0x10 /* Tx FIFO empty interrupt */ -#define SRC_INT 0x08 /* special receive condition interrupt */ -#define DELTA_CD 0x04 /* CD change interrupt */ -#define DELTA_CTS 0x02 /* CTS change interrupt */ -#define DELTA_DSR 0x01 /* DSR change interrupt */ - -#define REP1W2_EN 0x10 /* replace byte 1 with 2 bytes enable */ -#define IGN2_EN 0x08 /* ignore byte 2 enable */ -#define IGN1_EN 0x04 /* ignore byte 1 enable */ -#define COMP2_EN 0x02 /* compare byte 2 enable */ -#define COMP1_EN 0x01 /* compare byte 1 enable */ - -#define RESET_ALL 0x80 /* reset AIOP (all channels) */ -#define TXOVERIDE 0x40 /* Transmit software off override */ -#define RESETUART 0x20 /* reset channel's UART */ -#define RESTXFCNT 0x10 /* reset channel's Tx FIFO count register */ -#define RESRXFCNT 0x08 /* reset channel's Rx FIFO count register */ - -#define INTSTAT0 0x01 /* AIOP 0 interrupt status */ -#define INTSTAT1 0x02 /* AIOP 1 interrupt status */ -#define INTSTAT2 0x04 /* AIOP 2 interrupt status */ -#define INTSTAT3 0x08 /* AIOP 3 interrupt status */ +#define CTSFC_EN 0x80 /* CTS flow control enable bit */ +#define RTSTOG_EN 0x40 /* RTS toggle enable bit */ +#define TXINT_EN 0x10 /* transmit interrupt enable */ +#define STOP2 0x08 /* enable 2 stop bits (0 = 1 stop) */ +#define PARITY_EN 0x04 /* enable parity (0 = no parity) */ +#define EVEN_PAR 0x02 /* even parity (0 = odd parity) */ +#define DATA8BIT 0x01 /* 8 bit data (0 = 7 bit data) */ + +#define SETBREAK 0x10 /* send break condition (must clear) */ +#define LOCALLOOP 0x08 /* local loopback set for test */ +#define SET_DTR 0x04 /* assert DTR */ +#define SET_RTS 0x02 /* assert RTS */ +#define TX_ENABLE 0x01 /* enable transmitter */ + +#define RTSFC_EN 0x40 /* RTS flow control enable */ +#define RXPROC_EN 0x20 /* receive processor enable */ +#define TRIG_NO 0x00 /* Rx FIFO trigger level 0 (no trigger) */ +#define TRIG_1 0x08 /* trigger level 1 char */ +#define TRIG_1_2 0x10 /* trigger level 1/2 */ +#define TRIG_7_8 0x18 /* trigger level 7/8 */ +#define TRIG_MASK 0x18 /* trigger level mask */ +#define SRCINT_EN 0x04 /* special Rx condition interrupt enable */ +#define RXINT_EN 0x02 /* Rx interrupt enable */ +#define MCINT_EN 0x01 /* modem change interrupt enable */ + +#define RXF_TRIG 0x20 /* Rx FIFO trigger level interrupt */ +#define TXFIFO_MT 0x10 /* Tx FIFO empty interrupt */ +#define SRC_INT 0x08 /* special receive condition interrupt */ +#define DELTA_CD 0x04 /* CD change interrupt */ +#define DELTA_CTS 0x02 /* CTS change interrupt */ +#define DELTA_DSR 0x01 /* DSR change interrupt */ + +#define REP1W2_EN 0x10 /* replace byte 1 with 2 bytes enable */ +#define IGN2_EN 0x08 /* ignore byte 2 enable */ +#define IGN1_EN 0x04 /* ignore byte 1 enable */ +#define COMP2_EN 0x02 /* compare byte 2 enable */ +#define COMP1_EN 0x01 /* compare byte 1 enable */ + +#define RESET_ALL 0x80 /* reset AIOP (all channels) */ +#define TXOVERIDE 0x40 /* Transmit software off override */ +#define RESETUART 0x20 /* reset channel's UART */ +#define RESTXFCNT 0x10 /* reset channel's Tx FIFO count register */ +#define RESRXFCNT 0x08 /* reset channel's Rx FIFO count register */ + +#define INTSTAT0 0x01 /* AIOP 0 interrupt status */ +#define INTSTAT1 0x02 /* AIOP 1 interrupt status */ +#define INTSTAT2 0x04 /* AIOP 2 interrupt status */ +#define INTSTAT3 0x08 /* AIOP 3 interrupt status */ -#define INTR_EN 0x08 /* allow interrupts to host */ -#define INT_STROB 0x04 /* strobe and clear interrupt line (EOI) */ +#define INTR_EN 0x08 /* allow interrupts to host */ +#define INT_STROB 0x04 /* strobe and clear interrupt line (EOI) */ /************************************************************************** MUDBAC remapped for PCI @@ -299,14 +284,22 @@ #define _CFG_INT_PCI 0x40 #define _PCI_INT_FUNC 0x3A -#define PCI_STROB 0x2000 /* bit 13 of int aiop register */ -#define INTR_EN_PCI 0x0010 /* allow interrupts to host */ - +#define PCI_STROB 0x2000 /* bit 13 of int aiop register */ +#define INTR_EN_PCI 0x0010 /* allow interrupts to host */ -#define CHAN3_EN 0x08 /* enable AIOP 3 */ -#define CHAN2_EN 0x04 /* enable AIOP 2 */ -#define CHAN1_EN 0x02 /* enable AIOP 1 */ -#define CHAN0_EN 0x01 /* enable AIOP 0 */ +/* + * Definitions for Universal PCI board registers + */ +#define _PCI_9030_INT_CTRL 0x4c /* Offsets from BAR1 */ +#define _PCI_9030_GPIO_CTRL 0x54 +#define PCI_INT_CTRL_AIOP 0x0001 +#define PCI_GPIO_CTRL_8PORT 0x4000 +#define _PCI_9030_RING_IND 0xc0 /* Offsets from BAR1 */ + +#define CHAN3_EN 0x08 /* enable AIOP 3 */ +#define CHAN2_EN 0x04 /* enable AIOP 2 */ +#define CHAN1_EN 0x02 /* enable AIOP 1 */ +#define CHAN0_EN 0x01 /* enable AIOP 0 */ #define FREQ_DIS 0x00 #define FREQ_274HZ 0x60 #define FREQ_137HZ 0x50 @@ -314,75 +307,110 @@ #define FREQ_34HZ 0x30 #define FREQ_17HZ 0x20 #define FREQ_9HZ 0x10 -#define PERIODIC_ONLY 0x80 /* only PERIODIC interrupt */ +#define PERIODIC_ONLY 0x80 /* only PERIODIC interrupt */ -#define CHANINT_EN 0x0100 /* flags to enable/disable channel ints */ +#define CHANINT_EN 0x0100 /* flags to enable/disable channel ints */ #define RDATASIZE 72 #define RREGDATASIZE 52 +/* + * AIOP interrupt bits for ISA/PCI boards and UPCI boards. + */ +#define AIOP_INTR_BIT_0 0x0001 +#define AIOP_INTR_BIT_1 0x0002 +#define AIOP_INTR_BIT_2 0x0004 +#define AIOP_INTR_BIT_3 0x0008 + +#define AIOP_INTR_BITS ( \ + AIOP_INTR_BIT_0 \ + | AIOP_INTR_BIT_1 \ + | AIOP_INTR_BIT_2 \ + | AIOP_INTR_BIT_3) + +#define UPCI_AIOP_INTR_BIT_0 0x0004 +#define UPCI_AIOP_INTR_BIT_1 0x0020 +#define UPCI_AIOP_INTR_BIT_2 0x0100 +#define UPCI_AIOP_INTR_BIT_3 0x0800 + +#define UPCI_AIOP_INTR_BITS ( \ + UPCI_AIOP_INTR_BIT_0 \ + | UPCI_AIOP_INTR_BIT_1 \ + | UPCI_AIOP_INTR_BIT_2 \ + | UPCI_AIOP_INTR_BIT_3) + /* Controller level information structure */ -typedef struct -{ - int CtlID; - int CtlNum; - int BusType; - WordIO_t PCIIO; - ByteIO_t MBaseIO; - ByteIO_t MReg1IO; - ByteIO_t MReg2IO; - ByteIO_t MReg3IO; - Byte_t MReg2; - Byte_t MReg3; - int NumAiop; - WordIO_t AiopIO[AIOP_CTL_SIZE]; - ByteIO_t AiopIntChanIO[AIOP_CTL_SIZE]; - int AiopID[AIOP_CTL_SIZE]; - int AiopNumChan[AIOP_CTL_SIZE]; +typedef struct { + int CtlID; + int CtlNum; + int BusType; + int boardType; + int isUPCI; + WordIO_t PCIIO; + WordIO_t PCIIO2; + ByteIO_t MBaseIO; + ByteIO_t MReg1IO; + ByteIO_t MReg2IO; + ByteIO_t MReg3IO; + Byte_t MReg2; + Byte_t MReg3; + int NumAiop; + int AltChanRingIndicator; + ByteIO_t UPCIRingInd; + WordIO_t AiopIO[AIOP_CTL_SIZE]; + ByteIO_t AiopIntChanIO[AIOP_CTL_SIZE]; + int AiopID[AIOP_CTL_SIZE]; + int AiopNumChan[AIOP_CTL_SIZE]; + Word_t *AiopIntrBits; } CONTROLLER_T; typedef CONTROLLER_T CONTROLLER_t; /* Channel level information structure */ -typedef struct -{ - CONTROLLER_T *CtlP; - int AiopNum; - int ChanID; - int ChanNum; - - ByteIO_t Cmd; - ByteIO_t IntChan; - ByteIO_t IntMask; - DWordIO_t IndexAddr; - WordIO_t IndexData; - - WordIO_t TxRxData; - WordIO_t ChanStat; - WordIO_t TxRxCount; - ByteIO_t IntID; - - Word_t TxFIFO; - Word_t TxFIFOPtrs; - Word_t RxFIFO; - Word_t RxFIFOPtrs; - Word_t TxPrioCnt; - Word_t TxPrioPtr; - Word_t TxPrioBuf; - - Byte_t R[RREGDATASIZE]; - - Byte_t BaudDiv[4]; - Byte_t TxControl[4]; - Byte_t RxControl[4]; - Byte_t TxEnables[4]; - Byte_t TxCompare[4]; - Byte_t TxReplace1[4]; - Byte_t TxReplace2[4]; +typedef struct { + CONTROLLER_T *CtlP; + int AiopNum; + int ChanID; + int ChanNum; + int rtsToggle; + + ByteIO_t Cmd; + ByteIO_t IntChan; + ByteIO_t IntMask; + DWordIO_t IndexAddr; + WordIO_t IndexData; + + WordIO_t TxRxData; + WordIO_t ChanStat; + WordIO_t TxRxCount; + ByteIO_t IntID; + + Word_t TxFIFO; + Word_t TxFIFOPtrs; + Word_t RxFIFO; + Word_t RxFIFOPtrs; + Word_t TxPrioCnt; + Word_t TxPrioPtr; + Word_t TxPrioBuf; + + Byte_t R[RREGDATASIZE]; + + Byte_t BaudDiv[4]; + Byte_t TxControl[4]; + Byte_t RxControl[4]; + Byte_t TxEnables[4]; + Byte_t TxCompare[4]; + Byte_t TxReplace1[4]; + Byte_t TxReplace2[4]; } CHANNEL_T; typedef CHANNEL_T CHANNEL_t; -typedef CHANNEL_T * CHANPTR_T; +typedef CHANNEL_T *CHANPTR_T; + +#define InterfaceModeRS232 0x00 +#define InterfaceModeRS422 0x08 +#define InterfaceModeRS485 0x10 +#define InterfaceModeRS232T 0x18 /*************************************************************************** Function: sClrBreak @@ -391,10 +419,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sClrBreak(ChP) \ -{ \ +do { \ (ChP)->TxControl[3] &= ~SETBREAK; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sClrDTR @@ -403,10 +431,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sClrDTR(ChP) \ -{ \ +do { \ (ChP)->TxControl[3] &= ~SET_DTR; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sClrRTS @@ -415,10 +443,11 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sClrRTS(ChP) \ -{ \ +do { \ + if ((ChP)->rtsToggle) break; \ (ChP)->TxControl[3] &= ~SET_RTS; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sClrTxXOFF @@ -427,10 +456,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sClrTxXOFF(ChP) \ -{ \ +do { \ sOutB((ChP)->Cmd,TXOVERIDE | (Byte_t)(ChP)->ChanNum); \ sOutB((ChP)->Cmd,(Byte_t)(ChP)->ChanNum); \ -} +} while (0) /*************************************************************************** Function: sCtlNumToCtlPtr @@ -452,10 +481,22 @@ /*************************************************************************** Function: sPCIControllerEOI Purpose: Strobe the PCI End Of Interrupt bit. + For the UPCI boards, toggle the AIOP interrupt enable bit + (this was taken from the Windows driver). Call: sPCIControllerEOI(CtlP) CONTROLLER_T *CtlP; Ptr to controller structure */ -#define sPCIControllerEOI(CTLP) sOutW((CTLP)->PCIIO, PCI_STROB) +#define sPCIControllerEOI(CTLP) \ +do { \ + if ((CTLP)->isUPCI) { \ + Word_t w = sInW((CTLP)->PCIIO); \ + sOutW((CTLP)->PCIIO, (w ^ PCI_INT_CTRL_AIOP)); \ + sOutW((CTLP)->PCIIO, w); \ + } \ + else { \ + sOutW((CTLP)->PCIIO, PCI_STROB); \ + } \ +} while (0) /*************************************************************************** Function: sDisAiop @@ -465,10 +506,10 @@ int AiopNum; Number of AIOP on controller */ #define sDisAiop(CTLP,AIOPNUM) \ -{ \ +do { \ (CTLP)->MReg3 &= sBitMapClrTbl[AIOPNUM]; \ sOutB((CTLP)->MReg3IO,(CTLP)->MReg3); \ -} +} while (0) /*************************************************************************** Function: sDisCTSFlowCtl @@ -477,10 +518,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sDisCTSFlowCtl(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] &= ~CTSFC_EN; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sDisIXANY @@ -489,10 +530,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sDisIXANY(ChP) \ -{ \ +do { \ (ChP)->R[0x0e] = 0x86; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x0c]); \ -} +} while (0) /*************************************************************************** Function: DisParity @@ -503,10 +544,23 @@ sDisParity(), sSetOddParity(), and sSetEvenParity(). */ #define sDisParity(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] &= ~PARITY_EN; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) + +/*************************************************************************** +Function: sDisRTSToggle +Purpose: Disable RTS toggle +Call: sDisRTSToggle(ChP) + CHANNEL_T *ChP; Ptr to channel structure +*/ +#define sDisRTSToggle(ChP) \ +do { \ + (ChP)->TxControl[2] &= ~RTSTOG_EN; \ + sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + (ChP)->rtsToggle = 0; \ +} while (0) /*************************************************************************** Function: sDisRxFIFO @@ -515,10 +569,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sDisRxFIFO(ChP) \ -{ \ +do { \ (ChP)->R[0x32] = 0x0a; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x30]); \ -} +} while (0) /*************************************************************************** Function: sDisRxStatusMode @@ -542,10 +596,10 @@ and transmit shift register going completely empty. */ #define sDisTransmit(ChP) \ -{ \ +do { \ (ChP)->TxControl[3] &= ~TX_ENABLE; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sDisTxSoftFlowCtl @@ -554,10 +608,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sDisTxSoftFlowCtl(ChP) \ -{ \ +do { \ (ChP)->R[0x06] = 0x8a; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x04]); \ -} +} while (0) /*************************************************************************** Function: sEnAiop @@ -567,10 +621,10 @@ int AiopNum; Number of AIOP on controller */ #define sEnAiop(CTLP,AIOPNUM) \ -{ \ +do { \ (CTLP)->MReg3 |= sBitMapSetTbl[AIOPNUM]; \ sOutB((CTLP)->MReg3IO,(CTLP)->MReg3); \ -} +} while (0) /*************************************************************************** Function: sEnCTSFlowCtl @@ -579,10 +633,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sEnCTSFlowCtl(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] |= CTSFC_EN; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sEnIXANY @@ -591,10 +645,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sEnIXANY(ChP) \ -{ \ +do { \ (ChP)->R[0x0e] = 0x21; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x0c]); \ -} +} while (0) /*************************************************************************** Function: EnParity @@ -608,10 +662,28 @@ functions sSetOddParity() or sSetEvenParity(). */ #define sEnParity(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] |= PARITY_EN; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) + +/*************************************************************************** +Function: sEnRTSToggle +Purpose: Enable RTS toggle +Call: sEnRTSToggle(ChP) + CHANNEL_T *ChP; Ptr to channel structure +Comments: This function will disable RTS flow control and clear the RTS + line to allow operation of RTS toggle. +*/ +#define sEnRTSToggle(ChP) \ +do { \ + (ChP)->RxControl[2] &= ~RTSFC_EN; \ + sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->RxControl[0]); \ + (ChP)->TxControl[2] |= RTSTOG_EN; \ + (ChP)->TxControl[3] &= ~SET_RTS; \ + sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + (ChP)->rtsToggle = 1; \ +} while (0) /*************************************************************************** Function: sEnRxFIFO @@ -620,10 +692,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sEnRxFIFO(ChP) \ -{ \ +do { \ (ChP)->R[0x32] = 0x08; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x30]); \ -} +} while (0) /*************************************************************************** Function: sEnRxProcessor @@ -641,10 +713,10 @@ microcode has been downloaded. */ #define sEnRxProcessor(ChP) \ -{ \ +do { \ (ChP)->RxControl[2] |= RXPROC_EN; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->RxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sEnRxStatusMode @@ -665,10 +737,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sEnTransmit(ChP) \ -{ \ +do { \ (ChP)->TxControl[3] |= TX_ENABLE; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sEnTxSoftFlowCtl @@ -677,10 +749,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sEnTxSoftFlowCtl(ChP) \ -{ \ +do { \ (ChP)->R[0x06] = 0xc5; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x04]); \ -} +} while (0) /*************************************************************************** Function: sGetAiopIntStatus @@ -774,6 +846,18 @@ */ #define sGetChanStatusLo(ChP) sInB((ByteIO_t)(ChP)->ChanStat) +/********************************************************************** + * Get RI status of channel + * Defined as a function in rocket.c -aes + */ +#if 0 +#define sGetChanRI(ChP) ((ChP)->CtlP->AltChanRingIndicator ? \ + (sInB((ByteIO_t)((ChP)->ChanStat+8)) & DSR_ACT) : \ + (((ChP)->CtlP->boardType == ROCKET_TYPE_PC104) ? \ + (!(sInB((ChP)->CtlP->AiopIO[3]) & sBitMapSetTbl[(ChP)->ChanNum])) : \ + 0)) +#endif + /*************************************************************************** Function: sGetControllerIntStatus Purpose: Get the controller interrupt status @@ -798,7 +882,10 @@ was generated from periodic. If a bit is set the AIOP is interrupting. */ -#define sPCIGetControllerIntStatus(CTLP) ((sInW((CTLP)->PCIIO) >> 8) & 0x1f) +#define sPCIGetControllerIntStatus(CTLP) \ + ((CTLP)->isUPCI ? \ + (sInW((CTLP)->PCIIO2) & UPCI_AIOP_INTR_BITS) : \ + ((sInW((CTLP)->PCIIO) >> 8) & AIOP_INTR_BITS)) /*************************************************************************** @@ -834,7 +921,7 @@ /*************************************************************************** Function: sInitChanDefaults -Purpose: Initialize a channel structure to its default state. +Purpose: Initialize a channel structure to it's default state. Call: sInitChanDefaults(ChP) CHANNEL_T *ChP; Ptr to the channel structure Comments: This function must be called once for every channel structure @@ -842,12 +929,12 @@ */ #define sInitChanDefaults(ChP) \ -{ \ +do { \ (ChP)->CtlP = NULLCTLPTR; \ (ChP)->AiopNum = NULLAIOP; \ (ChP)->ChanID = AIOPID_NULL; \ (ChP)->ChanNum = NULLCHAN; \ -} +} while (0) /*************************************************************************** Function: sResetAiopByNum @@ -857,10 +944,10 @@ AIOPNUM; AIOP index */ #define sResetAiopByNum(CTLP,AIOPNUM) \ -{ \ +do { \ sOutB((CTLP)->AiopIO[(AIOPNUM)]+_CMD_REG,RESET_ALL); \ sOutB((CTLP)->AiopIO[(AIOPNUM)]+_CMD_REG,0x0); \ -} +} while (0) /*************************************************************************** Function: sSendBreak @@ -869,10 +956,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSendBreak(ChP) \ -{ \ +do { \ (ChP)->TxControl[3] |= SETBREAK; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetBaud @@ -882,11 +969,11 @@ Word_t Divisor; 16 bit baud rate divisor for channel */ #define sSetBaud(ChP,DIVISOR) \ -{ \ +do { \ (ChP)->BaudDiv[2] = (Byte_t)(DIVISOR); \ (ChP)->BaudDiv[3] = (Byte_t)((DIVISOR) >> 8); \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->BaudDiv[0]); \ -} +} while (0) /*************************************************************************** Function: sSetData7 @@ -895,10 +982,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSetData7(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] &= ~DATA8BIT; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetData8 @@ -907,10 +994,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSetData8(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] |= DATA8BIT; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetDTR @@ -919,10 +1006,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSetDTR(ChP) \ -{ \ +do { \ (ChP)->TxControl[3] |= SET_DTR; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetEvenParity @@ -936,10 +1023,10 @@ sEnParity(). */ #define sSetEvenParity(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] |= EVEN_PAR; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetOddParity @@ -953,10 +1040,10 @@ sEnParity(). */ #define sSetOddParity(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] &= ~EVEN_PAR; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetRTS @@ -965,10 +1052,11 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSetRTS(ChP) \ -{ \ +do { \ + if ((ChP)->rtsToggle) break; \ (ChP)->TxControl[3] |= SET_RTS; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetRxTrigger @@ -990,11 +1078,11 @@ */ #define sSetRxTrigger(ChP,LEVEL) \ -{ \ +do { \ (ChP)->RxControl[2] &= ~TRIG_MASK; \ (ChP)->RxControl[2] |= LEVEL; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->RxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetStop1 @@ -1003,10 +1091,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSetStop1(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] &= ~STOP2; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetStop2 @@ -1015,10 +1103,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSetStop2(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] |= STOP2; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetTxXOFFChar @@ -1028,10 +1116,10 @@ Byte_t Ch; The value to set the Tx XOFF character to */ #define sSetTxXOFFChar(ChP,CH) \ -{ \ +do { \ (ChP)->R[0x07] = (CH); \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x04]); \ -} +} while (0) /*************************************************************************** Function: sSetTxXONChar @@ -1041,10 +1129,10 @@ Byte_t Ch; The value to set the Tx XON character to */ #define sSetTxXONChar(ChP,CH) \ -{ \ +do { \ (ChP)->R[0x0b] = (CH); \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x08]); \ -} +} while (0) /*************************************************************************** Function: sStartRxProcessor @@ -1069,37 +1157,38 @@ */ #define sWriteTxByte(IO,DATA) sOutB(IO,DATA) -int sInitController( CONTROLLER_T *CtlP, - int CtlNum, - ByteIO_t MudbacIO, - ByteIO_t *AiopIOList, - int AiopIOListSize, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly); - -int sPCIInitController( CONTROLLER_T *CtlP, - int CtlNum, - ByteIO_t *AiopIOList, - int AiopIOListSize, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly); +int sInitController(CONTROLLER_T * CtlP, + int CtlNum, + ByteIO_t MudbacIO, + ByteIO_t * AiopIOList, + int AiopIOListSize, + int IRQNum, Byte_t Frequency, int PeriodicOnly); + +int sPCIInitController(CONTROLLER_T * CtlP, + int CtlNum, + ByteIO_t * AiopIOList, + int AiopIOListSize, + WordIO_t ConfigIO, + int IRQNum, + Byte_t Frequency, + int PeriodicOnly, + int altChanRingIndicator, int UPCIRingInd); int sReadAiopID(ByteIO_t io); int sReadAiopNumChan(WordIO_t io); -int sInitChan( CONTROLLER_T *CtlP, - CHANNEL_T *ChP, - int AiopNum, - int ChanNum); -Byte_t sGetRxErrStatus(CHANNEL_T *ChP); -void sStopRxProcessor(CHANNEL_T *ChP); -void sStopSWInFlowCtl(CHANNEL_T *ChP); -void sFlushRxFIFO(CHANNEL_T *ChP); -void sFlushTxFIFO(CHANNEL_T *ChP); -int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data); -void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags); -void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags); +int sInitChan(CONTROLLER_T * CtlP, + CHANNEL_T * ChP, int AiopNum, int ChanNum); +Byte_t sGetRxErrStatus(CHANNEL_T * ChP); +void sStopRxProcessor(CHANNEL_T * ChP); +void sStopSWInFlowCtl(CHANNEL_T * ChP); +void sFlushRxFIFO(CHANNEL_T * ChP); +void sFlushTxFIFO(CHANNEL_T * ChP); +int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); +void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags); +void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); +void sModemReset(CONTROLLER_T * CtlP, int chan, int on); +void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); +void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode); extern Byte_t R[RDATASIZE]; extern CONTROLLER_T sController[CTL_SIZE]; @@ -1108,7 +1197,6 @@ extern Byte_t sBitMapSetTbl[8]; extern int sClockPrescale; - /* * Begin Linux specific definitions for the Rocketport driver * @@ -1116,34 +1204,45 @@ */ struct r_port { - int magic; - int line; - int flags; - int count; - int blocked_open; - struct tty_struct *tty; - int board:2; - int aiop:2; - int chan:3; + int magic; + int line; + int flags; + int count; + int blocked_open; + struct tty_struct *tty; + unsigned int board:3; + unsigned int aiop:2; + unsigned int chan:3; CONTROLLER_t *ctlp; - CHANNEL_t channel; - int closing_wait; - int close_delay; - int intmask; - int xmit_fifo_room; /* room in xmit fifo */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - int cd_status; - int ignore_status_mask; - int read_status_mask; - int cps; - struct termios normal_termios; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; + CHANNEL_t channel; + int closing_wait; + int close_delay; + int intmask; + int xmit_fifo_room; /* room in xmit fifo */ + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + int session; + int pgrp; + int cd_status; + int ignore_status_mask; + int read_status_mask; + int cps; + struct termios normal_termios; + struct termios callout_termios; + +#ifdef DECLARE_WAITQUEUE + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; +#else + struct wait_queue *open_wait; + struct wait_queue *close_wait; +#endif + spinlock_t slock; + struct semaphore write_sem; }; - + #define RPORT_MAGIC 0x525001 #define NUM_BOARDS 8 @@ -1158,16 +1257,14 @@ #define WAKEUP_CHARS 256 /* Internal flags used only by the rocketport driver */ -#define ROCKET_INITIALIZED 0x80000000 /* Port is active */ -#define ROCKET_CLOSING 0x40000000 /* Serial port is closing */ -#define ROCKET_NORMAL_ACTIVE 0x20000000 /* Normal port is active */ -#define ROCKET_CALLOUT_ACTIVE 0x10000000 /* Callout port is active */ +#define ROCKET_INITIALIZED 0x80000000 /* Port is active */ +#define ROCKET_CLOSING 0x40000000 /* Serial port is closing */ +#define ROCKET_NORMAL_ACTIVE 0x20000000 /* Normal port is active */ +#define ROCKET_CALLOUT_ACTIVE 0x10000000 /* Callout port is active */ -/* - * tty subtypes - * - */ +/* tty subtypes */ #define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 /* * Assigned major numbers for the Comtrol Rocketport @@ -1175,9 +1272,6 @@ #define TTY_ROCKET_MAJOR 46 #define CUA_ROCKET_MAJOR 47 -/* - * Utility function. - */ #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif @@ -1188,27 +1282,65 @@ #undef PCI_DEVICE_ID_RP8INTF #undef PCI_DEVICE_ID_RP16INTF #undef PCI_DEVICE_ID_RP32INTF +#undef PCI_DEVICE_ID_URP8OCTA +#undef PCI_DEVICE_ID_URP8INTF +#undef PCI_DEVICE_ID_URP16INTF +#undef PCI_DEVICE_ID_CRP16INTF +#undef PCI_DEVICE_ID_URP32INTF #endif +/* Comtrol PCI Vendor ID */ #define PCI_VENDOR_ID_RP 0x11fe -#define PCI_DEVICE_ID_RP32INTF 0x0001 -#define PCI_DEVICE_ID_RP8INTF 0x0002 -#define PCI_DEVICE_ID_RP16INTF 0x0003 -#define PCI_DEVICE_ID_RP8OCTA 0x0005 -#ifndef PCI_DEVICE_ID_RP4QUAD -#define PCI_DEVICE_ID_RP4QUAD 0x0004 -#endif -#ifndef PCI_DEVICE_ID_RP8J -#define PCI_DEVICE_ID_RP8J 0x0006 -#endif -#ifndef PCI_DEVICE_ID_RPP4 -#define PCI_DEVICE_ID_RPP4 0x000A -#endif -#ifndef PCI_DEVICE_ID_RPP8 -#define PCI_DEVICE_ID_RPP8 0x000B -#endif -#ifndef PCI_DEVICE_ID_RP8M -#define PCI_DEVICE_ID_RP8M 0x000C -#endif +/* Comtrol Device ID's */ +#define PCI_DEVICE_ID_RP32INTF 0x0001 /* Rocketport 32 port w/external I/F */ +#define PCI_DEVICE_ID_RP8INTF 0x0002 /* Rocketport 8 port w/external I/F */ +#define PCI_DEVICE_ID_RP16INTF 0x0003 /* Rocketport 16 port w/external I/F */ +#define PCI_DEVICE_ID_RP4QUAD 0x0004 /* Rocketport 4 port w/quad cable */ +#define PCI_DEVICE_ID_RP8OCTA 0x0005 /* Rocketport 8 port w/octa cable */ +#define PCI_DEVICE_ID_RP8J 0x0006 /* Rocketport 8 port w/RJ11 connectors */ +#define PCI_DEVICE_ID_RP4J 0x0007 /* Rocketport 4 port w/RJ11 connectors */ +#define PCI_DEVICE_ID_RP8SNI 0x0008 /* Rocketport 8 port w/ DB78 SNI (Siemens) connector */ +#define PCI_DEVICE_ID_RP16SNI 0x0009 /* Rocketport 16 port w/ DB78 SNI (Siemens) connector */ +#define PCI_DEVICE_ID_RPP4 0x000A /* Rocketport Plus 4 port */ +#define PCI_DEVICE_ID_RPP8 0x000B /* Rocketport Plus 8 port */ +#define PCI_DEVICE_ID_RP6M 0x000C /* RocketModem 6 port */ +#define PCI_DEVICE_ID_RP4M 0x000D /* RocketModem 4 port */ +#define PCI_DEVICE_ID_RP2_232 0x000E /* Rocketport Plus 2 port RS232 */ +#define PCI_DEVICE_ID_RP2_422 0x000F /* Rocketport Plus 2 port RS422 */ + +/* Universal PCI boards */ +#define PCI_DEVICE_ID_URP32INTF 0x0801 /* Rocketport UPCI 32 port w/external I/F */ +#define PCI_DEVICE_ID_URP8INTF 0x0802 /* Rocketport UPCI 8 port w/external I/F */ +#define PCI_DEVICE_ID_URP16INTF 0x0803 /* Rocketport UPCI 16 port w/external I/F */ +#define PCI_DEVICE_ID_URP8OCTA 0x0805 /* Rocketport UPCI 8 port w/octa cable */ +#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C /* Rocketmodem III 8 port */ +#define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D /* Rocketmodem III 4 port */ + +/* Compact PCI device */ +#define PCI_DEVICE_ID_CRP16INTF 0x0903 /* Rocketport Compact PCI 16 port w/external I/F */ + +/* Taking care of some kernel incompatibilities... */ +#if LINUX_VERSION_CODE > VERSION_CODE(2,5,68) + +#define TTY_GET_LINE(t) t->index + +#define TTY_DRIVER_MINOR_START(t) t->driver->minor_start +#define TTY_DRIVER_SUBTYPE(t) t->driver->subtype +#define TTY_DRIVER_NAME(t) t->driver->name +#define TTY_DRIVER_NAME_BASE(t) t->driver->name_base +#define TTY_DRIVER_FLUSH_BUFFER_EXISTS(t) t->driver->flush_buffer +#define TTY_DRIVER_FLUSH_BUFFER(t) t->driver->flush_buffer(t) + +#else + +#define TTY_GET_LINE(t) minor(t->device) - TTY_DRIVER_MINOR_START(t) + +#define TTY_DRIVER_MINOR_START(t) t->driver.minor_start +#define TTY_DRIVER_SUBTYPE(t) t->driver.subtype +#define TTY_DRIVER_NAME(t) t->driver.name +#define TTY_DRIVER_NAME_BASE(t) t->driver.name_base +#define TTY_DRIVER_FLUSH_BUFFER_EXISTS(t) t->driver.flush_buffer +#define TTY_DRIVER_FLUSH_BUFFER(t) t->driver.flush_buffer(t) +#endif diff -urN linux-2.5.70-bk10/drivers/char/tty_io.c linux-2.5.70-bk11/drivers/char/tty_io.c --- linux-2.5.70-bk10/drivers/char/tty_io.c 2003-06-06 04:38:12.000000000 -0700 +++ linux-2.5.70-bk11/drivers/char/tty_io.c 2003-06-06 04:38:22.000000000 -0700 @@ -2093,10 +2093,6 @@ # define tty_unregister_devfs(driver, index) do { } while (0) #endif /* CONFIG_DEVFS_FS */ -static struct class tty_class = { - .name = "tty", -}; - struct tty_dev { struct list_head node; dev_t dev; @@ -2104,6 +2100,17 @@ }; #define to_tty_dev(d) container_of(d, struct tty_dev, class_dev) +static void release_tty_dev(struct class_device *class_dev) +{ + struct tty_dev *tty_dev = to_tty_dev(class_dev); + kfree(tty_dev); +} + +static struct class tty_class = { + .name = "tty", + .release = &release_tty_dev, +}; + static LIST_HEAD(tty_dev_list); static spinlock_t tty_dev_list_lock = SPIN_LOCK_UNLOCKED; @@ -2167,7 +2174,6 @@ list_del(&tty_dev->node); spin_unlock(&tty_dev_list_lock); class_device_unregister(&tty_dev->class_dev); - kfree(tty_dev); } else { spin_unlock(&tty_dev_list_lock); } diff -urN linux-2.5.70-bk10/drivers/i2c/Kconfig linux-2.5.70-bk11/drivers/i2c/Kconfig --- linux-2.5.70-bk10/drivers/i2c/Kconfig 2003-05-26 18:00:25.000000000 -0700 +++ linux-2.5.70-bk11/drivers/i2c/Kconfig 2003-06-06 04:38:22.000000000 -0700 @@ -144,7 +144,7 @@ config I2C_KEYWEST tristate "Powermac Keywest I2C interface" - depends on I2C && ALL_PPC + depends on I2C && PPC_PMAC help This supports the use of the I2C interface in the combo-I/O chip on recent Apple machines. Say Y if you have such a machine. diff -urN linux-2.5.70-bk10/drivers/i2c/chips/w83781d.c linux-2.5.70-bk11/drivers/i2c/chips/w83781d.c --- linux-2.5.70-bk10/drivers/i2c/chips/w83781d.c 2003-05-26 18:00:19.000000000 -0700 +++ linux-2.5.70-bk11/drivers/i2c/chips/w83781d.c 2003-06-06 04:38:22.000000000 -0700 @@ -1031,27 +1031,129 @@ return i2c_detect(adapter, &addr_data, w83781d_detect); } +/* Assumes that adapter is of I2C, not ISA variety. + * OTHERWISE DON'T CALL THIS + */ +static int +w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, + struct i2c_client *new_client) +{ + int i, val1 = 0, id; + int err; + const char *client_name; + struct w83781d_data *data = i2c_get_clientdata(new_client); + + if (!(data->lm75 = kmalloc(2 * sizeof (struct i2c_client), + GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR_SC_0; + } + memset(data->lm75, 0x00, 2 * sizeof (struct i2c_client)); + + id = i2c_adapter_id(adapter); + + if (force_subclients[0] == id && force_subclients[1] == address) { + for (i = 2; i <= 3; i++) { + if (force_subclients[i] < 0x48 || + force_subclients[i] > 0x4f) { + dev_err(&new_client->dev, "Invalid subclient " + "address %d; must be 0x48-0x4f\n", + force_subclients[i]); + err = -EINVAL; + goto ERROR_SC_1; + } + } + w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR, + (force_subclients[2] & 0x07) | + ((force_subclients[3] & 0x07) << 4)); + data->lm75[0].addr = force_subclients[2]; + } else { + val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR); + data->lm75[0].addr = 0x48 + (val1 & 0x07); + } + + if (kind != w83783s) { + if (force_subclients[0] == id && + force_subclients[1] == address) { + data->lm75[1].addr = force_subclients[3]; + } else { + data->lm75[1].addr = 0x48 + ((val1 >> 4) & 0x07); + } + if (data->lm75[0].addr == data->lm75[1].addr) { + dev_err(&new_client->dev, + "Duplicate addresses 0x%x for subclients.\n", + data->lm75[0].addr); + err = -EBUSY; + goto ERROR_SC_1; + } + } + + if (kind == w83781d) + client_name = "W83781D subclient"; + else if (kind == w83782d) + client_name = "W83782D subclient"; + else if (kind == w83783s) + client_name = "W83783S subclient"; + else if (kind == w83627hf) + client_name = "W83627HF subclient"; + else if (kind == as99127f) + client_name = "AS99127F subclient"; + else + client_name = "unknown subclient?"; + + for (i = 0; i <= 1; i++) { + /* store all data in w83781d */ + i2c_set_clientdata(&data->lm75[i], NULL); + data->lm75[i].adapter = adapter; + data->lm75[i].driver = &w83781d_driver; + data->lm75[i].flags = 0; + strlcpy(data->lm75[i].dev.name, client_name, + DEVICE_NAME_SIZE); + if ((err = i2c_attach_client(&(data->lm75[i])))) { + dev_err(&new_client->dev, "Subclient %d " + "registration at address 0x%x " + "failed.\n", i, data->lm75[i].addr); + if (i == 1) + goto ERROR_SC_2; + goto ERROR_SC_1; + } + if (kind == w83783s) + break; + } + + return 0; + +/* Undo inits in case of errors */ +ERROR_SC_2: + i2c_detach_client(&(data->lm75[0])); +ERROR_SC_1: + kfree(data->lm75); +ERROR_SC_0: + return err; +} + static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind) { - int i = 0, val1 = 0, val2, id; + int i = 0, val1 = 0, val2; struct i2c_client *new_client; struct w83781d_data *data; - int err = 0; - const char *type_name = ""; + int err; const char *client_name = ""; int is_isa = i2c_is_isa_adapter(adapter); enum vendor { winbond, asus } vendid; if (!is_isa - && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + err = -EINVAL; goto ERROR0; + } - if (is_isa) { - if (!request_region(address, W83781D_EXTENT, "w83781d")) + if (is_isa) + if (!request_region(address, W83781D_EXTENT, "w83781d")) { + err = -EBUSY; goto ERROR0; - release_region(address, W83781D_EXTENT); - } + } /* Probe whether there is anything available on this address. Already done for SMBus clients */ @@ -1059,15 +1161,21 @@ if (is_isa) { #define REALLY_SLOW_IO - /* We need the timeouts for at least some LM78-like chips. But only - if we read 'undefined' registers. */ + /* We need the timeouts for at least some LM78-like + chips. But only if we read 'undefined' registers. */ i = inb_p(address + 1); - if (inb_p(address + 2) != i) - goto ERROR0; - if (inb_p(address + 3) != i) - goto ERROR0; - if (inb_p(address + 7) != i) - goto ERROR0; + if (inb_p(address + 2) != i) { + err = -ENODEV; + goto ERROR1; + } + if (inb_p(address + 3) != i) { + err = -ENODEV; + goto ERROR1; + } + if (inb_p(address + 7) != i) { + err = -ENODEV; + goto ERROR1; + } #undef REALLY_SLOW_IO /* Let's just hope nothing breaks here */ @@ -1075,7 +1183,8 @@ outb_p(~i & 0x7f, address + 5); if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { outb_p(i, address + 5); - return 0; + err = -ENODEV; + goto ERROR1; } } } @@ -1087,7 +1196,7 @@ if (!(new_client = kmalloc(sizeof (struct i2c_client) + sizeof (struct w83781d_data), GFP_KERNEL))) { err = -ENOMEM; - goto ERROR0; + goto ERROR1; } memset(new_client, 0x00, sizeof (struct i2c_client) + @@ -1108,8 +1217,10 @@ force_*=... parameter, and the Winbond will be reset to the right bank. */ if (kind < 0) { - if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) - goto ERROR1; + if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80){ + err = -ENODEV; + goto ERROR2; + } val1 = w83781d_read_value(new_client, W83781D_REG_BANK); val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); /* Check for Winbond or Asus ID if in bank 0 */ @@ -1117,14 +1228,19 @@ (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3) && (val2 != 0x94)) || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12) - && (val2 != 0x06)))) - goto ERROR1; - /* If Winbond SMBus, check address at 0x48. Asus doesn't support */ + && (val2 != 0x06)))) { + err = -ENODEV; + goto ERROR2; + } + /* If Winbond SMBus, check address at 0x48. + Asus doesn't support */ if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) || ((val1 & 0x80) && (val2 == 0x5c)))) { if (w83781d_read_value - (new_client, W83781D_REG_I2C_ADDR) != address) - goto ERROR1; + (new_client, W83781D_REG_I2C_ADDR) != address) { + err = -ENODEV; + goto ERROR2; + } } } @@ -1143,8 +1259,11 @@ vendid = winbond; else if ((val2 == 0x12) || (val2 == 0x06)) vendid = asus; - else - goto ERROR1; + else { + err = -ENODEV; + goto ERROR2; + } + /* mask off lower bit, not reliable */ val1 = w83781d_read_value(new_client, W83781D_REG_WCHIPID) & 0xfe; @@ -1166,38 +1285,31 @@ "Ignoring 'force' parameter for unknown chip at" "adapter %d, address 0x%02x\n", i2c_adapter_id(adapter), address); - goto ERROR1; + err = -EINVAL; + goto ERROR2; } } if (kind == w83781d) { - type_name = "w83781d"; client_name = "W83781D chip"; } else if (kind == w83782d) { - type_name = "w83782d"; client_name = "W83782D chip"; } else if (kind == w83783s) { - type_name = "w83783s"; client_name = "W83783S chip"; } else if (kind == w83627hf) { - type_name = "w83627hf"; client_name = "W83627HF chip"; } else if (kind == as99127f) { - type_name = "as99127f"; client_name = "AS99127F chip"; } else if (kind == w83697hf) { - type_name = "w83697hf"; client_name = "W83697HF chip"; } else { - dev_err(&new_client->dev, "Internal error: unknown kind (%d)?!?", kind); - goto ERROR1; + dev_err(&new_client->dev, "Internal error: unknown " + "kind (%d)?!?", kind); + err = -ENODEV; + goto ERROR2; } - /* Reserve the ISA region */ - if (is_isa) - request_region(address, W83781D_EXTENT, type_name); - - /* Fill in the remaining client fields and put it into the global list */ + /* Fill in the remaining client fields and put into the global list */ strlcpy(new_client->dev.name, client_name, DEVICE_NAME_SIZE); data->type = kind; @@ -1206,76 +1318,13 @@ /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) - goto ERROR3; + goto ERROR2; /* attach secondary i2c lm75-like clients */ if (!is_isa) { - if (!(data->lm75 = kmalloc(2 * sizeof (struct i2c_client), - GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR4; - } - - memset(data->lm75, 0x00, 2 * sizeof (struct i2c_client)); - - id = i2c_adapter_id(adapter); - if (force_subclients[0] == id && force_subclients[1] == address) { - for (i = 2; i <= 3; i++) { - if (force_subclients[i] < 0x48 || - force_subclients[i] > 0x4f) { - dev_err(&new_client->dev, - "Invalid subclient address %d; must be 0x48-0x4f\n", - force_subclients[i]); - goto ERROR5; - } - } - w83781d_write_value(new_client, - W83781D_REG_I2C_SUBADDR, - (force_subclients[2] & 0x07) | - ((force_subclients[3] & 0x07) << - 4)); - data->lm75[0].addr = force_subclients[2]; - } else { - val1 = w83781d_read_value(new_client, - W83781D_REG_I2C_SUBADDR); - data->lm75[0].addr = 0x48 + (val1 & 0x07); - } - if (kind != w83783s) { - if (force_subclients[0] == id && - force_subclients[1] == address) { - data->lm75[1].addr = force_subclients[3]; - } else { - data->lm75[1].addr = - 0x48 + ((val1 >> 4) & 0x07); - } - if (data->lm75[0].addr == data->lm75[1].addr) { - dev_err(&new_client->dev, - "Duplicate addresses 0x%x for subclients.\n", - data->lm75[0].addr); - goto ERROR5; - } - } - if (kind == w83781d) - client_name = "W83781D subclient"; - else if (kind == w83782d) - client_name = "W83782D subclient"; - else if (kind == w83783s) - client_name = "W83783S subclient"; - else if (kind == w83627hf) - client_name = "W83627HF subclient"; - else if (kind == as99127f) - client_name = "AS99127F subclient"; - - for (i = 0; i <= 1; i++) { - i2c_set_clientdata(&data->lm75[i], NULL); /* store all data in w83781d */ - data->lm75[i].adapter = adapter; - data->lm75[i].driver = &w83781d_driver; - data->lm75[i].flags = 0; - strlcpy(data->lm75[i].dev.name, client_name, - DEVICE_NAME_SIZE); - if (kind == w83783s) - break; - } + if ((err = w83781d_detect_subclients(adapter, address, + kind, new_client))) + goto ERROR3; } else { data->lm75 = NULL; } @@ -1346,24 +1395,14 @@ w83781d_init_client(new_client); return 0; -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR5: - if (!is_isa) { - i2c_detach_client(&data->lm75[0]); - if (data->type != w83783s) - i2c_detach_client(&data->lm75[1]); - kfree(data->lm75); - } - ERROR4: +ERROR3: i2c_detach_client(new_client); - ERROR3: +ERROR2: + kfree(new_client); +ERROR1: if (is_isa) release_region(address, W83781D_EXTENT); - ERROR1: - kfree(new_client); - ERROR0: +ERROR0: return err; } @@ -1373,12 +1412,7 @@ struct w83781d_data *data = i2c_get_clientdata(client); int err; - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); - return err; - } - + /* release ISA region or I2C subclients first */ if (i2c_is_isa_client(client)) { release_region(client->addr, W83781D_EXTENT); } else { @@ -1387,6 +1421,14 @@ i2c_detach_client(&data->lm75[1]); kfree(data->lm75); } + + /* now it's safe to scrap the rest */ + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + kfree(client); return 0; diff -urN linux-2.5.70-bk10/drivers/i2c/i2c-core.c linux-2.5.70-bk11/drivers/i2c/i2c-core.c --- linux-2.5.70-bk10/drivers/i2c/i2c-core.c 2003-05-26 18:00:24.000000000 -0700 +++ linux-2.5.70-bk11/drivers/i2c/i2c-core.c 2003-06-06 04:38:22.000000000 -0700 @@ -124,7 +124,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) { - struct list_head *item; + struct list_head *item, *_n; struct i2c_driver *driver; struct i2c_client *client; int res = 0; @@ -144,7 +144,7 @@ /* detach any active clients. This must be done first, because * it can fail; in which case we give upp. */ - list_for_each(item,&adap->clients) { + list_for_each_safe(item, _n, &adap->clients) { client = list_entry(item, struct i2c_client, list); /* detaching devices is unconditional of the set notify @@ -215,8 +215,7 @@ int i2c_del_driver(struct i2c_driver *driver) { - struct list_head *item1; - struct list_head *item2; + struct list_head *item1, *item2, *_n; struct i2c_client *client; struct i2c_adapter *adap; @@ -245,7 +244,7 @@ goto out_unlock; } } else { - list_for_each(item2,&adap->clients) { + list_for_each_safe(item2, _n, &adap->clients) { client = list_entry(item2, struct i2c_client, list); if (client->driver != driver) continue; diff -urN linux-2.5.70-bk10/drivers/ide/Kconfig linux-2.5.70-bk11/drivers/ide/Kconfig --- linux-2.5.70-bk10/drivers/ide/Kconfig 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk11/drivers/ide/Kconfig 2003-06-06 04:38:22.000000000 -0700 @@ -268,7 +268,7 @@ config BLK_DEV_IDEPCI bool "PCI IDE chipset support" if PCI depends on BLK_DEV_IDE - default BLK_DEV_IDEDMA_PMAC if ALL_PPC && BLK_DEV_IDEDMA_PMAC + default BLK_DEV_IDEDMA_PMAC if PPC_PMAC && BLK_DEV_IDEDMA_PMAC help Say Y here for PCI systems which use IDE drive(s). This option helps the IDE driver to automatically detect and @@ -409,7 +409,7 @@ bool depends on BLK_DEV_IDE default BLK_DEV_IDEDMA_ICS if ARCH_ACORN - default BLK_DEV_IDEDMA_PMAC if ALL_PPC && BLK_DEV_IDE_PMAC + default BLK_DEV_IDEDMA_PMAC if PPC_PMAC && BLK_DEV_IDE_PMAC default BLK_DEV_IDEDMA_PCI if PCI && BLK_DEV_IDEPCI config IDEDMA_PCI_WIP @@ -734,7 +734,7 @@ config BLK_DEV_IDE_PMAC bool "Builtin PowerMac IDE support" - depends on BLK_DEV_IDE && ALL_PPC + depends on BLK_DEV_IDE && PPC_PMAC help This driver provides support for the built-in IDE controller on most of the recent Apple Power Macintoshes and PowerBooks. diff -urN linux-2.5.70-bk10/drivers/ide/setup-pci.c linux-2.5.70-bk11/drivers/ide/setup-pci.c --- linux-2.5.70-bk10/drivers/ide/setup-pci.c 2003-06-06 04:38:12.000000000 -0700 +++ linux-2.5.70-bk11/drivers/ide/setup-pci.c 2003-06-06 04:38:23.000000000 -0700 @@ -880,7 +880,7 @@ ide_scan_pcidev(dev); } } else { - pci_for_each_dev_reverse(dev) { + while ((dev = pci_find_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { ide_scan_pcidev(dev); } } diff -urN linux-2.5.70-bk10/drivers/ieee1394/ohci1394.c linux-2.5.70-bk11/drivers/ieee1394/ohci1394.c --- linux-2.5.70-bk10/drivers/ieee1394/ohci1394.c 2003-06-06 04:38:12.000000000 -0700 +++ linux-2.5.70-bk11/drivers/ieee1394/ohci1394.c 2003-06-06 04:38:23.000000000 -0700 @@ -111,7 +111,7 @@ #include #include -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC #include #include #include @@ -3508,7 +3508,7 @@ OHCI1394_REGISTER_SIZE); #endif -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* On UniNorth, power down the cable and turn off the chip * clock when the module is removed to save power on * laptops. Turning it back ON is done by the arch code when @@ -3522,7 +3522,7 @@ pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, of_node, 0, 0); } } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ case OHCI_INIT_ALLOC_HOST: pci_set_drvdata(ohci->dev, NULL); diff -urN linux-2.5.70-bk10/drivers/macintosh/via-pmu68k.c linux-2.5.70-bk11/drivers/macintosh/via-pmu68k.c --- linux-2.5.70-bk10/drivers/macintosh/via-pmu68k.c 2003-05-26 18:00:24.000000000 -0700 +++ linux-2.5.70-bk11/drivers/macintosh/via-pmu68k.c 2003-06-06 04:38:23.000000000 -0700 @@ -839,11 +839,11 @@ pbook_pci_save(void) { int npci; - struct pci_dev *pd; + struct pci_dev *pd = NULL; struct pci_save *ps; npci = 0; - for (pd = pci_devices; pd != NULL; pd = pd->next) + while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) ++npci; n_pbook_pci_saves = npci; if (npci == 0) @@ -853,7 +853,8 @@ if (ps == NULL) return; - for (pd = pci_devices; pd != NULL && npci != 0; pd = pd->next) { + pd = NULL; + while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { pci_read_config_word(pd, PCI_COMMAND, &ps->command); pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat); pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr); @@ -867,10 +868,10 @@ { u16 cmd; struct pci_save *ps = pbook_pci_saves; - struct pci_dev *pd; + struct pci_dev *pd = NULL; int j; - for (pd = pci_devices; pd != NULL; pd = pd->next, ++ps) { + while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { if (ps->command == 0) continue; pci_read_config_word(pd, PCI_COMMAND, &cmd); diff -urN linux-2.5.70-bk10/drivers/media/video/Kconfig linux-2.5.70-bk11/drivers/media/video/Kconfig --- linux-2.5.70-bk10/drivers/media/video/Kconfig 2003-05-26 18:00:58.000000000 -0700 +++ linux-2.5.70-bk11/drivers/media/video/Kconfig 2003-06-06 04:38:23.000000000 -0700 @@ -45,7 +45,7 @@ config VIDEO_PLANB tristate "PlanB Video-In on PowerMac" - depends on ALL_PPC && VIDEO_DEV + depends on PPC_PMAC && VIDEO_DEV help PlanB is the V4L driver for the PowerMac 7x00/8x00 series video input hardware. If you want to experiment with this, say Y. diff -urN linux-2.5.70-bk10/drivers/message/fusion/linux_compat.h linux-2.5.70-bk11/drivers/message/fusion/linux_compat.h --- linux-2.5.70-bk10/drivers/message/fusion/linux_compat.h 2003-05-26 18:00:28.000000000 -0700 +++ linux-2.5.70-bk11/drivers/message/fusion/linux_compat.h 2003-06-06 04:38:23.000000000 -0700 @@ -147,9 +147,7 @@ /* PCI/driver subsystem { */ -#ifndef pci_for_each_dev -#define pci_for_each_dev(dev) for((dev)=pci_devices; (dev)!=NULL; (dev)=(dev)->next) -#define pci_peek_next_dev(dev) ((dev)->next ? (dev)->next : NULL) +#if 0 /* FIXME Don't know what to use to check for the proper kernel version */ #define DEVICE_COUNT_RESOURCE 6 #define PCI_BASEADDR_FLAGS(idx) base_address[idx] #define PCI_BASEADDR_START(idx) base_address[idx] & ~0xFUL @@ -169,11 +167,10 @@ (4 - size); \ }) #else -#define pci_peek_next_dev(dev) ((dev) != pci_dev_g(&pci_devices) ? pci_dev_g((dev)->global_list.next) : NULL) #define PCI_BASEADDR_FLAGS(idx) resource[idx].flags #define PCI_BASEADDR_START(idx) resource[idx].start #define PCI_BASEADDR_SIZE(dev,idx) (dev)->resource[idx].end - (dev)->resource[idx].start + 1 -#endif /* } ifndef pci_for_each_dev */ +#endif /* } ifndef 0 */ /* Compatability for the 2.3.x PCI DMA API. */ diff -urN linux-2.5.70-bk10/drivers/message/fusion/mptbase.c linux-2.5.70-bk11/drivers/message/fusion/mptbase.c --- linux-2.5.70-bk10/drivers/message/fusion/mptbase.c 2003-06-06 04:38:12.000000000 -0700 +++ linux-2.5.70-bk11/drivers/message/fusion/mptbase.c 2003-06-06 04:38:23.000000000 -0700 @@ -1184,7 +1184,7 @@ * Do some kind of look ahead here... */ if (pdev->devfn & 1) { - pdev2 = pci_peek_next_dev(pdev); + pdev2 = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev); if (pdev2 && (pdev2->vendor == 0x1000) && (PCI_SLOT(pdev2->devfn) == PCI_SLOT(pdev->devfn)) && (pdev2->device == pdev->device) && diff -urN linux-2.5.70-bk10/drivers/net/8139cp.c linux-2.5.70-bk11/drivers/net/8139cp.c --- linux-2.5.70-bk10/drivers/net/8139cp.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/8139cp.c 2003-06-06 04:38:24.000000000 -0700 @@ -1846,7 +1846,7 @@ } /* Configure DMA attributes. */ - if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) { + if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL)) { cp->pci_using_dac = 1; } else { rc = pci_set_dma_mask(pdev, (u64) 0xffffffff); diff -urN linux-2.5.70-bk10/drivers/net/Kconfig linux-2.5.70-bk11/drivers/net/Kconfig --- linux-2.5.70-bk10/drivers/net/Kconfig 2003-05-26 18:00:56.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/Kconfig 2003-06-06 04:38:24.000000000 -0700 @@ -225,7 +225,7 @@ config MACE tristate "MACE (Power Mac ethernet) support" - depends on NET_ETHERNET && PPC && ALL_PPC + depends on NET_ETHERNET && PPC_PMAC help Power Macintoshes and clones with Ethernet built-in on the motherboard will usually use a MACE (Medium Access Control for @@ -249,7 +249,7 @@ config BMAC tristate "BMAC (G3 ethernet) support" - depends on NET_ETHERNET && PPC && ALL_PPC + depends on NET_ETHERNET && PPC_PMAC help Say Y for support of BMAC Ethernet interfaces. These are used on G3 computers. diff -urN linux-2.5.70-bk10/drivers/net/Makefile linux-2.5.70-bk11/drivers/net/Makefile --- linux-2.5.70-bk10/drivers/net/Makefile 2003-05-26 18:00:27.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/Makefile 2003-06-06 04:38:24.000000000 -0700 @@ -173,7 +173,7 @@ obj-$(CONFIG_TUN) += tun.o obj-$(CONFIG_DL2K) += dl2k.o obj-$(CONFIG_R8169) += r8169.o -obj-$(CONFIG_AMD8111_ETH) += amd8111e.o +obj-$(CONFIG_AMD8111_ETH) += amd8111e.o mii.o # non-drivers/net drivers who want mii lib obj-$(CONFIG_PCMCIA_SMC91C92) += mii.o diff -urN linux-2.5.70-bk10/drivers/net/arcnet/arc-rawmode.c linux-2.5.70-bk11/drivers/net/arcnet/arc-rawmode.c --- linux-2.5.70-bk10/drivers/net/arcnet/arc-rawmode.c 2003-05-26 18:00:59.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/arcnet/arc-rawmode.c 2003-06-06 04:38:24.000000000 -0700 @@ -45,11 +45,11 @@ struct ArcProto rawmode_proto = { - 'r', - XMTU, - rx, - build_header, - prepare_tx + .suffix = 'r', + .mtu = XMTU, + .rx = rx, + .build_header = build_header, + .prepare_tx = prepare_tx, }; diff -urN linux-2.5.70-bk10/drivers/net/arcnet/arcnet.c linux-2.5.70-bk11/drivers/net/arcnet/arcnet.c --- linux-2.5.70-bk10/drivers/net/arcnet/arcnet.c 2003-05-26 18:00:43.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/arcnet/arcnet.c 2003-06-06 04:38:24.000000000 -0700 @@ -73,11 +73,11 @@ struct ArcProto arc_proto_null = { - '?', - XMTU, - null_rx, - null_build_header, - null_prepare_tx + .suffix = '?', + .mtu = XMTU, + .rx = null_rx, + .build_header = null_build_header, + .prepare_tx = null_prepare_tx, }; static spinlock_t arcnet_lock = SPIN_LOCK_UNLOCKED; diff -urN linux-2.5.70-bk10/drivers/net/arcnet/rfc1051.c linux-2.5.70-bk11/drivers/net/arcnet/rfc1051.c --- linux-2.5.70-bk10/drivers/net/arcnet/rfc1051.c 2003-05-26 18:00:42.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/arcnet/rfc1051.c 2003-06-06 04:38:24.000000000 -0700 @@ -45,11 +45,11 @@ struct ArcProto rfc1051_proto = { - 's', - XMTU - RFC1051_HDR_SIZE, - rx, - build_header, - prepare_tx + .suffix = 's', + .mtu = XMTU - RFC1051_HDR_SIZE, + .rx = rx, + .build_header = build_header, + .prepare_tx = prepare_tx, }; diff -urN linux-2.5.70-bk10/drivers/net/arcnet/rfc1201.c linux-2.5.70-bk11/drivers/net/arcnet/rfc1201.c --- linux-2.5.70-bk10/drivers/net/arcnet/rfc1201.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/arcnet/rfc1201.c 2003-06-06 04:38:24.000000000 -0700 @@ -44,12 +44,12 @@ struct ArcProto rfc1201_proto = { - 'a', - 1500, /* could be more, but some receivers can't handle it... */ - rx, - build_header, - prepare_tx, - continue_tx + .suffix = 'a', + .mtu = 1500, /* could be more, but some receivers can't handle it... */ + .rx = rx, + .build_header = build_header, + .prepare_tx = prepare_tx, + .continue_tx = continue_tx, }; diff -urN linux-2.5.70-bk10/drivers/net/bmac.c linux-2.5.70-bk11/drivers/net/bmac.c --- linux-2.5.70-bk10/drivers/net/bmac.c 2003-05-26 18:00:21.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/bmac.c 2003-06-06 04:38:24.000000000 -0700 @@ -1331,12 +1331,13 @@ } } - dev = init_etherdev(NULL, PRIV_BYTES); + dev = alloc_etherdev(PRIV_BYTES); if (!dev) { - printk(KERN_ERR "init_etherdev failed, out of memory for BMAC %s\n", + printk(KERN_ERR "alloc_etherdev failed, out of memory for BMAC %s\n", bmac->full_name); return; } + bp = (struct bmac_data *) dev->priv; SET_MODULE_OWNER(dev); bp->node = bmac; @@ -1344,21 +1345,22 @@ if (!request_OF_resource(bmac, 0, " (bmac)")) { printk(KERN_ERR "BMAC: can't request IO resource !\n"); - goto err_out; + goto out1; } if (!request_OF_resource(bmac, 1, " (bmac tx dma)")) { printk(KERN_ERR "BMAC: can't request TX DMA resource !\n"); - goto err_out; + goto out2; } - if (!request_OF_resource(bmac, 2, " (bmac rx dma)")) { printk(KERN_ERR "BMAC: can't request RX DMA resource !\n"); - goto err_out; + goto out3; } + dev->base_addr = (unsigned long) ioremap(bmac->addrs[0].address, bmac->addrs[0].size); if (!dev->base_addr) - goto err_out; + goto out4; + dev->irq = bmac->intrs[0].line; bmac_enable_and_reset_chip(dev); @@ -1429,11 +1431,19 @@ */ disable_irq(dev->irq); pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); + + if (register_netdev(dev) != 0) { + printk(KERN_ERR "registration failed for BMAC %s\n", + bmac->full_name); + goto err_out_irq2; + } bp->next_bmac = bmac_devs; bmac_devs = dev; return; +err_out_irq2: + free_irq(bmac->intrs[2].line, dev); err_out_irq1: free_irq(bmac->intrs[1].line, dev); err_out_irq0: @@ -1444,14 +1454,14 @@ iounmap((void *)bp->tx_dma); err_out_iounmap: iounmap((void *)dev->base_addr); -err_out: - if (bp->node) { - release_OF_resource(bp->node, 0); - release_OF_resource(bp->node, 1); - release_OF_resource(bp->node, 2); - pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); - } - unregister_netdev(dev); +out4: + release_OF_resource(bp->node, 2); +out3: + release_OF_resource(bp->node, 1); +out2: + release_OF_resource(bp->node, 0); +out1: + pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); kfree(dev); } diff -urN linux-2.5.70-bk10/drivers/net/dl2k.h linux-2.5.70-bk11/drivers/net/dl2k.h --- linux-2.5.70-bk10/drivers/net/dl2k.h 2003-05-26 18:00:57.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/dl2k.h 2003-06-06 04:38:24.000000000 -0700 @@ -243,7 +243,6 @@ VLANTagInsert = 0x0000000010000000, TFDDone = 0x80000000, VIDShift = 32, - CFI = 0x0000100000000000, UsePriorityShift = 48, }; diff -urN linux-2.5.70-bk10/drivers/net/hamradio/mkiss.c linux-2.5.70-bk11/drivers/net/hamradio/mkiss.c --- linux-2.5.70-bk10/drivers/net/hamradio/mkiss.c 2003-05-26 18:00:59.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/hamradio/mkiss.c 2003-06-06 04:38:24.000000000 -0700 @@ -329,6 +329,12 @@ return; } ax->rcount -= 2; + /* dl9sau bugfix: the trailling two bytes flexnet crc + * will not be passed to the kernel. thus we have + * to correct the kissparm signature, because it + * indicates a crc but there's none + */ + *ax->rbuff &= ~0x20; } } diff -urN linux-2.5.70-bk10/drivers/net/ns83820.c linux-2.5.70-bk11/drivers/net/ns83820.c --- linux-2.5.70-bk10/drivers/net/ns83820.c 2003-05-26 18:00:59.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/ns83820.c 2003-06-06 04:38:24.000000000 -0700 @@ -1769,7 +1769,7 @@ int using_dac = 0; /* See if we can set the dma mask early on; failure is fatal. */ - if (TRY_DAC && !pci_set_dma_mask(pci_dev, 0xffffffffffffffff)) { + if (TRY_DAC && !pci_set_dma_mask(pci_dev, 0xffffffffffffffffULL)) { using_dac = 1; } else if (!pci_set_dma_mask(pci_dev, 0xffffffff)) { using_dac = 0; diff -urN linux-2.5.70-bk10/drivers/net/pcmcia/fmvj18x_cs.c linux-2.5.70-bk11/drivers/net/pcmcia/fmvj18x_cs.c --- linux-2.5.70-bk10/drivers/net/pcmcia/fmvj18x_cs.c 2003-05-26 18:00:43.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/pcmcia/fmvj18x_cs.c 2003-06-06 04:38:24.000000000 -0700 @@ -923,8 +923,7 @@ htons(inw(ioaddr +14))); lp->stats.tx_errors++; /* ToDo: We should try to restart the adaptor... */ - cli(); - + local_irq_disable(); fjn_reset(dev); lp->tx_started = 0; @@ -932,7 +931,7 @@ lp->tx_queue_len = 0; lp->sent = 0; lp->open_time = jiffies; - sti(); + local_irq_enable(); netif_wake_queue(dev); } @@ -1361,9 +1360,8 @@ mc_filter[bit >> 3] |= (1 << bit); } } - - save_flags(flags); - cli(); + + local_irq_save(flags); if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) { int saved_bank = inb(ioaddr + CONFIG_1); /* Switch to bank 1 and set the multicast table. */ @@ -1373,5 +1371,5 @@ memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter)); outb(saved_bank, ioaddr + CONFIG_1); } - restore_flags(flags); + local_irq_restore(flags); } diff -urN linux-2.5.70-bk10/drivers/net/sb1000.c linux-2.5.70-bk11/drivers/net/sb1000.c --- linux-2.5.70-bk10/drivers/net/sb1000.c 2003-05-26 18:00:21.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/sb1000.c 2003-06-06 04:38:24.000000000 -0700 @@ -162,10 +162,17 @@ irq = pnp_irq(pdev, 0); - if (!request_region(ioaddr[0], 16, dev->name)) + if (!request_region(ioaddr[0], 16, "sb1000")) goto out_disable; - if (!request_region(ioaddr[1], 16, dev->name)) + if (!request_region(ioaddr[1], 16, "sb1000")) goto out_release_region0; + + dev = alloc_etherdev(sizeof(struct sb1000_private)); + if (!dev) { + error = -ENOMEM; + goto out_release_regions; + } + dev->base_addr = ioaddr[0]; /* mem_start holds the second I/O address */ @@ -177,12 +184,6 @@ "S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr, dev->mem_start, serial_number, dev->irq); - dev = alloc_etherdev(sizeof(struct sb1000_private)); - if (!dev) { - error = -ENOMEM; - goto out_release_regions; - } - /* * The SB1000 is an rx-only cable modem device. The uplink is a modem * and we do not want to arp on it. @@ -212,11 +213,9 @@ error = register_netdev(dev); if (error) - goto out_unregister; + goto out_release_regions; return 0; - out_unregister: - unregister_netdev(dev); out_release_regions: release_region(ioaddr[1], 16); out_release_region0: @@ -236,6 +235,7 @@ unregister_netdev(dev); release_region(dev->base_addr, 16); release_region(dev->mem_start, 16); + kfree(dev); } static struct pnp_driver sb1000_driver = { diff -urN linux-2.5.70-bk10/drivers/net/sk98lin/skge.c linux-2.5.70-bk11/drivers/net/sk98lin/skge.c --- linux-2.5.70-bk10/drivers/net/sk98lin/skge.c 2003-06-06 04:38:13.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/sk98lin/skge.c 2003-06-06 04:38:24.000000000 -0700 @@ -421,7 +421,7 @@ continue; /* Configure DMA attributes. */ - if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff) && + if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL) && pci_set_dma_mask(pdev, (u64) 0xffffffff)) continue; diff -urN linux-2.5.70-bk10/drivers/net/sungem.c linux-2.5.70-bk11/drivers/net/sungem.c --- linux-2.5.70-bk10/drivers/net/sungem.c 2003-05-26 18:00:59.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/sungem.c 2003-06-06 04:38:24.000000000 -0700 @@ -48,7 +48,7 @@ #include #endif -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC #include #include #include @@ -1491,7 +1491,7 @@ mifcfg &= ~MIF_CFG_BBMODE; writel(mifcfg, gp->regs + MIF_CFG); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { int i, j; @@ -1525,7 +1525,7 @@ break; } } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ if (gp->pdev->vendor == PCI_VENDOR_ID_SUN && gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) { @@ -1924,7 +1924,7 @@ } } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* Enable the chip's clock and make sure it's config space is * setup properly. There appear to be no need to restore the * base addresses. @@ -1963,7 +1963,7 @@ pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0); } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ /* Must be invoked under gp->lock. */ static void gem_stop_phy(struct gem *gp) @@ -2028,10 +2028,10 @@ spin_unlock_irq(&gp->lock); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* Power down the chip */ gem_apple_powerdown(gp); -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ } else { gem_stop(gp); @@ -2085,13 +2085,13 @@ * etc. state so it is safe to do this bit without gp->lock */ if (!gp->hw_running) { -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* First, we need to bring up the chip */ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { gem_apple_powerup(gp); gem_check_invariants(gp); } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ /* Reset the chip */ spin_lock_irq(&gp->lock); @@ -2112,10 +2112,10 @@ printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE) gem_apple_powerdown(gp); -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ /* Fire the PM timer that will shut us down in about 10 seconds */ gp->pm_timer.expires = jiffies + 10*HZ; add_timer(&gp->pm_timer); @@ -2227,13 +2227,13 @@ printk(KERN_INFO "%s: resuming\n", dev->name); if (gp->opened) { -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* First, we need to bring up the chip */ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { gem_apple_powerup(gp); gem_check_invariants(gp); } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ spin_lock_irq(&gp->lock); gem_stop(gp); @@ -2541,7 +2541,7 @@ return rc; } -#if (!defined(__sparc__) && !defined(CONFIG_ALL_PPC)) +#if (!defined(__sparc__) && !defined(CONFIG_PPC)) /* Fetch MAC address from vital product data of PCI ROM. */ static void find_eth_addr_in_vpd(void *rom_base, int len, unsigned char *dev_addr) { @@ -2604,7 +2604,7 @@ static int __devinit gem_get_device_address(struct gem *gp) { -#if defined(__sparc__) || defined(CONFIG_ALL_PPC) +#if defined(__sparc__) || defined(CONFIG_PPC_PMAC) struct net_device *dev = gp->dev; #endif @@ -2623,7 +2623,7 @@ } if (node == -1) memcpy(dev->dev_addr, idprom->id_ethaddr, 6); -#elif defined(CONFIG_ALL_PPC) +#elif defined(CONFIG_PPC_PMAC) unsigned char *addr; addr = get_property(gp->of_node, "local-mac-address", NULL); @@ -2748,7 +2748,7 @@ * invariants to work, but also because the firmware might * not have properly shut down the PHY. */ -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC if (pdev->vendor == PCI_VENDOR_ID_APPLE) gem_apple_powerup(gp); #endif @@ -2779,7 +2779,7 @@ goto err_out_iounmap; } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC gp->of_node = pci_device_to_OF_node(pdev); #endif if (gem_get_device_address(gp)) diff -urN linux-2.5.70-bk10/drivers/net/sungem.h linux-2.5.70-bk11/drivers/net/sungem.h --- linux-2.5.70-bk10/drivers/net/sungem.h 2003-05-26 18:00:41.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/sungem.h 2003-06-06 04:38:24.000000000 -0700 @@ -998,7 +998,7 @@ dma_addr_t gblock_dvma; struct pci_dev *pdev; struct net_device *dev; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC struct device_node *of_node; #endif }; diff -urN linux-2.5.70-bk10/drivers/net/sunqe.c linux-2.5.70-bk11/drivers/net/sunqe.c --- linux-2.5.70-bk10/drivers/net/sunqe.c 2003-06-06 04:38:13.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/sunqe.c 2003-06-06 04:38:24.000000000 -0700 @@ -722,34 +722,31 @@ struct net_device *qe_devs[4]; struct sunqe *qeps[4]; struct sbus_dev *qesdevs[4]; + struct sbus_dev *child; struct sunqec *qecp = NULL; u8 bsizes, bsizes_more; - int i, j, res = ENOMEM; + int i, j, res = -ENOMEM; - dev = init_etherdev(0, sizeof(struct sunqe)); - qe_devs[0] = dev; - qeps[0] = (struct sunqe *) dev->priv; - qeps[0]->channel = 0; - spin_lock_init(&qeps[0]->lock); - for (j = 0; j < 6; j++) - qe_devs[0]->dev_addr[j] = idprom->id_ethaddr[j]; + for (i = 0; i < 4; i++) { + qe_devs[i] = alloc_etherdev(sizeof(struct sunqe)); + if (!qe_devs[i]) + goto out; + } if (version_printed++ == 0) printk(KERN_INFO "%s", version); - qe_devs[1] = qe_devs[2] = qe_devs[3] = NULL; - for (i = 1; i < 4; i++) { - qe_devs[i] = init_etherdev(0, sizeof(struct sunqe)); - if (qe_devs[i] == NULL || qe_devs[i]->priv == NULL) - goto qec_free_devs; + for (i = 0; i < 4; i++) { qeps[i] = (struct sunqe *) qe_devs[i]->priv; for (j = 0; j < 6; j++) qe_devs[i]->dev_addr[j] = idprom->id_ethaddr[j]; qeps[i]->channel = i; + spin_lock_init(&qeps[i]->lock); } + qecp = kmalloc(sizeof(struct sunqec), GFP_KERNEL); if (qecp == NULL) - goto qec_free_devs; + goto out1; qecp->qec_sdev = sdev; for (i = 0; i < 4; i++) { @@ -758,25 +755,15 @@ qeps[i]->parent = qecp; } - /* Link in channel 0. */ - i = prom_getintdefault(sdev->child->prom_node, "channel#", -1); - if (i == -1) { res=ENODEV; goto qec_free_devs; } - qesdevs[i] = sdev->child; - - /* Link in channel 1. */ - i = prom_getintdefault(sdev->child->next->prom_node, "channel#", -1); - if (i == -1) { res=ENODEV; goto qec_free_devs; } - qesdevs[i] = sdev->child->next; - - /* Link in channel 2. */ - i = prom_getintdefault(sdev->child->next->next->prom_node, "channel#", -1); - if (i == -1) { res=ENODEV; goto qec_free_devs; } - qesdevs[i] = sdev->child->next->next; - - /* Link in channel 3. */ - i = prom_getintdefault(sdev->child->next->next->next->prom_node, "channel#", -1); - if (i == -1) { res=ENODEV; goto qec_free_devs; } - qesdevs[i] = sdev->child->next->next->next; + res = -ENODEV; + + for (i = 0, child = sdev->child; i < 4; i++, child = child->next) { + /* Link in channel */ + j = prom_getintdefault(child->prom_node, "channel#", -1); + if (j == -1) + goto out2; + qesdevs[j] = child; + } for (i = 0; i < 4; i++) qeps[i]->qe_sdev = qesdevs[i]; @@ -786,22 +773,18 @@ GLOB_REG_SIZE, "QEC Global Registers"); if (!qecp->gregs) { printk(KERN_ERR "QuadEther: Cannot map QEC global registers.\n"); - res = ENODEV; - goto qec_free_devs; + goto out2; } /* Make sure the QEC is in MACE mode. */ if ((sbus_readl(qecp->gregs + GLOB_CTRL) & 0xf0000000) != GLOB_CTRL_MMODE) { printk(KERN_ERR "QuadEther: AIEEE, QEC is not in MACE mode!\n"); - res = ENODEV; - goto qec_free_devs; + goto out3; } /* Reset the QEC. */ - if (qec_global_reset(qecp->gregs)) { - res = ENODEV; - goto qec_free_devs; - } + if (qec_global_reset(qecp->gregs)) + goto out3; /* Find and set the burst sizes for the QEC, since it does * the actual dma for all 4 channels. @@ -824,40 +807,36 @@ qec_init_once(qecp, sdev); for (i = 0; i < 4; i++) { + struct sunqe *qe = qeps[i]; /* Map in QEC per-channel control registers. */ - qeps[i]->qcregs = sbus_ioremap(&qesdevs[i]->resource[0], 0, - CREG_REG_SIZE, "QEC Channel Registers"); - if (!qeps[i]->qcregs) { + qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0, + CREG_REG_SIZE, "QEC Channel Registers"); + if (!qe->qcregs) { printk(KERN_ERR "QuadEther: Cannot map QE %d's channel registers.\n", i); - res = ENODEV; - goto qec_free_devs; + goto out4; } /* Map in per-channel AMD MACE registers. */ - qeps[i]->mregs = sbus_ioremap(&qesdevs[i]->resource[1], 0, - MREGS_REG_SIZE, "QE MACE Registers"); - if (!qeps[i]->mregs) { + qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0, + MREGS_REG_SIZE, "QE MACE Registers"); + if (!qe->mregs) { printk(KERN_ERR "QuadEther: Cannot map QE %d's MACE registers.\n", i); - res = ENODEV; - goto qec_free_devs; + goto out4; } - qeps[i]->qe_block = sbus_alloc_consistent(qesdevs[i], - PAGE_SIZE, - &qeps[i]->qblock_dvma); - qeps[i]->buffers = sbus_alloc_consistent(qesdevs[i], - sizeof(struct sunqe_buffers), - &qeps[i]->buffers_dvma); - if (qeps[i]->qe_block == NULL || - qeps[i]->qblock_dvma == 0 || - qeps[i]->buffers == NULL || - qeps[i]->buffers_dvma == 0) { - res = ENODEV; - goto qec_free_devs; + qe->qe_block = sbus_alloc_consistent(qe->qe_sdev, + PAGE_SIZE, + &qe->qblock_dvma); + qe->buffers = sbus_alloc_consistent(qe->qe_sdev, + sizeof(struct sunqe_buffers), + &qe->buffers_dvma); + if (qe->qe_block == NULL || qe->qblock_dvma == 0 || + qe->buffers == NULL || qe->buffers_dvma == 0) { + goto out4; } /* Stop this QE. */ - qe_stop(qeps[i]); + qe_stop(qe); } for (i = 0; i < 4; i++) { @@ -871,7 +850,6 @@ qe_devs[i]->watchdog_timeo = 5*HZ; qe_devs[i]->irq = sdev->irqs[0]; qe_devs[i]->dma = 0; - ether_setup(qe_devs[i]); } /* QEC receives interrupts from each QE, then it sends the actual @@ -882,8 +860,13 @@ if (request_irq(sdev->irqs[0], &qec_interrupt, SA_SHIRQ, "QuadEther", (void *) qecp)) { printk(KERN_ERR "QuadEther: Can't register QEC master irq handler.\n"); - res = EAGAIN; - goto qec_free_devs; + res = -EAGAIN; + goto out4; + } + + for (i = 0; i < 4; i++) { + if (register_netdev(qe_devs[i]) != 0) + goto out5; } /* Report the QE channels. */ @@ -899,42 +882,43 @@ /* We are home free at this point, link the qe's into * the master list for later driver exit. */ - for (i = 0; i < 4; i++) - qe_devs[i]->ifindex = dev_new_index(); qecp->next_module = root_qec_dev; root_qec_dev = qecp; return 0; -qec_free_devs: +out5: + while (i--) + unregister_netdev(qe_devs[i]); + free_irq(sdev->irqs[0], (void *)qecp); +out4: for (i = 0; i < 4; i++) { - if (qe_devs[i] != NULL) { - if (qe_devs[i]->priv) { - struct sunqe *qe = (struct sunqe *)qe_devs[i]->priv; - - if (qe->qcregs) - sbus_iounmap(qe->qcregs, CREG_REG_SIZE); - if (qe->mregs) - sbus_iounmap(qe->mregs, MREGS_REG_SIZE); - if (qe->qe_block != NULL) - sbus_free_consistent(qe->qe_sdev, - PAGE_SIZE, - qe->qe_block, - qe->qblock_dvma); - if (qe->buffers != NULL) - sbus_free_consistent(qe->qe_sdev, - sizeof(struct sunqe_buffers), - qe->buffers, - qe->buffers_dvma); - } - kfree(qe_devs[i]); - } - } - if (qecp != NULL) { - if (qecp->gregs) - sbus_iounmap(qecp->gregs, GLOB_REG_SIZE); - kfree(qecp); + struct sunqe *qe = (struct sunqe *)qe_devs[i]->priv; + + if (qe->qcregs) + sbus_iounmap(qe->qcregs, CREG_REG_SIZE); + if (qe->mregs) + sbus_iounmap(qe->mregs, MREGS_REG_SIZE); + if (qe->qe_block) + sbus_free_consistent(qe->qe_sdev, + PAGE_SIZE, + qe->qe_block, + qe->qblock_dvma); + if (qe->buffers) + sbus_free_consistent(qe->qe_sdev, + sizeof(struct sunqe_buffers), + qe->buffers, + qe->buffers_dvma); } +out3: + sbus_iounmap(qecp->gregs, GLOB_REG_SIZE); +out2: + kfree(qecp); +out1: + i = 4; +out: + while (i--) + kfree(qe_devs[i]); return res; } diff -urN linux-2.5.70-bk10/drivers/net/tg3.c linux-2.5.70-bk11/drivers/net/tg3.c --- linux-2.5.70-bk10/drivers/net/tg3.c 2003-06-06 04:38:14.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/tg3.c 2003-06-06 04:38:24.000000000 -0700 @@ -6740,7 +6740,7 @@ } /* Configure DMA attributes. */ - if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) { + if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL)) { pci_using_dac = 1; if (pci_set_consistent_dma_mask(pdev, (u64) 0xffffffffffffffff)) { diff -urN linux-2.5.70-bk10/drivers/net/tun.c linux-2.5.70-bk11/drivers/net/tun.c --- linux-2.5.70-bk10/drivers/net/tun.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/tun.c 2003-06-06 04:38:24.000000000 -0700 @@ -551,10 +551,12 @@ if (!(tun->flags & TUN_PERSIST)) { dev_close(&tun->dev); unregister_netdevice(&tun->dev); - kfree(tun); } rtnl_unlock(); + + if (!(tun->flags & TUN_PERSIST)) + kfree(tun); return 0; } diff -urN linux-2.5.70-bk10/drivers/net/wireless/Kconfig linux-2.5.70-bk11/drivers/net/wireless/Kconfig --- linux-2.5.70-bk10/drivers/net/wireless/Kconfig 2003-06-06 04:38:14.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/wireless/Kconfig 2003-06-06 04:38:24.000000000 -0700 @@ -149,7 +149,7 @@ unsure, say N. comment "Wireless 802.11b ISA/PCI cards support" - depends on NET_RADIO && (ISA || PCI || ALL_PPC || PCMCIA) + depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA) config AIRO tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" @@ -169,7 +169,7 @@ config HERMES tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" - depends on NET_RADIO && (ALL_PPC || PCI || PCMCIA) + depends on NET_RADIO && (PPC_PMAC || PCI || PCMCIA) ---help--- A driver for 802.11b wireless cards based based on the "Hermes" or Intersil HFA384x (Prism 2) MAC controller. This includes the vast @@ -191,7 +191,7 @@ config APPLE_AIRPORT tristate "Apple Airport support (built-in)" - depends on ALL_PPC && HERMES + depends on PPC_PMAC && HERMES help Say Y here to support the Airport 802.11b wireless Ethernet hardware built into the Macintosh iBook and other recent PowerPC-based @@ -281,10 +281,25 @@ for location). You also want to check out the PCMCIA-HOWTO, available from . +config PCMCIA_ATMEL + tristate "Atmel at76c502/at76c504 PCMCIA cards" + depends on NET_RADIO && EXPERIMENTAL && PCMCIA + ---help--- + A driver for PCMCIA 802.11 wireless cards based on the + Atmel fast-vnet chips. This driver supports standard + Linux wireless extensions. + + Many cards based on this chipset do not have flash memory + and need their firmware loaded at start-up. If yours is + one of these, you will need to provide a firmware image + to be loaded into the card by the driver. The Atmel + firmware package can be downloaded from + http://www.thekelleys.org.uk/atmel/atmel_firmware.tar.gz + # yes, this works even when no drivers are selected config NET_WIRELESS bool - depends on NET_RADIO && (ISA || PCI || ALL_PPC || PCMCIA) + depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA) default y endmenu diff -urN linux-2.5.70-bk10/drivers/net/wireless/Makefile linux-2.5.70-bk11/drivers/net/wireless/Makefile --- linux-2.5.70-bk10/drivers/net/wireless/Makefile 2003-06-06 04:38:14.000000000 -0700 +++ linux-2.5.70-bk11/drivers/net/wireless/Makefile 2003-06-06 04:38:24.000000000 -0700 @@ -22,4 +22,5 @@ # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o +obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o atmel.o diff -urN linux-2.5.70-bk10/drivers/net/wireless/atmel.c linux-2.5.70-bk11/drivers/net/wireless/atmel.c --- linux-2.5.70-bk10/drivers/net/wireless/atmel.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk11/drivers/net/wireless/atmel.c 2003-06-06 04:38:24.000000000 -0700 @@ -0,0 +1,3943 @@ +/*** -*- linux-c -*- ********************************************************** + + Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. + + Copyright 2000-2001 ATMEL Corporation. + Copyright 2003 Simon Kelley. + + This code was developed from version 2.1.1 of the Atmel drivers, + released by Atmel corp. under the GPL in December 2002. It also + includes code from the Linux aironet drivers (C) Benjamin Reed, + and the Linux PCMCIA package, (C) David Hinds and the Linux wireless + extensions, (C) Jean Tourrilhes. + + The firmware module for reading the MAC address of the card comes from + net.russotto.AtmelMACFW, written by Matthew T. Russotto and copyright + by him. net.russotto.AtmelMACFW is used under the GPL license version 2. + This file contains the module in binary form and, under the terms + of the GPL, in source form. The source is located at the end of the file. + + For all queries about this code, please contact the current author, + Simon Kelley and not Atmel Corporation. + + 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 software 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 Atmel wireless lan drivers; 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_FW_LOADER +#include +#endif +#include "ieee802_11.h" + +#define DRIVER_MAJOR 0 +#define DRIVER_MINOR 7 + +MODULE_AUTHOR("Simon Kelley"); +MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("Atmel at76c50x wireless cards"); + +/* The name of the firmware file to be loaded + over-rides any automatic selection */ +static char *firmware = NULL; +module_param(firmware, charp, 0); + +#define MAX_SSID_LENGTH 32 +#define MGMT_JIFFIES (256 * HZ / 100) + +#define MAX_BSS_ENTRIES 64 + +/* registers */ +#define GCR 0x00 // (SIR0) General Configuration Register +#define BSR 0x02 // (SIR1) Bank Switching Select Register +#define AR 0x04 +#define DR 0x08 +#define MR1 0x12 // Mirror Register 1 +#define MR2 0x14 // Mirror Register 2 +#define MR3 0x16 // Mirror Register 3 +#define MR4 0x18 // Mirror Register 4 + +#define GPR1 0x0c +#define GPR2 0x0e +#define GPR3 0x10 +// +// Constants for the GCR register. +// +#define GCR_REMAP 0x0400 // Remap internal SRAM to 0 +#define GCR_SWRES 0x0080 // BIU reset (ARM and PAI are NOT reset) +#define GCR_CORES 0x0060 // Core Reset (ARM and PAI are reset) +#define GCR_ENINT 0x0002 // Enable Interrupts +#define GCR_ACKINT 0x0008 // Acknowledge Interrupts + +#define BSS_SRAM 0x0200 // AMBA module selection --> SRAM +#define BSS_IRAM 0x0100 // AMBA module selection --> IRAM +// +// Constants for the MR registers. +// +#define MAC_INIT_COMPLETE 0x0001 // MAC init has been completed +#define MAC_BOOT_COMPLETE 0x0010 // MAC boot has been completed +#define MAC_INIT_OK 0x0002 // MAC boot has been completed + +#define C80211_SUBTYPE_MGMT_ASS_REQUEST 0x00 +#define C80211_SUBTYPE_MGMT_ASS_RESPONSE 0x10 +#define C80211_SUBTYPE_MGMT_REASS_REQUEST 0x20 +#define C80211_SUBTYPE_MGMT_REASS_RESPONSE 0x30 +#define C80211_SUBTYPE_MGMT_ProbeRequest 0x40 +#define C80211_SUBTYPE_MGMT_ProbeResponse 0x50 +#define C80211_SUBTYPE_MGMT_BEACON 0x80 +#define C80211_SUBTYPE_MGMT_ATIM 0x90 +#define C80211_SUBTYPE_MGMT_DISASSOSIATION 0xA0 +#define C80211_SUBTYPE_MGMT_Authentication 0xB0 +#define C80211_SUBTYPE_MGMT_Deauthentication 0xC0 + +#define C80211_MGMT_AAN_OPENSYSTEM 0x0000 +#define C80211_MGMT_AAN_SHAREDKEY 0x0001 + +#define C80211_MGMT_CAPABILITY_ESS 0x0001 // see 802.11 p.58 +#define C80211_MGMT_CAPABILITY_IBSS 0x0002 // - " - +#define C80211_MGMT_CAPABILITY_CFPollable 0x0004 // - " - +#define C80211_MGMT_CAPABILITY_CFPollRequest 0x0008 // - " - +#define C80211_MGMT_CAPABILITY_Privacy 0x0010 // - " - + +#define C80211_MGMT_SC_Success 0 +#define C80211_MGMT_SC_Unspecified 1 +#define C80211_MGMT_SC_SupportCapabilities 10 +#define C80211_MGMT_SC_ReassDenied 11 +#define C80211_MGMT_SC_AssDenied 12 +#define C80211_MGMT_SC_AuthAlgNotSupported 13 +#define C80211_MGMT_SC_AuthTransSeqNumError 14 +#define C80211_MGMT_SC_AuthRejectChallenge 15 +#define C80211_MGMT_SC_AuthRejectTimeout 16 +#define C80211_MGMT_SC_AssDeniedHandleAP 17 +#define C80211_MGMT_SC_AssDeniedBSSRate 18 + +#define C80211_MGMT_ElementID_SSID 0 +#define C80211_MGMT_ElementID_SupportedRates 1 +#define C80211_MGMT_ElementID_ChallengeText 16 +#define C80211_MGMT_CAPABILITY_ShortPreamble 0x0020 + +struct get_set_mib { + u8 type; + u8 size; + u8 index; + u8 reserved; + u8 data[72]; +}; + +struct rx_desc { + u32 Next; + u16 MsduPos; + u16 MsduSize; + + u8 State; + u8 Status; + u8 Rate; + u8 Rssi; + u8 LinkQuality; + u8 PreambleType; + u16 Duration; + u32 RxTime; + +}; + +#define RX_DESC_FLAG_VALID 0x80 +#define RX_DESC_FLAG_CONSUMED 0x40 +#define RX_DESC_FLAG_IDLE 0x00 + +#define RX_STATUS_SUCCESS 0x00 + +#define RX_DESC_MSDU_POS_OFFSET 4 +#define RX_DESC_MSDU_SIZE_OFFSET 6 +#define RX_DESC_FLAGS_OFFSET 8 +#define RX_DESC_STATUS_OFFSET 9 +#define RX_DESC_RSSI_OFFSET 11 +#define RX_DESC_LINK_QUALITY_OFFSET 12 +#define RX_DESC_PREAMBLE_TYPE_OFFSET 13 +#define RX_DESC_DURATION_OFFSET 14 +#define RX_DESC_RX_TIME_OFFSET 16 + + +struct tx_desc { + u32 NextDescriptor; + u16 TxStartOfFrame; + u16 TxLength; + + u8 TxState; + u8 TxStatus; + u8 RetryCount; + + u8 TxRate; + u32 TxTime; + u8 Reserved; + u8 PacketType; + u16 HostTxLength; + +}; + + +#define TX_DESC_NEXT_OFFSET 0 +#define TX_DESC_POS_OFFSET 4 +#define TX_DESC_SIZE_OFFSET 6 +#define TX_DESC_FLAGS_OFFSET 8 +#define TX_DESC_STATUS_OFFSET 9 +#define TX_DESC_RETRY_OFFSET 10 +#define TX_DESC_RATE_OFFSET 11 +#define TX_DESC_PACKET_TYPE_OFFSET 17 +#define TX_DESC_HOST_LENGTH_OFFSET 18 + + + +/////////////////////////////////////////////////////// +// Host-MAC interface +/////////////////////////////////////////////////////// + +#define TX_STATUS_SUCCESS 0x00 + +#define TX_FIRM_OWN 0x80 +#define TX_DONE 0x40 + + +#define TX_ERROR 0x01 + +#define TX_PACKET_TYPE_DATA 0x01 +#define TX_PACKET_TYPE_MGMT 0x02 + +#define ISR_EMPTY 0x00 // no bits set in ISR +#define ISR_TxCOMPLETE 0x01 // packet transmitted +#define ISR_RxCOMPLETE 0x02 // packet received +#define ISR_RxFRAMELOST 0x04 // Rx Frame lost +#define ISR_FATAL_ERROR 0x08 // Fatal error +#define ISR_COMMAND_COMPLETE 0x10 // command completed +#define ISR_OUT_OF_RANGE 0x20 // command completed +#define ISR_IBSS_MERGE 0x40 // (4.1.2.30): IBSS merge +#define ISR_GENERIC_IRQ 0x80 + + +#define Local_Mib_Type 0x01 +#define Mac_Address_Mib_Type 0x02 +#define Mac_Mib_Type 0x03 +#define Statistics_Mib_Type 0x04 +#define Mac_Mgmt_Mib_Type 0x05 +#define Mac_Wep_Mib_Type 0x06 +#define Phy_Mib_Type 0x07 +#define Multi_Domain_MIB 0x08 + +#define MAC_MGMT_MIB_CUR_BSSID_POS 14 +#define MAC_MIB_FRAG_THRESHOLD_POS 8 +#define MAC_MIB_RTS_THRESHOLD_POS 10 +#define MAC_MIB_SHORT_RETRY_POS 16 +#define MAC_MIB_LONG_RETRY_POS 17 +#define MAC_MIB_SHORT_RETRY_LIMIT_POS 16 +#define MAC_MGMT_MIB_BEACON_PER_POS 0 +#define MAC_MGMT_MIB_STATION_ID_POS 6 +#define MAC_MGMT_MIB_CUR_PRIVACY_POS 11 +#define MAC_MGMT_MIB_CUR_BSSID_POS 14 +#define MAC_MGMT_MIB_PS_MODE_POS 53 +#define MAC_MGMT_MIB_LISTEN_INTERVAL_POS 54 +#define MAC_MGMT_MIB_MULTI_DOMAIN_IMPLEMENTED 56 +#define MAC_MGMT_MIB_MULTI_DOMAIN_ENABLED 57 +#define PHY_MIB_CHANNEL_POS 14 +#define PHY_MIB_RATE_SET_POS 20 +#define PHY_MIB_REG_DOMAIN_POS 26 +#define LOCAL_MIB_AUTO_TX_RATE_POS 3 +#define LOCAL_MIB_SSID_SIZE 5 +#define LOCAL_MIB_TX_PROMISCUOUS_POS 6 +#define LOCAL_MIB_TX_MGMT_RATE_POS 7 +#define LOCAL_MIB_TX_CONTROL_RATE_POS 8 +#define LOCAL_MIB_PREAMBLE_TYPE 9 +#define MAC_ADDR_MIB_MAC_ADDR_POS 0 + + +#define CMD_Set_MIB_Vars 0x01 +#define CMD_Get_MIB_Vars 0x02 +#define CMD_Scan 0x03 +#define CMD_Join 0x04 +#define CMD_Start 0x05 +#define CMD_EnableRadio 0x06 +#define CMD_DisableRadio 0x07 +#define CMD_SiteSurvey 0x0B + +#define CMD_STATUS_IDLE 0x00 +#define CMD_STATUS_COMPLETE 0x01 +#define CMD_STATUS_UNKNOWN 0x02 +#define CMD_STATUS_INVALID_PARAMETER 0x03 +#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04 +#define CMD_STATUS_TIME_OUT 0x07 +#define CMD_STATUS_IN_PROGRESS 0x08 +#define CMD_STATUS_REJECTED_RADIO_OFF 0x09 +#define CMD_STATUS_HOST_ERROR 0xFF +#define CMD_STATUS_BUSY 0xFE + + +#define CMD_BLOCK_COMMAND_OFFSET 0 +#define CMD_BLOCK_STATUS_OFFSET 1 +#define CMD_BLOCK_PARAMETERS_OFFSET 4 + +#define SCAN_OPTIONS_SITE_SURVEY 0x80 + +#define MGMT_FRAME_BODY_OFFSET 24 +#define MAX_AUTHENTICATION_RETRIES 3 +#define MAX_ASSOCIATION_RETRIES 3 + +#define AUTHENTICATION_RESPONSE_TIME_OUT 1000 + +#define MAX_WIRELESS_BODY 2316 /* mtu is 2312, CRC is 4 */ +#define LOOP_RETRY_LIMIT 500000 + +#define ACTIVE_MODE 1 +#define PS_MODE 2 + +/////////////////////////////////////////////////////////////////////////// +// 802.11 related definitions +/////////////////////////////////////////////////////////////////////////// + +// +// Regulatory Domains +// + +#define REG_DOMAIN_FCC 0x10 //Channels 1-11 USA +#define REG_DOMAIN_DOC 0x20 //Channel 1-11 Canada +#define REG_DOMAIN_ETSI 0x30 //Channel 1-13 Europe (ex Spain/France) +#define REG_DOMAIN_SPAIN 0x31 //Channel 10-11 Spain +#define REG_DOMAIN_FRANCE 0x32 //Channel 10-13 France +#define REG_DOMAIN_MKK 0x40 //Channel 14 Japan +#define REG_DOMAIN_MKK1 0x41 //Channel 1-14 Japan(MKK1) +#define REG_DOMAIN_ISRAEL 0x50 //Channel 3-9 ISRAEL + +#define BSS_TYPE_AD_HOC 1 +#define BSS_TYPE_INFRASTRUCTURE 2 + +#define SCAN_TYPE_ACTIVE 0 +#define SCAN_TYPE_PASSIVE 1 + +#define LONG_PREAMBLE 0 +#define SHORT_PREAMBLE 1 +#define AUTO_PREAMBLE 2 + +#define DATA_FRAME_WS_HEADER_SIZE 30 + +/* promiscuous mode control */ +#define PROM_MODE_OFF 0x0 +#define PROM_MODE_UNKNOWN 0x1 +#define PROM_MODE_CRC_FAILED 0x2 +#define PROM_MODE_DUPLICATED 0x4 +#define PROM_MODE_MGMT 0x8 +#define PROM_MODE_CTRL 0x10 +#define PROM_MODE_BAD_PROTOCOL 0x20 + + +#define IFACE_INT_STATUS_OFFSET 0 +#define IFACE_INT_MASK_OFFSET 1 +#define IFACE_LOCKOUT_HOST_OFFSET 2 +#define IFACE_LOCKOUT_MAC_OFFSET 3 +#define IFACE_FUNC_CTRL_OFFSET 28 +#define IFACE_MAC_STAT_OFFSET 30 +#define IFACE_GENERIC_INT_TYPE_OFFSET 32 +// +// IFACE MACROS & definitions +// +// + +// FuncCtrl field: +// +#define FUNC_CTRL_TxENABLE 0x10 +#define FUNC_CTRL_RxENABLE 0x20 +#define FUNC_CTRL_INIT_COMPLETE 0x01 + +/* A stub firmware image which reads the MAC address from NVRAM on the card. + For copyright information and source see the end of this file. */ +static u8 mac_reader[] = { + 0x06,0x00,0x00,0xea,0x04,0x00,0x00,0xea,0x03,0x00,0x00,0xea,0x02,0x00,0x00,0xea, + 0x01,0x00,0x00,0xea,0x00,0x00,0x00,0xea,0xff,0xff,0xff,0xea,0xfe,0xff,0xff,0xea, + 0xd3,0x00,0xa0,0xe3,0x00,0xf0,0x21,0xe1,0x0e,0x04,0xa0,0xe3,0x00,0x10,0xa0,0xe3, + 0x81,0x11,0xa0,0xe1,0x00,0x10,0x81,0xe3,0x00,0x10,0x80,0xe5,0x1c,0x10,0x90,0xe5, + 0x10,0x10,0xc1,0xe3,0x1c,0x10,0x80,0xe5,0x01,0x10,0xa0,0xe3,0x08,0x10,0x80,0xe5, + 0x02,0x03,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0xb0,0x10,0xc0,0xe1,0xb4,0x10,0xc0,0xe1, + 0xb8,0x10,0xc0,0xe1,0xbc,0x10,0xc0,0xe1,0x56,0xdc,0xa0,0xe3,0x21,0x00,0x00,0xeb, + 0x0a,0x00,0xa0,0xe3,0x1a,0x00,0x00,0xeb,0x10,0x00,0x00,0xeb,0x07,0x00,0x00,0xeb, + 0x02,0x03,0xa0,0xe3,0x02,0x14,0xa0,0xe3,0xb4,0x10,0xc0,0xe1,0x4c,0x10,0x9f,0xe5, + 0xbc,0x10,0xc0,0xe1,0x10,0x10,0xa0,0xe3,0xb8,0x10,0xc0,0xe1,0xfe,0xff,0xff,0xea, + 0x00,0x40,0x2d,0xe9,0x00,0x20,0xa0,0xe3,0x02,0x3c,0xa0,0xe3,0x00,0x10,0xa0,0xe3, + 0x28,0x00,0x9f,0xe5,0x37,0x00,0x00,0xeb,0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, + 0x00,0x40,0x2d,0xe9,0x12,0x2e,0xa0,0xe3,0x06,0x30,0xa0,0xe3,0x00,0x10,0xa0,0xe3, + 0x02,0x04,0xa0,0xe3,0x2f,0x00,0x00,0xeb,0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, + 0x00,0x02,0x00,0x02,0x80,0x01,0x90,0xe0,0x01,0x00,0x00,0x0a,0x01,0x00,0x50,0xe2, + 0xfc,0xff,0xff,0xea,0x1e,0xff,0x2f,0xe1,0x80,0x10,0xa0,0xe3,0xf3,0x06,0xa0,0xe3, + 0x00,0x10,0x80,0xe5,0x00,0x10,0xa0,0xe3,0x00,0x10,0x80,0xe5,0x01,0x10,0xa0,0xe3, + 0x04,0x10,0x80,0xe5,0x00,0x10,0x80,0xe5,0x0e,0x34,0xa0,0xe3,0x1c,0x10,0x93,0xe5, + 0x02,0x1a,0x81,0xe3,0x1c,0x10,0x83,0xe5,0x58,0x11,0x9f,0xe5,0x30,0x10,0x80,0xe5, + 0x54,0x11,0x9f,0xe5,0x34,0x10,0x80,0xe5,0x38,0x10,0x80,0xe5,0x3c,0x10,0x80,0xe5, + 0x10,0x10,0x90,0xe5,0x08,0x00,0x90,0xe5,0x1e,0xff,0x2f,0xe1,0xf3,0x16,0xa0,0xe3, + 0x08,0x00,0x91,0xe5,0x05,0x00,0xa0,0xe3,0x0c,0x00,0x81,0xe5,0x10,0x00,0x91,0xe5, + 0x02,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0xff,0x00,0xa0,0xe3,0x0c,0x00,0x81,0xe5, + 0x10,0x00,0x91,0xe5,0x02,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x91,0xe5, + 0x10,0x00,0x91,0xe5,0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x91,0xe5, + 0xff,0x00,0x00,0xe2,0x1e,0xff,0x2f,0xe1,0x30,0x40,0x2d,0xe9,0x00,0x50,0xa0,0xe1, + 0x03,0x40,0xa0,0xe1,0xa2,0x02,0xa0,0xe1,0x08,0x00,0x00,0xe2,0x03,0x00,0x80,0xe2, + 0xd8,0x10,0x9f,0xe5,0x00,0x00,0xc1,0xe5,0x01,0x20,0xc1,0xe5,0xe2,0xff,0xff,0xeb, + 0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x1a,0x14,0x00,0xa0,0xe3,0xc4,0xff,0xff,0xeb, + 0x04,0x20,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x02,0x00,0xa0,0xe3,0x01,0x00,0x00,0xeb, + 0x30,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x70,0x40,0x2d,0xe9,0xf3,0x46,0xa0,0xe3, + 0x00,0x30,0xa0,0xe3,0x00,0x00,0x50,0xe3,0x08,0x00,0x00,0x9a,0x8c,0x50,0x9f,0xe5, + 0x03,0x60,0xd5,0xe7,0x0c,0x60,0x84,0xe5,0x10,0x60,0x94,0xe5,0x02,0x00,0x16,0xe3, + 0xfc,0xff,0xff,0x0a,0x01,0x30,0x83,0xe2,0x00,0x00,0x53,0xe1,0xf7,0xff,0xff,0x3a, + 0xff,0x30,0xa0,0xe3,0x0c,0x30,0x84,0xe5,0x08,0x00,0x94,0xe5,0x10,0x00,0x94,0xe5, + 0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x94,0xe5,0x00,0x00,0xa0,0xe3, + 0x00,0x00,0x52,0xe3,0x0b,0x00,0x00,0x9a,0x10,0x50,0x94,0xe5,0x02,0x00,0x15,0xe3, + 0xfc,0xff,0xff,0x0a,0x0c,0x30,0x84,0xe5,0x10,0x50,0x94,0xe5,0x01,0x00,0x15,0xe3, + 0xfc,0xff,0xff,0x0a,0x08,0x50,0x94,0xe5,0x01,0x50,0xc1,0xe4,0x01,0x00,0x80,0xe2, + 0x02,0x00,0x50,0xe1,0xf3,0xff,0xff,0x3a,0xc8,0x00,0xa0,0xe3,0x98,0xff,0xff,0xeb, + 0x70,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x01,0x0c,0x00,0x02,0x01,0x02,0x00,0x02, + 0x00,0x01,0x00,0x02 +}; + +struct atmel_private { + void *card; /* Bus dependent stucture varies for PCcard */ + int (*present_callback)(void *); /* And callback which uses it */ + char firmware_id[32]; + unsigned char *firmware; + int firmware_length; + struct timer_list management_timer; + struct net_device *dev; + struct device *sys_dev; + struct iw_statistics wstats; + struct net_device_stats stats; // device stats + spinlock_t irqlock, timerlock; // spinlocks + enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type; + enum { + CARD_TYPE_PARALLEL_FLASH, + CARD_TYPE_SPI_FLASH, + CARD_TYPE_EEPROM + } card_type; + int is3com; /* is this a 3com card? they are uniquely borken */ + int do_rx_crc; /* If we need to CRC incoming packets */ + int probe_crc; /* set if we don't yet know */ + int crc_ok_cnt, crc_ko_cnt; /* counters for probing */ + u16 rx_desc_head; + u16 tx_desc_free, tx_desc_head, tx_desc_tail, tx_desc_previous; + u16 tx_free_mem, tx_buff_head, tx_buff_tail; + + u16 frag_seq, frag_len, frag_no; + u8 frag_source[6]; + + int wep_key_len[4]; /* need to know these and not stored in Mib. */ + struct { /* NB this is matched to the hardware, don't change. */ + u8 wep_is_on; + u8 default_key; /* 0..3 */ + u8 reserved; + u8 exclude_unencrypted; + + u32 WEPICV_error_count; + u32 WEP_excluded_count; + + u8 wep_keys[4][13]; + u8 encryption_level; /* 0, 1, 2 */ + u8 reserved2[3]; + } wep; + + u16 host_info_base; + struct host_info_struct { + /* NB this is matched to the hardware, don't change. */ + u8 volatile int_status; + u8 volatile int_mask; + u8 volatile lockout_host; + u8 volatile lockout_mac; + + u16 tx_buff_pos; + u16 tx_buff_size; + u16 tx_desc_pos; + u16 tx_desc_count; + + u16 rx_buff_pos; + u16 rx_buff_size; + u16 rx_desc_pos; + u16 rx_desc_count; + + u16 build_version; + u16 command_pos; + + u16 major_version; + u16 minor_version; + + u16 func_ctrl; + u16 mac_status; + u16 generic_IRQ_type; + u8 reserved[2]; + } host_info; + + enum { + STATION_STATE_INITIALIZING, + STATION_STATE_SCANNING, + STATION_STATE_JOINNING, + STATION_STATE_AUTHENTICATING, + STATION_STATE_ASSOCIATING, + STATION_STATE_READY, + STATION_STATE_REASSOCIATING, + STATION_STATE_FORCED_JOINNING, + STATION_STATE_FORCED_JOIN_FAILURE, + STATION_STATE_DOWN, + STATION_STATE_NO_CARD, + STATION_STATE_MGMT_ERROR + } station_state; + + int operating_mode, power_mode; + time_t last_qual; + int beacons_this_sec; + u64 last_beacon_timestamp; + int channel; + int reg_domain; + int tx_rate; + int auto_tx_rate;; + int rts_threshold; + int frag_threshold; + int long_retry, short_retry; + int preamble; + int default_beacon_period, beacon_period, listen_interval; + int CurrentAuthentTransactionSeqNum, ExpectedAuthentTransactionSeqNum; + int AuthenticationRequestRetryCnt, AssociationRequestRetryCnt, ReAssociationRequestRetryCnt; + enum { + SITE_SURVEY_IDLE, + SITE_SURVEY_IN_PROGRESS, + SITE_SURVEY_COMPLETED + } site_survey_state; + time_t last_survey; + + int station_was_associated, station_is_associated; + int fast_scan; + + struct bss_info { + int channel; + int SSIDsize; + int RSSI; + int UsingWEP; + int preamble; + int beacon_period; + int BSStype; + u8 BSSID[6]; + u8 SSID[MAX_SSID_LENGTH]; + } BSSinfo[MAX_BSS_ENTRIES]; + int BSS_list_entries, current_BSS; + int connect_to_any_BSS; + int SSID_size, new_SSID_size; + u8 CurrentBSSID[6], BSSID[6]; + u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH]; + u8 rx_buf[MAX_WIRELESS_BODY]; + +}; + +static u8 atmel_basic_rates[4] = {0x82,0x84,0x0b,0x16}; + +static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void atmel_copy_to_card(struct net_device *dev, u16 dest, unsigned char *src, u16 len); +static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, u16 src, u16 len); +static void atmel_set_gcr(struct net_device *dev, u16 mask); +static void atmel_clear_gcr(struct net_device *dev, u16 mask); +static int atmel_lock_mac(struct atmel_private *priv); +static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); +static void atmel_command_irq(struct atmel_private *priv); +static int atmel_validate_channel(struct atmel_private *priv, int channel); +static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 frame_len, u8 rssi); +static void atmel_management_timer(u_long a); +static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size); +static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size); +static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, + u8 *body, int body_len); + +static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); +static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data); +static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 data); +static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len); +static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len); +static void atmel_scan(struct atmel_private *priv, int specific_ssid); +static void atmel_join_bss(struct atmel_private *priv, int bss_index); +static void atmel_smooth_qual(struct atmel_private *priv); +static void atmel_writeAR(struct net_device *dev, u16 data); +static int probe_atmel_card(struct net_device *dev); +int reset_atmel_card(struct net_device *dev ); +static void atmel_enter_state(struct atmel_private *priv, int new_state); + +static inline u16 atmel_hi(struct atmel_private *priv, u16 offset) +{ + return priv->host_info_base + offset; +} + +static inline u16 atmel_co(struct atmel_private *priv, u16 offset) +{ + return priv->host_info.command_pos + offset; +} + +static inline u16 atmel_rx(struct atmel_private *priv, u16 offset, u16 desc) +{ + return priv->host_info.rx_desc_pos + (sizeof(struct rx_desc) * desc) + offset; +} + +static inline u16 atmel_tx(struct atmel_private *priv, u16 offset, u16 desc) +{ + return priv->host_info.tx_desc_pos + (sizeof(struct tx_desc) * desc) + offset; +} + +static inline u8 atmel_read8(struct net_device *dev, u16 offset) +{ + return inb(dev->base_addr + offset); +} + +static inline void atmel_write8(struct net_device *dev, u16 offset, u8 data) +{ + outb(data, dev->base_addr + offset); +} + +static inline u16 atmel_read16(struct net_device *dev, u16 offset) +{ + return inw(dev->base_addr + offset); +} + +static inline void atmel_write16(struct net_device *dev, u16 offset, u16 data) +{ + outw(data, dev->base_addr + offset); +} + + +static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos) +{ + atmel_writeAR(priv->dev, pos); + return atmel_read8(priv->dev, DR); +} + +static inline void atmel_wmem8(struct atmel_private *priv, u16 pos, u16 data) +{ + atmel_writeAR(priv->dev, pos); + atmel_write8(priv->dev, DR, data); +} + +static inline u16 atmel_rmem16(struct atmel_private *priv, u16 pos) +{ + atmel_writeAR(priv->dev, pos); + return atmel_read16(priv->dev, DR); +} + +static inline void atmel_wmem16(struct atmel_private *priv, u16 pos, u16 data) +{ + atmel_writeAR(priv->dev, pos); + atmel_write16(priv->dev, DR, data); +} + +static const struct iw_handler_def atmel_handler_def; + +static void tx_done_irq(struct atmel_private *priv) +{ + int i; + + for (i = 0; + atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE && + i < priv->host_info.tx_desc_count; + i++) { + + u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head)); + u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head)); + u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head)); + + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head), 0); + + priv->tx_free_mem += msdu_size; + priv->tx_desc_free++; + + if (priv->tx_buff_head + msdu_size > (priv->host_info.tx_buff_pos + priv->host_info.tx_buff_size)) + priv->tx_buff_head = 0; + else + priv->tx_buff_head += msdu_size; + + if (priv->tx_desc_head < (priv->host_info.tx_desc_count - 1)) + priv->tx_desc_head++ ; + else + priv->tx_desc_head = 0; + + if (type == TX_PACKET_TYPE_DATA) { + if (status == TX_STATUS_SUCCESS) + priv->stats.tx_packets++; + else + priv->stats.tx_errors++; + netif_wake_queue(priv->dev); + } + } +} + +static u16 find_tx_buff(struct atmel_private *priv, u16 len) +{ + u16 bottom_free = priv->host_info.tx_buff_size - priv->tx_buff_tail; + + if (priv->tx_desc_free == 3 || priv->tx_free_mem < len) + return 0; + + if (bottom_free >= len) + return priv->host_info.tx_buff_pos + priv->tx_buff_tail; + + if (priv->tx_free_mem - bottom_free >= len) { + priv->tx_buff_tail = 0; + return priv->host_info.tx_buff_pos; + } + + return 0; +} + +static void tx_update_descriptor(struct atmel_private *priv, u16 len, u16 buff, u8 type) +{ + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff); + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len); + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len); + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type); + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate); + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0); + atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L); + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN); + if (priv->tx_desc_previous != priv->tx_desc_tail) + atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0); + priv->tx_desc_previous = priv->tx_desc_tail; + if (priv->tx_desc_tail < (priv->host_info.tx_desc_count -1 )) + priv->tx_desc_tail++; + else + priv->tx_desc_tail = 0; + priv->tx_desc_free--; + priv->tx_free_mem -= len; + +} + +static int start_tx (struct sk_buff *skb, struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *)dev->priv; + struct ieee802_11_hdr header; + unsigned long flags; + u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + + if(priv->station_state != STATION_STATE_READY) { + priv->stats.tx_errors++; + return 0; + } + + if (priv->card && priv->present_callback && + !(*priv->present_callback)(priv->card)) { + priv->stats.tx_errors++; + return 0; + } + + /* first ensure the timer func cannot run */ + spin_lock_bh(&priv->timerlock); + /* then stop the hardware ISR */ + spin_lock_irqsave(&priv->irqlock, flags); + /* nb doing the above in the opposite order will deadlock */ + + /* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the + 12 first bytes (containing DA/SA) and put them in the appropriate fields of + the Wireless Header. Thus the packet length is then the initial + 18 (+30-12) */ + + if (!(buff = find_tx_buff(priv, len + 18))) { + priv->stats.tx_dropped++; + spin_unlock_irqrestore(&priv->irqlock, flags); + spin_unlock_bh(&priv->timerlock); + netif_stop_queue(dev); + return 1; + } + + frame_ctl = IEEE802_11_FTYPE_DATA; + header.duration_id = 0; + header.seq_ctl = 0; + if (priv->wep.wep_is_on) + frame_ctl |= IEEE802_11_FCTL_WEP; + if (priv->operating_mode == IW_MODE_ADHOC) { + memcpy(&header.addr1, skb->data, 6); + memcpy(&header.addr2, dev->dev_addr, 6); + memcpy(&header.addr3, priv->BSSID, 6); + } else { + frame_ctl |= IEEE802_11_FCTL_TODS; + memcpy(&header.addr1, priv->CurrentBSSID, 6); + memcpy(&header.addr2, dev->dev_addr, 6); + memcpy(&header.addr3, skb->data, 6); + } + + header.frame_ctl = cpu_to_le16(frame_ctl); + /* Copy the wireless header into the card */ + atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); + /* Copy the packet sans its 802.3 header addresses which have been replaced */ + atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12); + priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE; + + tx_update_descriptor(priv, len + 18, buff, TX_PACKET_TYPE_DATA); + dev->trans_start = jiffies; + priv->stats.tx_bytes += len; + + spin_unlock_irqrestore(&priv->irqlock, flags); + spin_unlock_bh(&priv->timerlock); + dev_kfree_skb(skb); + + return 0; +} + +static void atmel_transmit_management_frame(struct atmel_private *priv, + struct ieee802_11_hdr *header, + u8 *body, int body_len) +{ + u16 buff; + int len = MGMT_FRAME_BODY_OFFSET + body_len; + + if (!(buff = find_tx_buff(priv, len))) + return; + + atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET); + atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len); + priv->tx_buff_tail += len; + tx_update_descriptor(priv, len, buff, TX_PACKET_TYPE_MGMT); +} + +static void fast_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 msdu_size, u16 rx_packet_loc, u32 crc) +{ + /* fast path: unfragmented packet copy directly into skbuf */ + u8 mac4[6]; + struct sk_buff *skb; + unsigned char *skbp; + + /* get the final, mac 4 header field, this tells us encapsulation */ + atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6); + msdu_size -= 6; + + if (priv->do_rx_crc) { + crc = crc32_le(crc, mac4, 6); + msdu_size -= 4; + } + + if (!(skb = dev_alloc_skb(msdu_size + 14))) { + priv->stats.rx_dropped++; + return; + } + + skb_reserve(skb, 2); + skbp = skb_put(skb, msdu_size + 12); + atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size); + + if (priv->do_rx_crc) { + u32 netcrc; + crc = crc32_le(crc, skbp + 12, msdu_size); + atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); + if ((crc ^ 0xffffffff) != netcrc) { + priv->stats.rx_crc_errors++; + dev_kfree_skb(skb); + return; + } + } + + memcpy(skbp, header->addr1, 6); /* destination address */ + if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) + memcpy(&skbp[6], header->addr3, 6); + else + memcpy(&skbp[6], header->addr2, 6); /* source address */ + + priv->dev->last_rx=jiffies; + skb->dev = priv->dev; + skb->protocol = eth_type_trans(skb, priv->dev); + skb->ip_summed = CHECKSUM_NONE; + netif_rx(skb); + priv->stats.rx_bytes += 12 + msdu_size; + priv->stats.rx_packets++; +} + +/* Test to see if the packet in card memory at packet_loc has a valid CRC + It doesn't matter that this is slow: it is only used to proble the first few packets. */ +static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) +{ + int i = msdu_size - 4; + u32 netcrc, crc = 0xffffffff; + + if (msdu_size < 4) + return 0; + + atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4); + + atmel_writeAR(priv->dev, packet_loc); + while (i--) { + u8 octet = atmel_read8(priv->dev, DR); + crc = crc32_le(crc, &octet, 1); + } + + return (crc ^ 0xffffffff) == netcrc; +} + +static void frag_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags) +{ + u8 mac4[6]; + u8 source[6]; + struct sk_buff *skb; + + if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) + memcpy(source, header->addr3, 6); + else + memcpy(source, header->addr2, 6); + + rx_packet_loc += 24; /* skip header */ + + if (priv->do_rx_crc) + msdu_size -= 4; + + if (frag_no == 0) { /* first fragment */ + atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, 6); + msdu_size -= 6; + rx_packet_loc += 6; + + if (priv->do_rx_crc) + crc = crc32_le(crc, mac4, 6); + + priv->frag_seq = seq_no; + priv->frag_no = 1; + priv->frag_len = msdu_size; + memcpy(priv->frag_source, source, 6); + memcpy(&priv->rx_buf[6], source, 6); + memcpy(priv->rx_buf, header->addr1, 6); + + atmel_copy_to_host(priv->dev, &priv->rx_buf[12], rx_packet_loc, msdu_size); + + if (priv->do_rx_crc) { + u32 netcrc; + crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); + atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); + if ((crc ^ 0xffffffff) != netcrc) { + priv->stats.rx_crc_errors++; + memset(priv->frag_source, 0xff, 6); + } + } + + } else if (priv->frag_no == frag_no && + priv->frag_seq == seq_no && + memcmp(priv->frag_source, source, 6) == 0) { + + atmel_copy_to_host(priv->dev, &priv->rx_buf[12 + priv->frag_len], + rx_packet_loc, msdu_size); + if (priv->do_rx_crc) { + u32 netcrc; + crc = crc32_le(crc, + &priv->rx_buf[12 + priv->frag_len], + msdu_size); + atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); + if ((crc ^ 0xffffffff) != netcrc) { + priv->stats.rx_crc_errors++; + memset(priv->frag_source, 0xff, 6); + more_frags = 1; /* don't send broken assembly */ + } + } + + priv->frag_len += msdu_size; + priv->frag_no++; + + if (!more_frags) { /* last one */ + memset(priv->frag_source, 0xff, 6); + if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { + priv->stats.rx_dropped++; + } else { + skb_reserve(skb, 2); + memcpy(skb_put(skb, priv->frag_len + 12), + priv->rx_buf, + priv->frag_len + 12); + priv->dev->last_rx = jiffies; + skb->dev = priv->dev; + skb->protocol = eth_type_trans(skb, priv->dev); + skb->ip_summed = CHECKSUM_NONE; + netif_rx(skb); + priv->stats.rx_bytes += priv->frag_len + 12; + priv->stats.rx_packets++; + } + } + + } else + priv->wstats.discard.fragment++; +} + +static void rx_done_irq(struct atmel_private *priv) +{ + int i; + struct ieee802_11_hdr header; + + for (i = 0; + atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && + i < priv->host_info.rx_desc_count; + i++) { + + u16 msdu_size, rx_packet_loc, frame_ctl, seq_control; + u8 status = atmel_rmem8(priv, atmel_rx(priv, RX_DESC_STATUS_OFFSET, priv->rx_desc_head)); + u32 crc = 0xffffffff; + + if (status != RX_STATUS_SUCCESS) { + if (status == 0xc1) /* determined by experiment */ + priv->wstats.discard.nwid++; + else + priv->stats.rx_errors++; + goto next; + } + + msdu_size = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_SIZE_OFFSET, priv->rx_desc_head)); + rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); + + if (msdu_size < 30) { + priv->stats.rx_errors++; + goto next; + } + + /* Get header as far as end of seq_ctl */ + atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); + frame_ctl = le16_to_cpu(header.frame_ctl); + seq_control = le16_to_cpu(header.seq_ctl); + + /* probe for CRC use here if needed once five packets have arrived with + the same crc status, we assume we know what's happening and stop probing */ + if (priv->probe_crc) { + if (!priv->wep.wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP)) { + priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size); + } else { + priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24); + } + if (priv->do_rx_crc) { + if (priv->crc_ok_cnt++ > 5) + priv->probe_crc = 0; + } else { + if (priv->crc_ko_cnt++ > 5) + priv->probe_crc = 0; + } + } + + /* don't CRC header when WEP in use */ + if (priv->do_rx_crc && (!priv->wep.wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP))) { + crc = crc32_le(0xffffffff, (unsigned char *)&header, 24); + } + msdu_size -= 24; /* header */ + + if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_DATA) { + + int more_fragments = frame_ctl & IEEE802_11_FCTL_MOREFRAGS; + u8 packet_fragment_no = seq_control & IEEE802_11_SCTL_FRAG; + u16 packet_sequence_no = (seq_control & IEEE802_11_SCTL_SEQ) >> 4; + + if (!more_fragments && packet_fragment_no == 0 ) { + fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc); + } else { + frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc, + packet_sequence_no, packet_fragment_no, more_fragments); + } + } + + if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_MGMT) { + /* copy rest of packet into buffer */ + atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size); + + /* we use the same buffer for frag reassembly and control packets */ + memset(priv->frag_source, 0xff, 6); + + if (priv->do_rx_crc) { + /* last 4 octets is crc */ + msdu_size -= 4; + crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); + if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) { + priv->stats.rx_crc_errors++; + goto next; + } + } + + atmel_management_frame(priv, &header, msdu_size, + atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head))); + } + + next: + /* release descriptor */ + atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED); + + if (priv->rx_desc_head < (priv->host_info.rx_desc_count - 1)) + priv->rx_desc_head++; + else + priv->rx_desc_head = 0; + } +} + +static void reset_irq_status(struct atmel_private *priv, u8 mask) +{ + u8 isr; + + atmel_lock_mac(priv); + isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); + isr ^= mask; + atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); + atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); +} + +static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct atmel_private *priv = (struct atmel_private *) dev->priv; + u8 isr; + + if (priv->card && priv->present_callback && + !(*priv->present_callback)(priv->card)) + return IRQ_HANDLED; + + atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ + + while (1) { + if (!atmel_lock_mac(priv)) { + printk(KERN_ALERT "%s: MAC gone away in ISR.\n", dev->name); + /* bad things - don't re-enable interrupts */ + return IRQ_HANDLED; + } + + isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); + atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); + if (isr) + atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */ + else + break; /* no pending irqs */ + + if (isr & ISR_OUT_OF_RANGE) { + reset_irq_status(priv, ISR_OUT_OF_RANGE); + if(priv->operating_mode == IW_MODE_INFRA && + priv->station_state == STATION_STATE_READY) { + priv->station_is_associated = 0; + atmel_scan(priv, 1); + } + } else if (isr & ISR_RxCOMPLETE) { + reset_irq_status(priv, ISR_RxCOMPLETE); + rx_done_irq(priv); + } else if (isr & ISR_TxCOMPLETE) { + reset_irq_status(priv, ISR_TxCOMPLETE); + tx_done_irq(priv); + } else if (isr & ISR_RxFRAMELOST) { + reset_irq_status(priv, ISR_RxFRAMELOST); + priv->wstats.discard.misc++; + rx_done_irq(priv); + } else if (isr & ISR_FATAL_ERROR) { + reset_irq_status(priv, ISR_FATAL_ERROR); + printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name); + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + } else if (isr & ISR_COMMAND_COMPLETE) { + reset_irq_status(priv, ISR_COMMAND_COMPLETE); + atmel_command_irq(priv); + } else if (isr & ISR_IBSS_MERGE) { + reset_irq_status(priv, ISR_IBSS_MERGE); + atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, + priv->CurrentBSSID, 6); + } else if (isr & ISR_GENERIC_IRQ) { + reset_irq_status(priv, ISR_GENERIC_IRQ); + printk(KERN_INFO "%s: Generic_irq recieved.\n", dev->name); + } + } + + atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ + return IRQ_HANDLED; +} + + +static struct net_device_stats *atmel_get_stats (struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *)dev->priv; + return &priv->stats; +} + +static struct iw_statistics *atmel_get_wireless_stats (struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *)dev->priv; + + /* update the link quality here in case we are seeing no beacons + at all to drive the process */ + atmel_smooth_qual(priv); + + priv->wstats.status = priv->station_state; + + if (priv->operating_mode == IW_MODE_INFRA) { + if (priv->station_state != STATION_STATE_READY) { + priv->wstats.qual.qual = 0; + priv->wstats.qual.level = 0; + } + priv->wstats.qual.noise = 0; + priv->wstats.qual.updated = 7; + } else { + // Quality levels cannot be determined in ad-hoc mode, + // because we can 'hear' more that one remote station. + priv->wstats.qual.qual = 0; + priv->wstats.qual.level = 0; + priv->wstats.qual.noise = 0; + priv->wstats.qual.updated = 0; + priv->wstats.miss.beacon = 0; + } + + return (&priv->wstats); +} + +static int atmel_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > 2312)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +static int atmel_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + memcpy (dev->dev_addr, addr->sa_data, dev->addr_len); + reset_atmel_card(dev); + return 0; +} + +static int atmel_open (struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *) dev->priv; + priv->station_state = STATION_STATE_INITIALIZING; + if (!reset_atmel_card(dev)) { + priv->station_state = STATION_STATE_DOWN; + return -EAGAIN; + } + return 0; +} + +static int atmel_close (struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *) dev->priv; + + if (netif_running(dev)) + netif_stop_queue(dev); + + priv->station_state = STATION_STATE_DOWN; + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + atmel_write16(dev, GCR, 0x0040); + return 0; +} + +static int atmel_proc_output (char *buf, struct atmel_private *priv) +{ + char *p = buf; + char *s, *r, *c; + + p += sprintf(p, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR); + + if (priv->station_state != STATION_STATE_DOWN) { + p += sprintf(p, "Firmware version:\t%d.%d build %d ", + priv->host_info.major_version, + priv->host_info.minor_version, + priv->host_info.build_version); + + if (priv->card_type != CARD_TYPE_EEPROM) + p += sprintf(p, "[built-in]\n"); + else if (priv->firmware) + p += sprintf(p, "[%s loaded by host]\n", priv->firmware_id); + else + p += sprintf(p, "[%s loaded by hotplug]\n", priv->firmware_id); + + switch(priv->card_type) { + case CARD_TYPE_PARALLEL_FLASH: c = "Parallel flash"; break; + case CARD_TYPE_SPI_FLASH: c = "SPI flash\n"; break; + case CARD_TYPE_EEPROM: c = "EEPROM"; break; + default: c = ""; + } + + switch (priv->reg_domain) { + case REG_DOMAIN_FCC: r = "USA"; break; + case REG_DOMAIN_DOC: r = "Canada"; break; + case REG_DOMAIN_ETSI: r = "Europe"; break; + case REG_DOMAIN_SPAIN: r = "Spain"; break; + case REG_DOMAIN_FRANCE: r = "France"; break; + case REG_DOMAIN_MKK: r = "Japan (MKK)"; break; + case REG_DOMAIN_MKK1: r = "Japan (MKK1)"; break; + case REG_DOMAIN_ISRAEL: r = "Israel"; break; + default: r = ""; + } + p += sprintf(p, "MAC memory type:\t%s\n", c); + p += sprintf(p, "Regulatory domain:\t%s\n", r); + p += sprintf(p, "Host CRC checking:\t%s\n", + priv->do_rx_crc ? "On" : "Off"); + } + + switch(priv->station_state) { + case STATION_STATE_INITIALIZING: s = "Initialising"; break; + case STATION_STATE_SCANNING: s = "Scanning"; break; + case STATION_STATE_JOINNING: s = "Joining"; break; + case STATION_STATE_AUTHENTICATING: s = "Authenticating"; break; + case STATION_STATE_ASSOCIATING: s = "Associating"; break; + case STATION_STATE_READY: s = "Ready"; break; + case STATION_STATE_REASSOCIATING: s = "Reassociating"; break; + case STATION_STATE_FORCED_JOINNING: s = "Forced joining"; break; + case STATION_STATE_FORCED_JOIN_FAILURE: s = "Forced join failure"; break; + case STATION_STATE_NO_CARD: s = "No card"; break; + case STATION_STATE_MGMT_ERROR: s = "Management error"; break; + case STATION_STATE_DOWN: s = "Down"; break; + default: s = ""; + } + + p += sprintf(p, "Current state:\t\t%s\n", s); + return p - buf; +} + +static int atmel_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct atmel_private *priv = (struct atmel_private *)data; + int len = atmel_proc_output (page, priv); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +struct net_device *init_atmel_card( unsigned short irq, int port, char *firmware_id, int is3com, + struct device *sys_dev, int (*card_present)(void *), void *card) +{ + struct net_device *dev; + struct atmel_private *priv; + int rc; + + /* Create the network device object. */ + dev = alloc_etherdev(sizeof(*priv)); + if (!dev) { + printk(KERN_ERR "atmel: Couldn't alloc_etherdev\n"); + return NULL; + } + if (dev_alloc_name(dev, dev->name) < 0) { + printk(KERN_ERR "atmel: Couldn't get name!\n"); + goto err_out_free; + } + + priv = dev->priv; + priv->dev = dev; + priv->sys_dev = sys_dev; + priv->present_callback = card_present; + priv->card = card; + priv->firmware = NULL; + if (firmware) /* module parameter */ + strcpy(priv->firmware_id, firmware); + else if (firmware_id) /* from PCMCIA card-matching or PCI */ + strcpy(priv->firmware_id, firmware_id); + else + priv->firmware_id[0] = '\0'; + priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI; + priv->station_state = STATION_STATE_DOWN; + priv->is3com = is3com; + priv->do_rx_crc = 0; + /* For PCMCIA cards, some chips need CRC, some don't + so we have to probe. */ + if (priv->bus_type == BUS_TYPE_PCCARD) { + priv->probe_crc = 1; + priv->crc_ok_cnt = priv->crc_ko_cnt = 0; + } else + priv->probe_crc = 0; + memset(&priv->stats, 0, sizeof(priv->stats)); + memset(&priv->wstats, 0, sizeof(priv->wstats)); + priv->last_qual = jiffies; + priv->last_beacon_timestamp = 0; + memset(priv->frag_source, 0xff, sizeof(priv->frag_source)); + memset(priv->BSSID, 0, 6); + priv->CurrentBSSID[0] = 0xFF; /* Initialize to something invalid.... */ + priv->station_was_associated = 0; + + priv->last_survey = jiffies; + priv->preamble = LONG_PREAMBLE; + priv->operating_mode = IW_MODE_INFRA; + priv->connect_to_any_BSS = 0; + priv->tx_rate = 3; + priv->auto_tx_rate = 1; + priv->channel = 4; + priv->power_mode = 0; + priv->SSID[0] = '\0'; + priv->SSID_size = 0; + priv->new_SSID_size = 0; + priv->frag_threshold = 2346; + priv->rts_threshold = 2347; + priv->short_retry = 7; + priv->long_retry = 4; + priv->wep.wep_is_on = 0; + priv->wep.default_key = 0; + priv->wep.encryption_level = 0; + priv->default_beacon_period = priv->beacon_period = 100; + priv->listen_interval = 1; + + init_timer(&priv->management_timer); + spin_lock_init(&priv->irqlock); + spin_lock_init(&priv->timerlock); + priv->management_timer.function = atmel_management_timer; + priv->management_timer.data = (unsigned long) dev; + + dev->open = atmel_open; + dev->stop = atmel_close; + dev->change_mtu = atmel_change_mtu; + dev->set_mac_address = atmel_set_mac_address; + dev->hard_start_xmit = start_tx; + dev->get_stats = atmel_get_stats; + dev->get_wireless_stats = atmel_get_wireless_stats; + dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def; + dev->do_ioctl = atmel_ioctl; + dev->irq = irq; + dev->base_addr = port; + + if ((rc = request_irq(dev->irq, service_interrupt, SA_SHIRQ, dev->name, dev))) { + printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc ); + goto err_out_free; + } + + if (priv->bus_type == BUS_TYPE_PCI && + !request_region( dev->base_addr, 64, dev->name )) { + goto err_out_irq; + } + + if (register_netdev(dev)) + goto err_out_res; + + if (!probe_atmel_card(dev)) + goto err_out_res; + + create_proc_read_entry ("driver/atmel", 0, 0, atmel_read_proc, priv); + + printk(KERN_INFO "%s: Atmel at76c50x wireless. Version %d.%d simon@thekelleys.org.uk\n", + dev->name, DRIVER_MAJOR, DRIVER_MINOR); + + SET_MODULE_OWNER(dev); + return dev; + + err_out_res: + if (priv->bus_type == BUS_TYPE_PCI) + release_region( dev->base_addr, 64 ); + err_out_irq: + free_irq(dev->irq, dev); + err_out_free: + kfree(dev); + return NULL; +} + +EXPORT_SYMBOL(init_atmel_card); + +void stop_atmel_card(struct net_device *dev, int freeres) +{ + struct atmel_private *priv = dev->priv; + unregister_netdev(dev); + + /* put a brick on it... */ + + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + atmel_write16(dev, GCR, 0x0040); + + remove_proc_entry("driver/atmel", NULL); + del_timer_sync(&priv->management_timer); + free_irq(dev->irq, dev); + if (priv->firmware) + kfree(priv->firmware); + if (freeres) { + /* PCMCIA frees this stuff, so only for PCI */ + release_region(dev->base_addr, 64); + } + kfree(dev); +} + +EXPORT_SYMBOL(stop_atmel_card); + +static const struct { + int reg_domain; + int min, max; +} channel_table[] = { { REG_DOMAIN_FCC, 1, 11}, + { REG_DOMAIN_DOC, 1, 11}, + { REG_DOMAIN_ETSI, 1, 13}, + { REG_DOMAIN_SPAIN, 10, 11}, + { REG_DOMAIN_FRANCE, 10, 13}, + { REG_DOMAIN_MKK, 14, 14}, + { REG_DOMAIN_MKK1, 1, 14}, + { REG_DOMAIN_ISRAEL, 9} }; + + +static int atmel_validate_channel(struct atmel_private *priv, int channel) +{ + /* check that channel is OK, if so return zero, + else return suitable default channel */ + int i; + + for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++) + if (priv->reg_domain == channel_table[i].reg_domain) { + if (channel >= channel_table[i].min && + channel <= channel_table[i].max) + return 0; + else + return channel_table[i].min; + } + return 1; +} + +static int atmel_set_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + /* Check if we asked for `any' */ + if(dwrq->flags == 0) { + priv->connect_to_any_BSS = 1; + } else { + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + + priv->connect_to_any_BSS = 0; + + /* Check the size of the string */ + if (dwrq->length > MAX_SSID_LENGTH + 1) + return -E2BIG ; + if (index != 0) + return -EINVAL; + + memcpy(priv->new_SSID, extra, dwrq->length - 1); + priv->new_SSID_size = dwrq->length - 1; + } + + return -EINPROGRESS; +} + +static int atmel_get_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + /* Get the current SSID */ + if (priv->SSID_size == 0) { + memcpy(extra, priv->new_SSID, priv->new_SSID_size); + extra[priv->new_SSID_size] = '\0'; + dwrq->length = priv->new_SSID_size + 1; + } else { + memcpy(extra, priv->SSID, priv->SSID_size); + extra[priv->SSID_size] = '\0'; + dwrq->length = priv->SSID_size + 1; + } + + dwrq->flags = !priv->connect_to_any_BSS; /* active */ + + return 0; +} + +static int atmel_get_wap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *awrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + memcpy(awrq->sa_data, priv->CurrentBSSID, 6); + awrq->sa_family = ARPHRD_ETHER; + + return 0; +} + +static int atmel_set_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + /* Basic checking: do we have a key to set ? + * Note : with the new API, it's impossible to get a NULL pointer. + * Therefore, we need to check a key size == 0 instead. + * New version of iwconfig properly set the IW_ENCODE_NOKEY flag + * when no key is present (only change flags), but older versions + * don't do it. - Jean II */ + if (dwrq->length > 0) { + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + int current_index = priv->wep.default_key; + /* Check the size of the key */ + if (dwrq->length > 13) { + return -EINVAL; + } + /* Check the index (none -> use current) */ + if (index < 0 || index >= 4) + index = current_index; + else + priv->wep.default_key = index; + /* Set the length */ + if (dwrq->length > 5) + priv->wep_key_len[index] = 13; + else + if (dwrq->length > 0) + priv->wep_key_len[index] = 5; + else + /* Disable the key */ + priv->wep_key_len[index] = 0; + /* Check if the key is not marked as invalid */ + if(!(dwrq->flags & IW_ENCODE_NOKEY)) { + /* Cleanup */ + memset(priv->wep.wep_keys[index], 0, 13); + /* Copy the key in the driver */ + memcpy(priv->wep.wep_keys[index], extra, dwrq->length); + } + /* WE specify that if a valid key is set, encryption + * should be enabled (user may turn it off later) + * This is also how "iwconfig ethX key on" works */ + if (index == current_index && + priv->wep_key_len[index] > 0) { + priv->wep.wep_is_on = 1; + priv->wep.exclude_unencrypted = 1; + if (priv->wep_key_len[index] > 5) + priv->wep.encryption_level = 2; + else + priv->wep.encryption_level = 1; + } + } else { + /* Do we want to just set the transmit key index ? */ + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + if ( index>=0 && index < 4 ) { + priv->wep.default_key = index; + } else + /* Don't complain if only change the mode */ + if(!dwrq->flags & IW_ENCODE_MODE) { + return -EINVAL; + } + } + /* Read the flags */ + if(dwrq->flags & IW_ENCODE_DISABLED) { + priv->wep.wep_is_on = 0; + priv->wep.encryption_level = 0; + } else { + priv->wep.wep_is_on = 1; + if (priv->wep_key_len[priv->wep.default_key] > 5) + priv->wep.encryption_level = 2; + else + priv->wep.encryption_level = 1; + } + if(dwrq->flags & IW_ENCODE_RESTRICTED) + priv->wep.exclude_unencrypted = 1; + if(dwrq->flags & IW_ENCODE_OPEN) + priv->wep.exclude_unencrypted = 0; + + return -EINPROGRESS; /* Call commit handler */ +} + + +static int atmel_get_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + + if (!priv->wep.wep_is_on) + dwrq->flags = IW_ENCODE_DISABLED; + else if (priv->wep.exclude_unencrypted) + dwrq->flags = IW_ENCODE_RESTRICTED; + else + dwrq->flags = IW_ENCODE_OPEN; + + /* Which key do we want ? -1 -> tx index */ + if (index < 0 || index >= 4) + index = priv->wep.default_key; + dwrq->flags |= index + 1; + /* Copy the key to the user buffer */ + dwrq->length = priv->wep_key_len[index]; + if (dwrq->length > 16) { + dwrq->length=0; + } else { + memset(extra, 0, 16); + memcpy(extra, priv->wep.wep_keys[index], dwrq->length); + } + + return 0; +} + +static int atmel_get_name(struct net_device *dev, + struct iw_request_info *info, + char *cwrq, + char *extra) +{ + strcpy(cwrq, "IEEE 802.11-DS"); + return 0; +} + +static int atmel_set_rate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + if (vwrq->fixed == 0) { + priv->tx_rate = 3; + priv->auto_tx_rate = 1; + } else { + priv->auto_tx_rate = 0; + + /* Which type of value ? */ + if((vwrq->value < 4) && (vwrq->value >= 0)) { + /* Setting by rate index */ + priv->tx_rate = vwrq->value; + } else { + /* Setting by frequency value */ + switch (vwrq->value) { + case (int)1e6: priv->tx_rate = 0; break; + case (int)2e6: priv->tx_rate = 1; break; + case (int)5.5e6: priv->tx_rate = 2; break; + case (int)11e6: priv->tx_rate = 3; break; + default: return -EINVAL; + } + } + } + + return -EINPROGRESS; +} + +static int atmel_set_mode(struct net_device *dev, + struct iw_request_info *info, + __u32 *uwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA) + return -EINVAL; + + priv->operating_mode = *uwrq; + return -EINPROGRESS; +} + +static int atmel_get_mode(struct net_device *dev, + struct iw_request_info *info, + __u32 *uwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + *uwrq = priv->operating_mode; + return 0; +} + +static int atmel_get_rate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + if (priv->auto_tx_rate) { + vwrq->fixed = 0; + vwrq->value = 11e6; + } else { + vwrq->fixed = 1; + switch(priv->tx_rate) { + case 0: vwrq->value = 1e6; break; + case 1: vwrq->value = 2e6; break; + case 2: vwrq->value = 5.5e6; break; + case 3: vwrq->value = 11e6; break; + } + } + return 0; +} + +static int atmel_set_power(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + priv->power_mode = vwrq->disabled ? 0 : 1; + return -EINPROGRESS; +} + +static int atmel_get_power(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + vwrq->disabled = priv->power_mode ? 0 : 1; + vwrq->flags = IW_POWER_ON; + return 0; +} + +static int atmel_set_retry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + if(!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) { + if(vwrq->flags & IW_RETRY_MAX) + priv->long_retry = vwrq->value; + else if (vwrq->flags & IW_RETRY_MIN) + priv->short_retry = vwrq->value; + else { + /* No modifier : set both */ + priv->long_retry = vwrq->value; + priv->short_retry = vwrq->value; + } + return -EINPROGRESS; + } + + return -EINVAL; +} + +static int atmel_get_retry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + vwrq->disabled = 0; /* Can't be disabled */ + + /* Note : by default, display the min retry number */ + if((vwrq->flags & IW_RETRY_MAX)) { + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + vwrq->value = priv->long_retry; + } else { + vwrq->flags = IW_RETRY_LIMIT; + vwrq->value = priv->short_retry; + if(priv->long_retry != priv->short_retry) + vwrq->flags |= IW_RETRY_MIN; + } + + return 0; +} + +static int atmel_set_rts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int rthr = vwrq->value; + + if(vwrq->disabled) + rthr = 2347; + if((rthr < 0) || (rthr > 2347)) { + return -EINVAL; + } + priv->rts_threshold = rthr; + + return -EINPROGRESS; /* Call commit handler */ +} + +static int atmel_get_rts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + vwrq->value = priv->rts_threshold; + vwrq->disabled = (vwrq->value >= 2347); + vwrq->fixed = 1; + + return 0; +} + +static int atmel_set_frag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int fthr = vwrq->value; + + if(vwrq->disabled) + fthr = 2346; + if((fthr < 256) || (fthr > 2346)) { + return -EINVAL; + } + fthr &= ~0x1; /* Get an even value - is it really needed ??? */ + priv->frag_threshold = fthr; + + return -EINPROGRESS; /* Call commit handler */ +} + +static int atmel_get_frag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + vwrq->value = priv->frag_threshold; + vwrq->disabled = (vwrq->value >= 2346); + vwrq->fixed = 1; + + return 0; +} + +const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; + +static int atmel_set_freq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *fwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int rc = -EINPROGRESS; /* Call commit handler */ + + /* If setting by frequency, convert to a channel */ + if((fwrq->e == 1) && + (fwrq->m >= (int) 2.412e8) && + (fwrq->m <= (int) 2.487e8)) { + int f = fwrq->m / 100000; + int c = 0; + while((c < 14) && (f != frequency_list[c])) + c++; + /* Hack to fall through... */ + fwrq->e = 0; + fwrq->m = c + 1; + } + /* Setting by channel number */ + if((fwrq->m > 1000) || (fwrq->e > 0)) + rc = -EOPNOTSUPP; + else { + int channel = fwrq->m; + if (atmel_validate_channel(priv, channel) == 0) { + priv->channel = channel; + } else { + rc = -EINVAL; + } + } + return rc; +} + +static int atmel_get_freq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *fwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + fwrq->m = priv->channel; + fwrq->e = 0; + return 0; +} + +static int atmel_set_scan(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + /* Note : you may have realised that, as this is a SET operation, + * this is privileged and therefore a normal user can't + * perform scanning. + * This is not an error, while the device perform scanning, + * traffic doesn't flow, so it's a perfect DoS... + * Jean II */ + + if (priv->station_state == STATION_STATE_DOWN || + priv->station_state == STATION_STATE_NO_CARD) + return -EAGAIN; + + /* Timeout old surveys. */ + if ((jiffies - priv->last_survey) > (20 * HZ)) + priv->site_survey_state = SITE_SURVEY_IDLE; + priv->last_survey = jiffies; + + /* Initiate a scan command */ + if (priv->site_survey_state == SITE_SURVEY_IN_PROGRESS) + return -EBUSY; + + priv->site_survey_state = SITE_SURVEY_IN_PROGRESS; + + atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ + del_timer_sync(&priv->management_timer); + atmel_scan(priv, 0); + atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ + + return 0; +} + +static int atmel_get_scan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int i; + char *current_ev = extra; + struct iw_event iwe; + + if (priv->site_survey_state != SITE_SURVEY_COMPLETED) + return -EAGAIN; + + for(i=0; iBSS_list_entries; i++) { + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, 6); + current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN); + + iwe.u.data.length = priv->BSSinfo[i].SSIDsize; + if (iwe.u.data.length > 32) + iwe.u.data.length = 32; + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, priv->BSSinfo[i].SSID); + + iwe.cmd = SIOCGIWMODE; + iwe.u.mode = priv->BSSinfo[i].BSStype; + current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_UINT_LEN); + + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = priv->BSSinfo[i].channel; + iwe.u.freq.e = 0; + current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_FREQ_LEN); + + iwe.cmd = SIOCGIWENCODE; + if (priv->BSSinfo[i].UsingWEP) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, NULL); + + } + + /* Length of data */ + dwrq->length = (current_ev - extra); + dwrq->flags = 0; /* todo */ + + return 0; +} + +static int atmel_get_range(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + struct iw_range *range = (struct iw_range *) extra; + int k,i,j; + + dwrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(range)); + range->min_nwid = 0x0000; + range->max_nwid = 0x0000; + range->num_channels = 0; + for (j = 0; j < sizeof(channel_table)/sizeof(channel_table[0]); j++) + if (priv->reg_domain == channel_table[j].reg_domain) { + range->num_channels = channel_table[j].max - channel_table[j].min + 1; + } + if (range->num_channels != 0) { + for(k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) { + range->freq[k].i = i + 1; /* List index */ + range->freq[k].m = frequency_list[i] * 100000; + range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */ + } + range->num_frequency = k; + } + + range->max_qual.qual = 100; + range->max_qual.level = 100; + range->max_qual.noise = 0; + range->sensitivity = 0; + + range->bitrate[0] = 1e6; + range->bitrate[1] = 2e6; + range->bitrate[2] = 5.5e6; + range->bitrate[3] = 11e6; + range->num_bitrates = 4; + + range->min_rts = 0; + range->max_rts = 2347; + range->min_frag = 256; + range->max_frag = 2346; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = 4; + + range->pmp_flags = IW_POWER_ON; + range->pmt_flags = IW_POWER_ON; + range->pm_capa = 0; + + range->we_version_source = WIRELESS_EXT; + range->we_version_compiled = WIRELESS_EXT; + range->retry_capa = IW_RETRY_LIMIT ; + range->retry_flags = IW_RETRY_LIMIT; + range->r_time_flags = 0; + range->min_retry = 1; + range->max_retry = 65535; + range->avg_qual.qual = 50; + range->avg_qual.level = 50; + range->avg_qual.noise = 0; + + return 0; +} + +static int atmel_set_wap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *awrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int i; + static const u8 bcast[] = { 255, 255, 255, 255, 255, 255 }; + + if (awrq->sa_family != ARPHRD_ETHER) + return -EINVAL; + + if (memcmp(bcast, awrq->sa_data, 6) == 0) { + atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ + del_timer_sync(&priv->management_timer); + atmel_scan(priv, 1); + atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ + return 0; + } + + for(i=0; iBSS_list_entries; i++) { + if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) { + if (!priv->wep.wep_is_on && priv->BSSinfo[i].UsingWEP) { + return -EINVAL; + } else if (priv->wep.wep_is_on && !priv->BSSinfo[i].UsingWEP) { + return -EINVAL; + } else + atmel_join_bss(priv, i); + return 0; + } + } + + return -EINVAL; +} + +static int atmel_config_commit(struct net_device *dev, + struct iw_request_info *info, /* NULL */ + void *zwrq, /* NULL */ + char *extra) /* NULL */ +{ + reset_atmel_card(dev); + return 0; +} + +static const iw_handler atmel_handler[] = +{ + (iw_handler) atmel_config_commit, /* SIOCSIWCOMMIT */ + (iw_handler) atmel_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) atmel_set_freq, /* SIOCSIWFREQ */ + (iw_handler) atmel_get_freq, /* SIOCGIWFREQ */ + (iw_handler) atmel_set_mode, /* SIOCSIWMODE */ + (iw_handler) atmel_get_mode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) atmel_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) atmel_set_wap, /* SIOCSIWAP */ + (iw_handler) atmel_get_wap, /* SIOCGIWAP */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCGIWAPLIST */ + (iw_handler) atmel_set_scan, /* SIOCSIWSCAN */ + (iw_handler) atmel_get_scan, /* SIOCGIWSCAN */ + (iw_handler) atmel_set_essid, /* SIOCSIWESSID */ + (iw_handler) atmel_get_essid, /* SIOCGIWESSID */ + (iw_handler) NULL, /* SIOCSIWNICKN */ + (iw_handler) NULL, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) atmel_set_rate, /* SIOCSIWRATE */ + (iw_handler) atmel_get_rate, /* SIOCGIWRATE */ + (iw_handler) atmel_set_rts, /* SIOCSIWRTS */ + (iw_handler) atmel_get_rts, /* SIOCGIWRTS */ + (iw_handler) atmel_set_frag, /* SIOCSIWFRAG */ + (iw_handler) atmel_get_frag, /* SIOCGIWFRAG */ + (iw_handler) NULL, /* SIOCSIWTXPOW */ + (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) atmel_set_retry, /* SIOCSIWRETRY */ + (iw_handler) atmel_get_retry, /* SIOCGIWRETRY */ + (iw_handler) atmel_set_encode, /* SIOCSIWENCODE */ + (iw_handler) atmel_get_encode, /* SIOCGIWENCODE */ + (iw_handler) atmel_set_power, /* SIOCSIWPOWER */ + (iw_handler) atmel_get_power, /* SIOCGIWPOWER */ +}; + + +static const iw_handler atmel_private_handler[] = +{ + NULL, /* SIOCIWFIRSTPRIV */ +}; + +typedef struct atmel_priv_ioctl { + char id[32]; + unsigned char *data; + unsigned short len; +} atmel_priv_ioctl; + + +#define ATMELFWL SIOCIWFIRSTPRIV +#define ATMELIDIFC ATMELFWL + 1 +#define ATMELMAGIC 0x51807 + +static const struct iw_priv_args atmel_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + { ATMELFWL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (atmel_priv_ioctl), IW_PRIV_TYPE_NONE, "atmelfwl" }, + { ATMELIDIFC, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "atmelidifc" }, +}; + +static const struct iw_handler_def atmel_handler_def = +{ + .num_standard = sizeof(atmel_handler)/sizeof(iw_handler), + .num_private = sizeof(atmel_private_handler)/sizeof(iw_handler), + .num_private_args = sizeof(atmel_private_args)/sizeof(struct iw_priv_args), + .standard = (iw_handler *) atmel_handler, + .private = (iw_handler *) atmel_private_handler, + .private_args = (struct iw_priv_args *) atmel_private_args +}; + +static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc = 0; + struct atmel_private *priv = (struct atmel_private *) dev->priv; + atmel_priv_ioctl com; + struct iwreq *wrq = (struct iwreq *) rq; + unsigned char *new_firmware; + + switch (cmd) { + case SIOCGIWPRIV: + if(wrq->u.data.pointer) { + /* Set the number of ioctl available */ + wrq->u.data.length = sizeof(atmel_private_args) / sizeof(atmel_private_args[0]); + + /* Copy structure to the user buffer */ + if (copy_to_user(wrq->u.data.pointer, + (u_char *) atmel_private_args, + sizeof(atmel_private_args))) + rc = -EFAULT; + } + break; + + case ATMELIDIFC: + wrq->u.param.value = ATMELMAGIC; + break; + + case ATMELFWL: + if (copy_from_user(&com, rq->ifr_data, sizeof(com))) { + rc = -EFAULT; + break; + } + + if (!capable(CAP_NET_ADMIN)) { + rc = -EPERM; + break; + } + + if (!(new_firmware = kmalloc(com.len, GFP_KERNEL))) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(new_firmware, com.data, com.len)) { + rc = -EFAULT; + break; + } + + if (priv->firmware) + kfree(priv->firmware); + + priv->firmware = new_firmware; + priv->firmware_length = com.len; + strncpy(priv->firmware_id, com.id, 31); + priv->firmware_id[31] = '\0'; + break; + + default: + rc = -EOPNOTSUPP; + } + + return rc; +} + +struct auth_body { + u16 alg; + u16 trans_seq; + u16 status; + u8 el_id; + u8 chall_text_len; + u8 chall_text[253]; +}; + +static void atmel_enter_state(struct atmel_private *priv, int new_state) +{ + int old_state = priv->station_state; + + if (new_state == old_state) + return; + + if (new_state == STATION_STATE_READY) + netif_start_queue(priv->dev); + + if (old_state == STATION_STATE_READY) { + netif_stop_queue(priv->dev); + priv->last_beacon_timestamp = 0; + } + + priv->station_state = new_state; + +} + +static void atmel_scan(struct atmel_private *priv, int specific_ssid) +{ + struct { + u8 BSSID[6]; + u8 SSID[MAX_SSID_LENGTH]; + u8 scan_type; + u8 channel; + u16 BSS_type; + u16 min_channel_time; + u16 max_channel_time; + u8 options; + u8 SSID_size; + } cmd; + + atmel_enter_state(priv, STATION_STATE_SCANNING); + + memset(cmd.BSSID, 0xff, 6); + + if (priv->fast_scan) { + cmd.SSID_size = priv->SSID_size; + memcpy(cmd.SSID, priv->SSID, priv->SSID_size); + cmd.min_channel_time = cpu_to_le16(10); + cmd.max_channel_time = cpu_to_le16(50); + } else { + priv->BSS_list_entries = 0; + cmd.SSID_size = 0; + cmd.min_channel_time = cpu_to_le16(10); + cmd.max_channel_time = cpu_to_le16(120); + } + + cmd.options = 0; + + if (!specific_ssid) + cmd.options |= SCAN_OPTIONS_SITE_SURVEY; + + cmd.channel = (priv->channel & 0x7f); + cmd.scan_type = SCAN_TYPE_ACTIVE; + cmd.BSS_type = cpu_to_le16(priv->operating_mode == IW_MODE_ADHOC ? + BSS_TYPE_AD_HOC : BSS_TYPE_INFRASTRUCTURE); + + atmel_send_command(priv, CMD_Scan, &cmd, sizeof(cmd)); +} + +static void join(struct atmel_private *priv, int type) +{ + struct { + u8 BSSID[6]; + u8 SSID[MAX_SSID_LENGTH]; + u8 BSS_type; /* this is a short in a scan command - wierd */ + u8 channel; + u16 timeout; + u8 SSID_size; + u8 reserved; + } cmd; + + cmd.SSID_size = priv->SSID_size; + memcpy(cmd.SSID, priv->SSID, priv->SSID_size); + memcpy(cmd.BSSID, priv->CurrentBSSID, 6); + cmd.channel = (priv->channel & 0x7f); + cmd.BSS_type = type; + cmd.timeout = cpu_to_le16(2000); + + atmel_send_command(priv, CMD_Join, &cmd, sizeof(cmd)); +} + + +static void start(struct atmel_private *priv, int type) +{ + struct { + u8 BSSID[6]; + u8 SSID[MAX_SSID_LENGTH]; + u8 BSS_type; + u8 channel; + u8 SSID_size; + u8 reserved[3]; + } cmd; + + cmd.SSID_size = priv->SSID_size; + memcpy(cmd.SSID, priv->SSID, priv->SSID_size); + memcpy(cmd.BSSID, priv->BSSID, 6); + cmd.BSS_type = type; + cmd.channel = (priv->channel & 0x7f); + + atmel_send_command(priv, CMD_Start, &cmd, sizeof(cmd)); +} + +static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 channel) +{ + int rejoin = 0; + int new = capability & C80211_MGMT_CAPABILITY_ShortPreamble ? + SHORT_PREAMBLE : LONG_PREAMBLE; + + if (priv->preamble != new) { + priv->preamble = new; + rejoin = 1; + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, new); + } + + if (priv->channel != channel) { + priv->channel = channel; + rejoin = 1; + atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_CHANNEL_POS, channel); + } + + if (rejoin) { + priv->station_is_associated = 0; + atmel_enter_state(priv, STATION_STATE_JOINNING); + + if (priv->operating_mode == IW_MODE_INFRA) + join(priv, BSS_TYPE_INFRASTRUCTURE); + else + join(priv, BSS_TYPE_AD_HOC); + } +} + + +static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len) +{ + struct ieee802_11_hdr header; + struct auth_body auth; + + header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | IEEE802_11_STYPE_AUTH); + header.duration_id = cpu_to_le16(0x8000); + header.seq_ctl = 0; + memcpy(header.addr1, priv->CurrentBSSID, 6); + memcpy(header.addr2, priv->dev->dev_addr, 6); + memcpy(header.addr3, priv->CurrentBSSID, 6); + + if (priv->wep.wep_is_on) { + auth.alg = C80211_MGMT_AAN_SHAREDKEY; + /* no WEP for authentication frames with TrSeqNo 1 */ + if (priv->CurrentAuthentTransactionSeqNum != 1) + header.frame_ctl |= cpu_to_le16(IEEE802_11_FCTL_WEP); + } else { + auth.alg = C80211_MGMT_AAN_OPENSYSTEM; + } + + auth.status = 0; + auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum); + priv->ExpectedAuthentTransactionSeqNum = priv->CurrentAuthentTransactionSeqNum+1; + priv->CurrentAuthentTransactionSeqNum += 2; + + if (challenge_len != 0) { + auth.el_id = 16; /* challenge_text */ + auth.chall_text_len = challenge_len; + memcpy(auth.chall_text, challenge, challenge_len); + atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 8 + challenge_len); + } else { + atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 6); + } +} + +static void send_association_request(struct atmel_private *priv, int is_reassoc) +{ + u8 *ssid_el_p; + int bodysize; + struct ieee802_11_hdr header; + struct ass_req_format { + u16 capability; + u16 listen_interval; + u8 ap[6]; /* nothing after here directly accessible */ + u8 ssid_el_id; + u8 ssid_len; + u8 ssid[MAX_SSID_LENGTH]; + u8 sup_rates_el_id; + u8 sup_rates_len; + u8 rates[4]; + } body; + + header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | + (is_reassoc ? IEEE802_11_STYPE_REASSOC_REQ : IEEE802_11_STYPE_ASSOC_REQ)); + header.duration_id = cpu_to_le16(0x8000); + header.seq_ctl = 0; + + memcpy(header.addr1, priv->CurrentBSSID, 6); + memcpy(header.addr2, priv->dev->dev_addr, 6); + memcpy(header.addr3, priv->CurrentBSSID, 6); + + body.capability = cpu_to_le16(C80211_MGMT_CAPABILITY_ESS); + if (priv->wep.wep_is_on) + body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_Privacy); + if (priv->preamble == SHORT_PREAMBLE) + body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_ShortPreamble); + + body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); + + /* current AP address - only in reassoc frame */ + if (is_reassoc) { + memcpy(body.ap, priv->CurrentBSSID, 6); + ssid_el_p = (u8 *)&body.ssid_el_id; + bodysize = 18 + priv->SSID_size; + } else { + ssid_el_p = (u8 *)&body.ap[0]; + bodysize = 12 + priv->SSID_size; + } + + ssid_el_p[0]= C80211_MGMT_ElementID_SSID; + ssid_el_p[1] = priv->SSID_size; + memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); + ssid_el_p[2 + priv->SSID_size] = C80211_MGMT_ElementID_SupportedRates; + ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */ + memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); + + atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); +} + +static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee802_11_hdr *header) +{ + if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) + return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; + else + return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; +} + +static int retrieve_bss(struct atmel_private *priv) +{ + int i; + int max_rssi = -128; + int max_index = -1; + + if (priv->BSS_list_entries == 0) + return -1; + + if (priv->connect_to_any_BSS) { + /* Select a BSS with the max-RSSI but of the same type and of the same WEP mode + and that it is not marked as 'bad' (i.e. we had previously failed to connect to + this BSS with the settings that we currently use) */ + priv->current_BSS = 0; + for(i=0; iBSS_list_entries; i++) { + if (priv->operating_mode == priv->BSSinfo[i].BSStype && + ((!priv->wep.wep_is_on && !priv->BSSinfo[i].UsingWEP) || + (priv->wep.wep_is_on && priv->BSSinfo[i].UsingWEP)) && + !(priv->BSSinfo[i].channel & 0x80)) { + max_rssi = priv->BSSinfo[i].RSSI; + priv->current_BSS = max_index = i; + } + + } + return max_index; + } + + for(i=0; iBSS_list_entries; i++) { + if (priv->SSID_size == priv->BSSinfo[i].SSIDsize && + memcmp(priv->SSID, priv->BSSinfo[i].SSID, priv->SSID_size) == 0 && + priv->operating_mode == priv->BSSinfo[i].BSStype && + atmel_validate_channel(priv, priv->BSSinfo[i].channel) == 0) { + if (priv->BSSinfo[i].RSSI >= max_rssi) { + max_rssi = priv->BSSinfo[i].RSSI; + max_index = i; + } + } + } + return max_index; +} + + +static void store_bss_info(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 capability, u16 beacon_period, u8 channel, u8 rssi, + u8 ssid_len, u8 *ssid, int is_beacon) +{ + u8 *bss = capability & C80211_MGMT_CAPABILITY_ESS ? header->addr2 : header->addr3; + int i, index; + + for (index = -1, i = 0; i < priv->BSS_list_entries; i++) + if (memcmp(bss, priv->BSSinfo[i].BSSID, 6) == 0) + index = i; + + /* If we process a probe and an entry from this BSS exists + we will update the BSS entry with the info from this BSS. + If we process a beacon we will only update RSSI */ + + if (index == -1) { + if (priv->BSS_list_entries == MAX_BSS_ENTRIES) + return; + index = priv->BSS_list_entries++; + memcpy(priv->BSSinfo[index].BSSID, bss, 6); + priv->BSSinfo[index].RSSI = rssi; + } else { + if (rssi > priv->BSSinfo[index].RSSI) + priv->BSSinfo[index].RSSI = rssi; + if (is_beacon) + return; + } + + priv->BSSinfo[index].channel = channel; + priv->BSSinfo[index].beacon_period = beacon_period; + priv->BSSinfo[index].UsingWEP = capability & C80211_MGMT_CAPABILITY_Privacy; + memcpy(priv->BSSinfo[index].SSID, ssid, ssid_len); + priv->BSSinfo[index].SSIDsize = ssid_len; + + if (capability & C80211_MGMT_CAPABILITY_IBSS) + priv->BSSinfo[index].BSStype = IW_MODE_ADHOC; + else if (capability & C80211_MGMT_CAPABILITY_ESS) + priv->BSSinfo[index].BSStype =IW_MODE_INFRA; + + priv->BSSinfo[index].preamble = capability & C80211_MGMT_CAPABILITY_ShortPreamble ? + SHORT_PREAMBLE : LONG_PREAMBLE; +} + +static void authenticate(struct atmel_private *priv, u16 frame_len) +{ + struct auth_body *auth = (struct auth_body *)priv->rx_buf; + u16 status = le16_to_cpu(auth->status); + u16 trans_seq_no = le16_to_cpu(auth->trans_seq); + + if (status == C80211_MGMT_SC_Success && !priv->wep.wep_is_on) { + /* no WEP */ + if (priv->station_was_associated) { + atmel_enter_state(priv, STATION_STATE_REASSOCIATING); + send_association_request(priv, 1); + return; + } else { + atmel_enter_state(priv, STATION_STATE_ASSOCIATING); + send_association_request(priv, 0); + return; + } + } + + if (status == C80211_MGMT_SC_Success && priv->wep.wep_is_on) { + /* WEP */ + if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum) + return; + + if (trans_seq_no == 0x0002 && + auth->el_id == C80211_MGMT_ElementID_ChallengeText) { + send_authentication_request(priv, auth->chall_text, auth->chall_text_len); + return; + } + + if (trans_seq_no == 0x0004) { + if(priv->station_was_associated) { + atmel_enter_state(priv, STATION_STATE_REASSOCIATING); + send_association_request(priv, 1); + return; + } else { + atmel_enter_state(priv, STATION_STATE_ASSOCIATING); + send_association_request(priv, 0); + return; + } + } + } + + if (status == C80211_MGMT_SC_AuthAlgNotSupported && priv->connect_to_any_BSS) { + int bss_index; + + priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; + + if ((bss_index = retrieve_bss(priv)) != -1) { + atmel_join_bss(priv, bss_index); + return; + } + } + + + priv->AuthenticationRequestRetryCnt = 0; + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; +} + +static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) +{ + struct ass_resp_format { + u16 capability; + u16 status; + u16 ass_id; + u8 el_id; + u8 length; + u8 rates[4]; + } *ass_resp = (struct ass_resp_format *)priv->rx_buf; + + u16 status = le16_to_cpu(ass_resp->status); + u16 ass_id = le16_to_cpu(ass_resp->ass_id); + u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length; + + if (frame_len < 8 + rates_len) + return; + + if (status == C80211_MGMT_SC_Success) { + if (subtype == C80211_SUBTYPE_MGMT_ASS_RESPONSE) + priv->AssociationRequestRetryCnt = 0; + else + priv->ReAssociationRequestRetryCnt = 0; + + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff); + atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len); + if (priv->power_mode == 0) { + priv->listen_interval = 1; + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); + } else { + priv->listen_interval = 2; + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, PS_MODE); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2); + } + + priv->station_is_associated = 1; + priv->station_was_associated = 1; + atmel_enter_state(priv, STATION_STATE_READY); + return; + } + + if (subtype == C80211_SUBTYPE_MGMT_ASS_RESPONSE && + status != C80211_MGMT_SC_AssDeniedBSSRate && + status != C80211_MGMT_SC_SupportCapabilities && + priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + priv->AssociationRequestRetryCnt++; + send_association_request(priv, 0); + return; + } + + if (subtype == C80211_SUBTYPE_MGMT_REASS_RESPONSE && + status != C80211_MGMT_SC_AssDeniedBSSRate && + status != C80211_MGMT_SC_SupportCapabilities && + priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + priv->ReAssociationRequestRetryCnt++; + send_association_request(priv, 1); + return; + } + + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + + if(priv->connect_to_any_BSS) { + int bss_index; + priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; + + if ((bss_index = retrieve_bss(priv)) != -1) + atmel_join_bss(priv, bss_index); + + } +} + +void atmel_join_bss(struct atmel_private *priv, int bss_index) +{ + struct bss_info *bss = &priv->BSSinfo[bss_index]; + + memcpy(priv->CurrentBSSID, bss->BSSID, 6); + memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize); + + /* When switching to AdHoc turn OFF Power Save if needed */ + + if (bss->BSStype == IW_MODE_ADHOC && + priv->operating_mode != IW_MODE_ADHOC && + priv->power_mode) { + priv->power_mode = 0; + priv->listen_interval = 1; + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); + } + + priv->operating_mode = bss->BSStype; + priv->channel = bss->channel & 0x7f; + priv->beacon_period = bss->beacon_period; + + if (priv->preamble != bss->preamble) { + priv->preamble = bss->preamble; + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, bss->preamble); + } + + if (!priv->wep.wep_is_on && bss->UsingWEP) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + return; + } + + if (priv->wep.wep_is_on && !bss->UsingWEP) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + return; + } + + atmel_enter_state(priv, STATION_STATE_JOINNING); + + if (priv->operating_mode == IW_MODE_INFRA) + join(priv, BSS_TYPE_INFRASTRUCTURE); + else + join(priv, BSS_TYPE_AD_HOC); +} + + +static void restart_search(struct atmel_private *priv) +{ + int bss_index; + + if (!priv->connect_to_any_BSS) { + atmel_scan(priv, 1); + } else { + priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; + + if ((bss_index = retrieve_bss(priv)) != -1) + atmel_join_bss(priv, bss_index); + else + atmel_scan(priv, 0); + + } +} + +static void smooth_rssi(struct atmel_private *priv, u8 rssi) +{ + u8 old = priv->wstats.qual.level; + + /* 502-rmfd-revd gives max signal level as 42, by experiment. + This is going to break for other hardware variants. */ + + rssi = rssi * 100 / 42; + if((rssi + old) % 2) + priv->wstats.qual.level = ((rssi + old)/2) + 1; + else + priv->wstats.qual.level = ((rssi + old)/2); + +} + +static void atmel_smooth_qual(struct atmel_private *priv) +{ + unsigned long time_diff = (jiffies - priv->last_qual)/HZ; + while (time_diff--) { + priv->last_qual += HZ; + priv->wstats.qual.qual = priv->wstats.qual.qual/2; + priv->wstats.qual.qual += + priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000; + priv->beacons_this_sec = 0; + } +} + +/* deals with incoming managment frames. */ +static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 frame_len, u8 rssi) +{ + u16 subtype; + + switch (subtype = le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_STYPE) { + case C80211_SUBTYPE_MGMT_BEACON : + case C80211_SUBTYPE_MGMT_ProbeResponse: + + /* beacon frame has multiple variable-length fields - + never let an engineer loose with a data structure design. */ + { + struct beacon_format { + u64 timestamp; + u16 interval; + u16 capability; + u8 ssid_el_id; + u8 ssid_length; + /* ssid here */ + u8 rates_el_id; + u8 rates_length; + /* rates here */ + u8 ds_el_id; + u8 ds_length; + /* ds here */ + } *beacon = (struct beacon_format *)priv->rx_buf; + + u8 channel, rates_length, ssid_length; + u64 timestamp = le64_to_cpu(beacon->timestamp); + u16 beacon_interval = le16_to_cpu(beacon->interval); + u16 capability = le16_to_cpu(beacon->capability); + u8 *beaconp = priv->rx_buf; + ssid_length = beacon->ssid_length; + /* this blows chunks. */ + if (frame_len < 14 || frame_len < ssid_length + 15) + return; + rates_length = beaconp[beacon->ssid_length + 15]; + if (frame_len < ssid_length + rates_length + 18) + return; + if (ssid_length > MAX_SSID_LENGTH) + return; + channel = beaconp[ssid_length + rates_length + 18]; + + if (priv->station_state == STATION_STATE_READY) { + smooth_rssi(priv, rssi); + if (is_frame_from_current_bss(priv, header)) { + priv->beacons_this_sec++; + atmel_smooth_qual(priv); + if (priv->last_beacon_timestamp) { + /* Note truncate this to 32 bits - kernel can't divide a long long */ + u32 beacon_delay = timestamp - priv->last_beacon_timestamp; + int beacons = beacon_delay / (beacon_interval * 1000); + if (beacons > 1) + priv->wstats.miss.beacon += beacons - 1; + } + priv->last_beacon_timestamp = timestamp; + handle_beacon_probe(priv, capability, channel); + } + } + + if (priv->station_state == STATION_STATE_SCANNING ) + store_bss_info(priv, header, capability, beacon_interval, channel, + rssi, ssid_length, &beacon->rates_el_id, + subtype == C80211_SUBTYPE_MGMT_BEACON) ; + } + break; + + case C80211_SUBTYPE_MGMT_Authentication: + + if (priv->station_state == STATION_STATE_AUTHENTICATING) + authenticate(priv, frame_len); + + break; + + case C80211_SUBTYPE_MGMT_ASS_RESPONSE: + case C80211_SUBTYPE_MGMT_REASS_RESPONSE: + + if (priv->station_state == STATION_STATE_ASSOCIATING || + priv->station_state == STATION_STATE_REASSOCIATING) + associate(priv, frame_len, subtype); + + break; + + case C80211_SUBTYPE_MGMT_DISASSOSIATION: + if (priv->station_is_associated && + priv->operating_mode == IW_MODE_INFRA && + is_frame_from_current_bss(priv, header)) { + priv->station_was_associated = 0; + priv->station_is_associated = 0; + + atmel_enter_state(priv, STATION_STATE_JOINNING); + join(priv, BSS_TYPE_INFRASTRUCTURE); + } + + break; + + case C80211_SUBTYPE_MGMT_Deauthentication: + if (priv->operating_mode == IW_MODE_INFRA && + is_frame_from_current_bss(priv, header)) { + priv->station_was_associated = 0; + + atmel_enter_state(priv, STATION_STATE_JOINNING); + join(priv, BSS_TYPE_INFRASTRUCTURE); + } + + break; + } +} + +/* run when timer expires */ +static void atmel_management_timer(u_long a) +{ + struct net_device *dev = (struct net_device *) a; + struct atmel_private *priv = (struct atmel_private *)dev->priv; + unsigned long flags; + + /* Check if the card has been yanked. */ + if (priv->card && priv->present_callback && + !(*priv->present_callback)(priv->card)) + return; + + if (priv->station_state == STATION_STATE_NO_CARD) + return; + + spin_lock_irqsave(&priv->irqlock, flags); + + switch (priv->station_state) { + + case STATION_STATE_AUTHENTICATING: + + if (priv->AuthenticationRequestRetryCnt >= MAX_AUTHENTICATION_RETRIES) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + priv->AuthenticationRequestRetryCnt = 0; + restart_search(priv); + } else { + priv->AuthenticationRequestRetryCnt++; + priv->CurrentAuthentTransactionSeqNum = 0x0001; + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + send_authentication_request(priv, NULL, 0); + } + + break; + + case STATION_STATE_ASSOCIATING: + + if (priv->AssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + priv->AssociationRequestRetryCnt = 0; + restart_search(priv); + } else { + priv->AssociationRequestRetryCnt++; + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + send_association_request(priv, 0); + } + + break; + + case STATION_STATE_REASSOCIATING: + + if (priv->ReAssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + priv->ReAssociationRequestRetryCnt = 0; + restart_search(priv); + } else { + priv->ReAssociationRequestRetryCnt++; + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + send_association_request(priv, 1); + } + + break; + + default: + break; + } + + spin_unlock_irqrestore(&priv->irqlock, flags); +} + +static void atmel_command_irq(struct atmel_private *priv) +{ + u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); + u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); + int fast_scan; + + if (status == CMD_STATUS_IDLE || + status == CMD_STATUS_IN_PROGRESS) + return; + + switch (command){ + + case CMD_Start: + if (status == CMD_STATUS_COMPLETE) { + priv->station_was_associated = priv->station_is_associated; + atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, + (u8 *)priv->CurrentBSSID, 6); + atmel_enter_state(priv, STATION_STATE_READY); + } + break; + + case CMD_Scan: + fast_scan = priv->fast_scan; + priv->fast_scan = 0; + + if (status != CMD_STATUS_COMPLETE) { + atmel_scan(priv, 1); + } else { + int bss_index = retrieve_bss(priv); + if (bss_index != -1) { + atmel_join_bss(priv, bss_index); + } else if (priv->operating_mode == IW_MODE_ADHOC && + priv->SSID_size != 0) { + start(priv, BSS_TYPE_AD_HOC); + } else { + priv->fast_scan = !fast_scan; + atmel_scan(priv, 1); + } + } + break; + + case CMD_SiteSurvey: + priv->fast_scan = 0; + + if (status != CMD_STATUS_COMPLETE) + return; + + priv->site_survey_state = SITE_SURVEY_COMPLETED; + if (priv->station_is_associated) { + atmel_enter_state(priv, STATION_STATE_READY); + } else { + atmel_scan(priv, 1); + } + break; + + case CMD_Join: + if (status == CMD_STATUS_COMPLETE) { + if (priv->operating_mode == IW_MODE_ADHOC) { + priv->station_was_associated = priv->station_is_associated; + atmel_enter_state(priv, STATION_STATE_READY); + } else { + priv->AuthenticationRequestRetryCnt = 0; + atmel_enter_state(priv, STATION_STATE_AUTHENTICATING); + + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + priv->CurrentAuthentTransactionSeqNum = 0x0001; + send_authentication_request(priv, NULL, 0); + } + return; + } + + + if (priv->station_state == STATION_STATE_FORCED_JOINNING) { + atmel_enter_state(priv, STATION_STATE_FORCED_JOIN_FAILURE); + } else { + atmel_scan(priv, 1); + } + } +} + +static int atmel_wakeup_firmware(struct atmel_private *priv) +{ + struct host_info_struct *iface = &priv->host_info; + u16 mr1, mr3; + int i; + + if (priv->card_type == CARD_TYPE_SPI_FLASH) + atmel_set_gcr(priv->dev, GCR_REMAP); + + /* wake up on-board processor */ + atmel_clear_gcr(priv->dev, 0x0040); + atmel_write16(priv->dev, BSR, BSS_SRAM); + + if (priv->card_type == CARD_TYPE_SPI_FLASH) + mdelay(100); + + /* and wait for it */ + for (i = LOOP_RETRY_LIMIT; i; i--) { + mr1 = atmel_read16(priv->dev, MR1); + mr3 = atmel_read16(priv->dev, MR3); + + if (mr3 & MAC_BOOT_COMPLETE) + break; + if (mr1 & MAC_BOOT_COMPLETE && + priv->bus_type == BUS_TYPE_PCCARD) + break; + } + + if (i == 0) { + printk(KERN_ALERT "%s: MAC failed to boot.\n", priv->dev->name); + return 0; + } + + if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) { + printk(KERN_ALERT "%s: card missing.\n", priv->dev->name); + priv->station_state = STATION_STATE_NO_CARD; + return 0; + } + + /* now check for completion of MAC initialization through + the FunCtrl field of the IFACE, poll MR1 to detect completion of + MAC initialization, check completion status, set interrupt mask, + enables interrupts and calls Tx and Rx initialization functions */ + + atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), FUNC_CTRL_INIT_COMPLETE); + + for (i = LOOP_RETRY_LIMIT; i; i--) { + mr1 = atmel_read16(priv->dev, MR1); + mr3 = atmel_read16(priv->dev, MR3); + + if (mr3 & MAC_INIT_COMPLETE) + break; + if (mr1 & MAC_INIT_COMPLETE && + priv->bus_type == BUS_TYPE_PCCARD) + break; + } + + if (i == 0) { + printk(KERN_ALERT "%s: MAC failed to initialise.\n", priv->dev->name); + return 0; + } + + /* Check for MAC_INIT_OK only on the register that the MAC_INIT_OK was set */ + if ((mr3 & MAC_INIT_COMPLETE) && + !(atmel_read16(priv->dev, MR3) & MAC_INIT_OK)) { + printk(KERN_ALERT "%s: MAC failed MR3 self-test.\n", priv->dev->name); + return 0; + } + if ((mr1 & MAC_INIT_COMPLETE) && + !(atmel_read16(priv->dev, MR1) & MAC_INIT_OK)) { + printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name); + return 0; + } + + atmel_copy_to_host(priv->dev, (unsigned char *)iface, + priv->host_info_base, sizeof(*iface)); + + iface->tx_buff_pos = le16_to_cpu(iface->tx_buff_pos); + iface->tx_buff_size = le16_to_cpu(iface->tx_buff_size); + iface->tx_desc_pos = le16_to_cpu(iface->tx_desc_pos); + iface->tx_desc_count = le16_to_cpu(iface->tx_desc_count); + iface->rx_buff_pos = le16_to_cpu(iface->rx_buff_pos); + iface->rx_buff_size = le16_to_cpu(iface->rx_buff_size); + iface->rx_desc_pos = le16_to_cpu(iface->rx_desc_pos); + iface->rx_desc_count = le16_to_cpu(iface->rx_desc_count); + iface->build_version = le16_to_cpu(iface->build_version); + iface->command_pos = le16_to_cpu(iface->command_pos); + iface->major_version = le16_to_cpu(iface->major_version); + iface->minor_version = le16_to_cpu(iface->minor_version); + iface->func_ctrl = le16_to_cpu(iface->func_ctrl); + iface->mac_status = le16_to_cpu(iface->mac_status); + + return 1; +} + +/* determine type of memory and MAC address */ +static int probe_atmel_card(struct net_device *dev) +{ + int rc = 0; + struct atmel_private *priv = dev->priv; + + /* reset pccard */ + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + + atmel_write16(dev, GCR, 0x0040); + mdelay(500); + + if (atmel_read16(dev, MR2) == 0) { + /* No stored firmware so load a small stub which just + tells us the MAC address */ + int i; + priv->card_type = CARD_TYPE_EEPROM; + atmel_write16(dev, BSR, BSS_IRAM); + atmel_copy_to_card(dev, 0, mac_reader, sizeof(mac_reader)); + atmel_set_gcr(dev, GCR_REMAP); + atmel_clear_gcr(priv->dev, 0x0040); + atmel_write16(dev, BSR, BSS_SRAM); + for (i = LOOP_RETRY_LIMIT; i; i--) + if (atmel_read16(dev, MR3) & MAC_BOOT_COMPLETE) + break; + if (i == 0) { + printk(KERN_ALERT "%s: MAC failed to boot MAC address reader.\n", dev->name); + } else { + atmel_copy_to_host(dev, dev->dev_addr, atmel_read16(dev, MR2), 6); + + /* got address, now squash it again until the network + interface is opened */ + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + atmel_write16(dev, GCR, 0x0040); + rc = 1; + } + } else if (atmel_read16(dev, MR4) == 0) { + /* Mac address easy in this case. */ + priv->card_type = CARD_TYPE_PARALLEL_FLASH; + atmel_write16(dev, BSR, 1); + atmel_copy_to_host(dev, dev->dev_addr, 0xc000, 6); + atmel_write16(dev, BSR, 0x200); + rc = 1; + } else { + /* Standard firmware in flash, boot it up and ask + for the Mac Address */ + priv->card_type = CARD_TYPE_SPI_FLASH; + if (atmel_wakeup_firmware(priv)) { + atmel_get_mib(priv, Mac_Address_Mib_Type, 0, dev->dev_addr, 6); + + /* got address, now squash it again until the network + interface is opened */ + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + atmel_write16(dev, GCR, 0x0040); + rc = 1; + } + } + + if (rc) { + if (dev->dev_addr[0] == 0xFF) { + u8 default_mac[] = {0x00,0x04, 0x25, 0x00, 0x00, 0x00}; + printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name); + memcpy(dev->dev_addr, default_mac, 6); + } + printk(KERN_INFO "%s: MAC address %x:%x:%x:%x:%x:%x\n", + dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); + + } + + return rc; +} + +int reset_atmel_card(struct net_device *dev) +{ + /* do everything necessary to wake up the hardware, including + waiting for the lightning strike and throwing the knife switch.... + + set all the Mib values which matter in the card to match + their settings in the atmel_private structure. Some of these + can be altered on the fly, but many (WEP, infrastucture or ad-hoc) + can only be changed by tearing down the world and coming back through + here. + + This routine is also responsible for initialising some + hardware-specific fields in the atmel_private structure, + including a copy of the firmware's hostinfo stucture + which is the route into the rest of the firmare datastructures. */ + + int channel; + struct atmel_private *priv = dev->priv; + u8 configuration; + + if (priv->station_state == STATION_STATE_NO_CARD || + priv->station_state == STATION_STATE_DOWN) + return 0; + + /* reset pccard */ + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(priv->dev, GCR, 0x0060); + + /* stop card , disable interrupts */ + atmel_write16(priv->dev, GCR, 0x0040); + + /* any scheduled timer is no longer needed and might screw things up.. */ + del_timer_sync(&priv->management_timer); + if (priv->new_SSID_size) { + memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size); + priv->SSID_size = priv->new_SSID_size; + priv->new_SSID_size = 0; + } + priv->BSS_list_entries = 0; + + priv->AuthenticationRequestRetryCnt = 0; + priv->AssociationRequestRetryCnt = 0; + priv->ReAssociationRequestRetryCnt = 0; + priv->CurrentAuthentTransactionSeqNum = 0x0001; + priv->ExpectedAuthentTransactionSeqNum = 0x0002; + + priv->station_state = STATION_STATE_INITIALIZING; + priv->site_survey_state = SITE_SURVEY_IDLE; + priv->station_is_associated = 0; + + if (priv->card_type == CARD_TYPE_EEPROM) { + /* copy in firmware if needed */ +#ifdef CONFIG_FW_LOADER + const struct firmware *fw_entry = NULL; +#endif + unsigned char *fw; + int len = priv->firmware_length; + if (!(fw = priv->firmware)) { +#ifdef CONFIG_FW_LOADER + if (strlen(priv->firmware_id) == 0) { + printk(KERN_INFO + "%s: card type is unknown: assuming at76c502 firmware is OK.\n", + dev->name); + printk(KERN_INFO + "%s: if not, use the firmware= module parameter.\n", + dev->name); + strcpy(priv->firmware_id, "atmel_at76c502.bin"); + } + if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) != 0) { + printk(KERN_ALERT + "%s: firmware %s is missing, cannot start.\n", + dev->name, priv->firmware_id); + return 0; + } + fw = fw_entry->data; + len = fw_entry->size; +#else + printk(KERN_ALERT + "%s: no firmware supplied, cannot start.\n", dev->name); + return 0; +#endif + } + + if (len <= 0x6000) { + atmel_write16(priv->dev, BSR, BSS_IRAM); + atmel_copy_to_card(priv->dev, 0, fw, len); + atmel_set_gcr(priv->dev, GCR_REMAP); + } else { + /* Remap */ + atmel_set_gcr(priv->dev, GCR_REMAP); + atmel_write16(priv->dev, BSR, BSS_IRAM); + atmel_copy_to_card(priv->dev, 0, fw, 0x6000); + atmel_write16(priv->dev, BSR, 0x2ff); + atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000); + } + +#ifdef CONFIG_FW_LOADER + if (fw_entry) + release_firmware(fw_entry); +#endif + } + + if (!atmel_wakeup_firmware(priv)) + return 0; + + /* unmask all irq sources */ + atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff); + + /* int Tx system and enable Tx */ + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, 0), 0); + atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, 0), 0x80000000L); + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, 0), 0); + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, 0), 0); + + priv->tx_desc_free = priv->host_info.tx_desc_count; + priv->tx_desc_head = 0; + priv->tx_desc_tail = 0; + priv->tx_desc_previous = 0; + priv->tx_free_mem = priv->host_info.tx_buff_size; + priv->tx_buff_head = 0; + priv->tx_buff_tail = 0; + + configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); + atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), + configuration | FUNC_CTRL_TxENABLE); + + /* init Rx system and enable */ + priv->rx_desc_head = 0; + + configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); + atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), + configuration | FUNC_CTRL_RxENABLE); + + priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS); + if (priv->reg_domain != REG_DOMAIN_FCC && + priv->reg_domain != REG_DOMAIN_DOC && + priv->reg_domain != REG_DOMAIN_ETSI && + priv->reg_domain != REG_DOMAIN_SPAIN && + priv->reg_domain != REG_DOMAIN_FRANCE && + priv->reg_domain != REG_DOMAIN_MKK && + priv->reg_domain != REG_DOMAIN_MKK1 && + priv->reg_domain != REG_DOMAIN_ISRAEL) { + priv->reg_domain = REG_DOMAIN_MKK1; + printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name); + } + if ((channel = atmel_validate_channel(priv, priv->channel))) + priv->channel = channel; + + if (!priv->is3com) { + if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) == + CMD_STATUS_REJECTED_RADIO_OFF) { + printk(KERN_INFO + "%s: cannot turn the radio on. (Hey radio, you're beautiful!)\n", + dev->name); + return 0; + } + } + + /* set up enough MIB values to run. */ + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_AUTO_TX_RATE_POS, priv->auto_tx_rate); + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_TX_PROMISCUOUS_POS, PROM_MODE_OFF); + atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_RTS_THRESHOLD_POS, priv->rts_threshold); + atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_FRAG_THRESHOLD_POS, priv->frag_threshold); + atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_SHORT_RETRY_POS, priv->short_retry); + atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_LONG_RETRY_POS, priv->long_retry); + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, priv->preamble); + atmel_set_mib(priv, Mac_Address_Mib_Type, MAC_ADDR_MIB_MAC_ADDR_POS, + priv->dev->dev_addr, 6); + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period); + atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4); + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep.wep_is_on); + atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&priv->wep, sizeof(priv->wep)); + + atmel_scan(priv, 1); + + atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */ + + return 1; +} + +EXPORT_SYMBOL(reset_atmel_card); + +static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size) +{ + if (cmd) + atmel_copy_to_card(priv->dev, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET), + cmd, cmd_size); + + atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET), command); + atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET), 0); +} + +static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size) +{ + int i, status; + + atmel_send_command(priv, command, cmd, cmd_size); + + for (i = LOOP_RETRY_LIMIT; i; i--) { + status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); + if (status != CMD_STATUS_IDLE && + status != CMD_STATUS_IN_PROGRESS) + break; + } + + if (i == 0) { + printk(KERN_ALERT "%s: command %d failed to complete.\n", priv->dev->name, command); + status = CMD_STATUS_HOST_ERROR; + } else { + if (command != CMD_EnableRadio) + status = CMD_STATUS_COMPLETE; + } + + return status; +} + +static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index) +{ + struct get_set_mib m; + m.type = type; + m.size = 1; + m.index = index; + + atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, sizeof(m)); + return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + 4)); +} + +static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data) +{ + struct get_set_mib m; + m.type = type; + m.size = 1; + m.index = index; + m.data[0] = data; + + atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m)); +} + +static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 data) +{ + struct get_set_mib m; + m.type = type; + m.size = 2; + m.index = index; + m.data[0] = data; + m.data[1] = data >> 8; + + atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m)); +} + +static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len) +{ + struct get_set_mib m; + m.type = type; + m.size = data_len; + m.index = index; + + memcpy(m.data, data, data_len); + atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m)); +} + +static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len) +{ + struct get_set_mib m; + m.type = type; + m.size = data_len; + m.index = index; + + atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, sizeof(m)); + atmel_copy_to_host(priv->dev, data, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + 4), data_len); +} + +static void atmel_writeAR(struct net_device *dev, u16 data) +{ + int i; + outw(data, dev->base_addr + AR); + /* Address register appears to need some convincing..... */ + for (i = 0; data != inw(dev->base_addr + AR) && i<10; i++) + outw(data, dev->base_addr + AR); +} + +static void atmel_copy_to_card(struct net_device *dev, u16 dest, unsigned char *src, u16 len) +{ + int i; + atmel_writeAR(dev, dest); + if (dest % 2) { + atmel_write8(dev, DR, *src); + src++; len--; + } + for (i = len; i > 1 ; i -= 2) { + u8 lb = *src++; + u8 hb = *src++; + atmel_write16(dev, DR, lb | (hb << 8)); + } + if (i) + atmel_write8(dev, DR, *src); +} + +static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, u16 src, u16 len) +{ + int i; + atmel_writeAR(dev, src); + if (src % 2) { + *dest = atmel_read8(dev, DR); + dest++; len--; + } + for (i = len; i > 1 ; i -= 2) { + u16 hw = atmel_read16(dev, DR); + *dest++ = hw; + *dest++ = hw >> 8; + } + if (i) + *dest = atmel_read8(dev, DR); +} + +static void atmel_set_gcr(struct net_device *dev, u16 mask) +{ + outw(inw(dev->base_addr + GCR) | mask, dev->base_addr + GCR); +} + +static void atmel_clear_gcr(struct net_device *dev, u16 mask) +{ + outw(inw(dev->base_addr + GCR) & ~mask, dev->base_addr + GCR); +} + +static int atmel_lock_mac(struct atmel_private *priv) +{ + int i, j = 100; + retry: + for (i = LOOP_RETRY_LIMIT ; atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET)) && i ; i--); + + if (!i) return 0; /* timed out */ + + atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 1); + if (atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) { + atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); + if (!j--) return 0; /* timed out */ + goto retry; + } + + return 1; +} + +static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data) +{ + atmel_writeAR(priv->dev, pos); + atmel_write16(priv->dev, DR, data); /* card is little-endian */ + atmel_write16(priv->dev, DR, data >> 16); +} + + +/***************************************************************************/ +/* There follows the source form of the MAC address reading firmware */ +/***************************************************************************/ +#if 0 + +/* Copyright 2003 Matthew T. Russotto */ +/* But derived from the Atmel 76C502 firmware written by Atmel and */ +/* included in "atmel wireless lan drivers" package */ +/** + This file is part of net.russotto.AtmelMACFW, hereto referred to + as AtmelMACFW + + AtmelMACFW is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + AtmelMACFW 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 AtmelMACFW; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +****************************************************************************/ +/* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */ +/* It will probably work on the 76C504 and 76C502 RFMD_3COM */ +/* It only works on SPI EEPROM versions of the card. */ + +/* This firmware initializes the SPI controller and clock, reads the MAC */ +/* address from the EEPROM into SRAM, and puts the SRAM offset of the MAC */ +/* address in MR2, and sets MR3 to 0x10 to indicate it is done */ +/* It also puts a complete copy of the EEPROM in SRAM with the offset in */ +/* MR4, for investigational purposes (maybe we can determine chip type */ +/* from that?) */ + + .org 0 + .set MRBASE, 0x8000000 + .set CPSR_INITIAL, 0xD3 /* IRQ/FIQ disabled, ARM mode, Supervisor state */ + .set CPSR_USER, 0xD1 /* IRQ/FIQ disabled, ARM mode, USER state */ + .set SRAM_BASE, 0x02000000 + .set SP_BASE, 0x0F300000 + .set UNK_BASE, 0x0F000000 /* Some internal device, but which one? */ + .set SPI_CGEN_BASE, 0x0E000000 /* Some internal device, but which one? */ + .set UNK3_BASE, 0x02014000 /* Some internal device, but which one? */ + .set STACK_BASE, 0x5600 + .set SP_SR, 0x10 + .set SP_TDRE, 2 /* status register bit -- TDR empty */ + .set SP_RDRF, 1 /* status register bit -- RDR full */ + .set SP_SWRST, 0x80 + .set SP_SPIEN, 0x1 + .set SP_CR, 0 /* control register */ + .set SP_MR, 4 /* mode register */ + .set SP_RDR, 0x08 /* Read Data Register */ + .set SP_TDR, 0x0C /* Transmit Data Register */ + .set SP_CSR0, 0x30 /* chip select registers */ + .set SP_CSR1, 0x34 + .set SP_CSR2, 0x38 + .set SP_CSR3, 0x3C + .set NVRAM_CMD_RDSR, 5 /* read status register */ + .set NVRAM_CMD_READ, 3 /* read data */ + .set NVRAM_SR_RDY, 1 /* RDY bit. This bit is inverted */ + .set SPI_8CLOCKS, 0xFF /* Writing this to the TDR doesn't do anything to the + serial output, since SO is normally high. But it + does cause 8 clock cycles and thus 8 bits to be + clocked in to the chip. See Atmel's SPI + controller (e.g. AT91M55800) timing and 4K + SPI EEPROM manuals */ + + .set NVRAM_SCRATCH, 0x02000100 /* arbitrary area for scratchpad memory */ + .set NVRAM_IMAGE, 0x02000200 + .set NVRAM_LENGTH, 0x0200 + .set MAC_ADDRESS_MIB, SRAM_BASE + .set MAC_ADDRESS_LENGTH, 6 + .set MAC_BOOT_FLAG, 0x10 + .set MR1, 0 + .set MR2, 4 + .set MR3, 8 + .set MR4, 0xC +RESET_VECTOR: + b RESET_HANDLER +UNDEF_VECTOR: + b HALT1 +SWI_VECTOR: + b HALT1 +IABORT_VECTOR: + b HALT1 +DABORT_VECTOR: +RESERVED_VECTOR: + b HALT1 +IRQ_VECTOR: + b HALT1 +FIQ_VECTOR: + b HALT1 +HALT1: b HALT1 +RESET_HANDLER: + mov r0, #CPSR_INITIAL + msr CPSR_c, r0 /* This is probably unnecessary */ + +/* I'm guessing this is initializing clock generator electronics for SPI */ + ldr r0, =SPI_CGEN_BASE + mov r1, #0 + mov r1, r1, lsl #3 + orr r1,r1, #0 + str r1, [r0] + ldr r1, [r0, #28] + bic r1, r1, #16 + str r1, [r0, #28] + mov r1, #1 + str r1, [r0, #8] + + ldr r0, =MRBASE + mov r1, #0 + strh r1, [r0, #MR1] + strh r1, [r0, #MR2] + strh r1, [r0, #MR3] + strh r1, [r0, #MR4] + + mov sp, #STACK_BASE + bl SP_INIT + mov r0, #10 + bl DELAY9 + bl GET_MAC_ADDR + bl GET_WHOLE_NVRAM + ldr r0, =MRBASE + ldr r1, =MAC_ADDRESS_MIB + strh r1, [r0, #MR2] + ldr r1, =NVRAM_IMAGE + strh r1, [r0, #MR4] + mov r1, #MAC_BOOT_FLAG + strh r1, [r0, #MR3] +HALT2: b HALT2 +.func Get_Whole_NVRAM, GET_WHOLE_NVRAM +GET_WHOLE_NVRAM: + stmdb sp!, {lr} + mov r2, #0 /* 0th bytes of NVRAM */ + mov r3, #NVRAM_LENGTH + mov r1, #0 /* not used in routine */ + ldr r0, =NVRAM_IMAGE + bl NVRAM_XFER + ldmia sp!, {lr} + bx lr +.endfunc + +.func Get_MAC_Addr, GET_MAC_ADDR +GET_MAC_ADDR: + stmdb sp!, {lr} + mov r2, #0x120 /* address of MAC Address within NVRAM */ + mov r3, #MAC_ADDRESS_LENGTH + mov r1, #0 /* not used in routine */ + ldr r0, =MAC_ADDRESS_MIB + bl NVRAM_XFER + ldmia sp!, {lr} + bx lr +.endfunc +.ltorg +.func Delay9, DELAY9 +DELAY9: + adds r0, r0, r0, LSL #3 /* r0 = r0 * 9 */ +DELAYLOOP: + beq DELAY9_done + subs r0, r0, #1 + b DELAYLOOP +DELAY9_done: + bx lr +.endfunc + +.func SP_Init, SP_INIT +SP_INIT: + mov r1, #SP_SWRST + ldr r0, =SP_BASE + str r1, [r0, #SP_CR] /* reset the SPI */ + mov r1, #0 + str r1, [r0, #SP_CR] /* release SPI from reset state */ + mov r1, #SP_SPIEN + str r1, [r0, #SP_MR] /* set the SPI to MASTER mode*/ + str r1, [r0, #SP_CR] /* enable the SPI */ + +/* My guess would be this turns on the SPI clock */ + ldr r3, =SPI_CGEN_BASE + ldr r1, [r3, #28] + orr r1, r1, #0x2000 + str r1, [r3, #28] + + ldr r1, =0x2000c01 + str r1, [r0, #SP_CSR0] + ldr r1, =0x2000201 + str r1, [r0, #SP_CSR1] + str r1, [r0, #SP_CSR2] + str r1, [r0, #SP_CSR3] + ldr r1, [r0, #SP_SR] + ldr r0, [r0, #SP_RDR] + bx lr +.endfunc +.func NVRAM_Init, NVRAM_INIT +NVRAM_INIT: + ldr r1, =SP_BASE + ldr r0, [r1, #SP_RDR] + mov r0, #NVRAM_CMD_RDSR + str r0, [r1, #SP_TDR] +SP_loop1: + ldr r0, [r1, #SP_SR] + tst r0, #SP_TDRE + beq SP_loop1 + + mov r0, #SPI_8CLOCKS + str r0, [r1, #SP_TDR] +SP_loop2: + ldr r0, [r1, #SP_SR] + tst r0, #SP_TDRE + beq SP_loop2 + + ldr r0, [r1, #SP_RDR] +SP_loop3: + ldr r0, [r1, #SP_SR] + tst r0, #SP_RDRF + beq SP_loop3 + + ldr r0, [r1, #SP_RDR] + and r0, r0, #255 + bx lr +.endfunc + +.func NVRAM_Xfer, NVRAM_XFER + /* r0 = dest address */ + /* r1 = not used */ + /* r2 = src address within NVRAM */ + /* r3 = length */ +NVRAM_XFER: + stmdb sp!, {r4, r5, lr} + mov r5, r0 /* save r0 (dest address) */ + mov r4, r3 /* save r3 (length) */ + mov r0, r2, LSR #5 /* SPI memories put A8 in the command field */ + and r0, r0, #8 + add r0, r0, #NVRAM_CMD_READ + ldr r1, =NVRAM_SCRATCH + strb r0, [r1, #0] /* save command in NVRAM_SCRATCH[0] */ + strb r2, [r1, #1] /* save low byte of source address in NVRAM_SCRATCH[1] */ +_local1: + bl NVRAM_INIT + tst r0, #NVRAM_SR_RDY + bne _local1 + mov r0, #20 + bl DELAY9 + mov r2, r4 /* length */ + mov r1, r5 /* dest address */ + mov r0, #2 /* bytes to transfer in command */ + bl NVRAM_XFER2 + ldmia sp!, {r4, r5, lr} + bx lr +.endfunc + +.func NVRAM_Xfer2, NVRAM_XFER2 +NVRAM_XFER2: + stmdb sp!, {r4, r5, r6, lr} + ldr r4, =SP_BASE + mov r3, #0 + cmp r0, #0 + bls _local2 + ldr r5, =NVRAM_SCRATCH +_local4: + ldrb r6, [r5, r3] + str r6, [r4, #SP_TDR] +_local3: + ldr r6, [r4, #SP_SR] + tst r6, #SP_TDRE + beq _local3 + add r3, r3, #1 + cmp r3, r0 /* r0 is # of bytes to send out (command+addr) */ + blo _local4 +_local2: + mov r3, #SPI_8CLOCKS + str r3, [r4, #SP_TDR] + ldr r0, [r4, #SP_RDR] +_local5: + ldr r0, [r4, #SP_SR] + tst r0, #SP_RDRF + beq _local5 + ldr r0, [r4, #SP_RDR] /* what's this byte? It's the byte read while writing the TDR -- nonsense, because the NVRAM doesn't read and write at the same time */ + mov r0, #0 + cmp r2, #0 /* r2 is # of bytes to copy in */ + bls _local6 +_local7: + ldr r5, [r4, #SP_SR] + tst r5, #SP_TDRE + beq _local7 + str r3, [r4, #SP_TDR] /* r3 has SPI_8CLOCKS */ +_local8: + ldr r5, [r4, #SP_SR] + tst r5, #SP_RDRF + beq _local8 + ldr r5, [r4, #SP_RDR] /* but didn't we read this byte above? */ + strb r5, [r1], #1 /* postindexed */ + add r0, r0, #1 + cmp r0, r2 + blo _local7 /* since we don't send another address, the NVRAM must be capable of sequential reads */ +_local6: + mov r0, #200 + bl DELAY9 + ldmia sp!, {r4, r5, r6, lr} + bx lr +#endif diff -urN linux-2.5.70-bk10/drivers/net/wireless/atmel_cs.c linux-2.5.70-bk11/drivers/net/wireless/atmel_cs.c --- linux-2.5.70-bk10/drivers/net/wireless/atmel_cs.c 1969-12-31 16:00:00.000000000 -0800 +++ linux-2.5.70-bk11/drivers/net/wireless/atmel_cs.c 2003-06-06 04:38:24.000000000 -0700 @@ -0,0 +1,768 @@ +/*** -*- linux-c -*- ********************************************************** + + Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. + + Copyright 2000-2001 ATMEL Corporation. + Copyright 2003 Simon Kelley. + + This code was developed from version 2.1.1 of the Atmel drivers, + released by Atmel corp. under the GPL in December 2002. It also + includes code from the Linux aironet drivers (C) Benjamin Reed, + and the Linux PCMCIA package, (C) David Hinds. + + For all queries about this code, please contact the current author, + Simon Kelley and not Atmel Corporation. + + 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 software 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 Atmel wireless lan drivers; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +******************************************************************************/ + +#include +#ifdef __IN_PCMCIA_PACKAGE__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + + +/* + All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. +*/ +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +static char *version = "$Revision: 1.2 $"; +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* The old way: bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static u_int irq_mask = 0xdeb8; +/* Newer, simpler way of listing specific interrupts */ +static int irq_list[4] = { -1 }; + +MODULE_AUTHOR("Simon Kelley"); +MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethnet cards."); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards"); +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +/*====================================================================*/ + +/* + The event() function is this driver's Card Services event handler. + It will be called by Card Services when an appropriate card status + event is received. The config() and release() entry points are + used to configure or release a socket, in response to card + insertion and ejection events. They are invoked from the atmel_cs + event handler. +*/ + +struct net_device *init_atmel_card(int, int, char *, int, struct device *, + int (*present_func)(void *), void * ); +void stop_atmel_card( struct net_device *, int ); +int reset_atmel_card( struct net_device * ); + +static void atmel_config(dev_link_t *link); +static void atmel_release(u_long arg); +static int atmel_event(event_t event, int priority, + event_callback_args_t *args); + +/* + The attach() and detach() entry points are used to create and destroy + "instances" of the driver, where each instance represents everything + needed to manage one actual PCMCIA card. +*/ + +static dev_link_t *atmel_attach(void); +static void atmel_detach(dev_link_t *); + +/* + You'll also need to prototype all the functions that will actually + be used to talk to your device. See 'pcmem_cs' for a good example + of a fully self-sufficient driver; the other drivers rely more or + less on other parts of the kernel. +*/ + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "atmel_cs"; + +/* + A linked list of "instances" of the atmelnet device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; + +/* + A dev_link_t structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a dev_link_t structure can be used to point to + a device-specific private data structure, like this. + + A driver needs to provide a dev_node_t structure for each device + on a card. In some cases, there is only one device per card (for + example, ethernet cards, modems). In other cases, there may be + many actual or logical devices (SCSI adapters, memory cards with + multiple partitions). The dev_node_t structures need to be kept + in a linked list starting at the 'dev' field of a dev_link_t + structure. We allocate them in the card's private data structure, + because they generally shouldn't be allocated dynamically. + + In this case, we also provide a flag to indicate if a device is + "stopped" due to a power management event, or card ejection. The + device IO routines can use a flag like this to throttle IO to a + card that is not ready to accept it. +*/ + +typedef struct local_info_t { + dev_node_t node; + struct net_device *eth_dev; +} local_info_t; + +/*====================================================================== + + This bit of code is used to avoid unregistering network devices + at inappropriate times. 2.2 and later kernels are fairly picky + about when this can happen. + + ======================================================================*/ + +static void flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + atmel_detach(link); + } +} + +/*====================================================================== + + atmel_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + + ======================================================================*/ + +static dev_link_t *atmel_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + local_info_t *local; + int ret, i; + + DEBUG(0, "atmel_attach()\n"); + flush_stale_links(); + + /* Initialize the dev_link_t structure */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + if (!link) { + printk(KERN_ERR "atmel_cs: no memory for new device\n"); + return NULL; + } + memset(link, 0, sizeof(struct dev_link_t)); + init_timer(&link->release); + link->release.function = &atmel_release; + link->release.data = (u_long)link; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = NULL; + + /* + General socket configuration defaults can go here. In this + client, we assume very little, and rely on the CIS for almost + everything. In most clients, many details (i.e., number, sizes, + and attributes of IO windows) are fixed by the nature of the + device, and can be hard-wired here. + */ + link->conf.Attributes = 0; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Allocate space for private device-specific data */ + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) { + printk(KERN_ERR "atmel_cs: no memory for new device\n"); + kfree (link); + return NULL; + } + memset(local, 0, sizeof(local_info_t)); + link->priv = local; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &atmel_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + atmel_detach(link); + return NULL; + } + + return link; +} /* atmel_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + + ======================================================================*/ + +static void atmel_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "atmel_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + del_timer(&link->release); + if ( link->state & DEV_CONFIG ) { + atmel_release( (int)link ); + if ( link->state & DEV_STALE_CONFIG ) { + link->state |= DEV_STALE_LINK; + return; + } + } + + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + + + /* Unlink device structure, free pieces */ + *linkp = link->next; + if (link->priv) { + kfree(link->priv); + } + kfree(link); + +} /* atmel_detach */ + +/*====================================================================== + + atmel_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + device available to the system. + + ======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +/* Call-back function to interrogate PCMCIA-specific information + about the current existance of the card */ +static int card_present(void *arg) +{ + dev_link_t *link = (dev_link_t *)arg; + if (link->state & DEV_SUSPEND) + return 0; + else if (link->state & DEV_PRESENT) + return 1; + + return 0; +} + +/* list of cards we know about and their firmware requirements. + Go either by Manfid or version strings. + Cards not in this list will need a firmware parameter to the module + in all probability. Note that the SMC 2632 V2 and V3 have the same + manfids, so we ignore those and use the version1 strings. */ + +static struct { + int manf, card; + char *ver1; + char *firmware; + char *name; +} card_table[] = { + { 0, 0, "WLAN/802.11b PC CARD", "atmel_at76c502d.bin", "Actiontec 802CAT1" }, + { 0, 0, "ATMEL/AT76C502AR", "atmel_at76c502.bin", "NoName-RFMD" }, + { 0, 0, "ATMEL/AT76C502AR_D", "atmel_at76c502d.bin", "NoName-revD" }, + { 0, 0, "ATMEL/AT76C502AR_E", "atmel_at76c502e.bin", "NoName-revE" }, + { 0, 0, "ATMEL/AT76C504", "atmel_at76c504.bin", "NoName-504" }, + { MANFID_3COM, 0x0620, NULL, "atmel_at76c502_3com.bin", "3com 3CRWE62092B" }, + { MANFID_3COM, 0x0696, NULL, "atmel_at76c502_3com.bin", "3com 3CRSHPW_96" }, + { 0, 0, "SMC/2632W-V2", "atmel_at76c502.bin", "SMC 2632W-V2" }, + { 0, 0, "SMC/2632W", "atmel_at76c502d.bin", "SMC 2632W-V3" }, + { 0xd601, 0x0007, NULL, "atmel_at76c502.bin", "Sitecom WLAN-011"}, /* suspect - from a usenet posting. */ + { 0x01bf, 0x3302, NULL, "atmel_at76c502d.bin", "Belkin F5D6060u"}, /* " " " " " */ +}; + +/* This is strictly temporary, until PCMCIA devices get integrated into the device model. */ +static struct device atmel_device = { + .name = "Atmel at76c50x wireless", + .bus_id = "pcmcia", +}; + +static void atmel_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + local_info_t *dev; + int last_fn, last_ret; + u_char buf[64]; + int card_index = -1; + + handle = link->handle; + dev = link->priv; + + DEBUG(0, "atmel_config(0x%p)\n", link); + + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + + tuple.DesiredTuple = CISTPL_MANFID; + if (CardServices(GetFirstTuple, handle, &tuple) == 0) { + int i; + cistpl_manfid_t *manfid; + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + manfid = &(parse.manfid); + for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) { + if (!card_table[i].ver1 && + manfid->manf == card_table[i].manf && + manfid->card == card_table[i].card) { + card_index = i; + goto done; + } + } + } + + tuple.DesiredTuple = CISTPL_VERS_1; + if (CardServices(GetFirstTuple, handle, &tuple) == 0) { + int i, j, k; + cistpl_vers_1_t *ver1; + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + ver1 = &(parse.version_1); + + for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) { + for (j = 0; j < ver1->ns; j++) { + char *p = card_table[i].ver1; + char *q = &ver1->str[ver1->ofs[j]]; + if (!p) + goto mismatch; + for (k = 0; k < j; k++) { + while ((*p != '\0') && (*p != '/')) p++; + if (*p == '\0') + goto mismatch; + p++; + } + while((*q != '\0') && (*p != '\0') && + (*p != '/') && (*p == *q)) p++, q++; + if (((*p != '\0') && *p != '/') || *q != '\0') + goto mismatch; + } + card_index = i; + goto done; + + mismatch: + + } + done: + } + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* + In this loop, we scan the CIS for configuration table entries, + each of which describes a valid card configuration, including + voltage, IO window, memory window, and interrupt settings. + + We make no assumptions about the card to be configured: we use + just the information available in the CIS. In an ideal world, + this would work for any PCMCIA card, but it requires a complete + and accurate CIS. In practice, a driver usually "knows" most of + these things without consulting the CIS, and most client drivers + will only use the CIS to fill in implementation-defined details. + */ + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + cistpl_cftable_entry_t dflt = { 0 }; + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; + if (cfg->index == 0) goto next_entry; + link->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1<conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vcc.present & (1<conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; + + if (cfg->vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vpp1.present & (1<conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) + link->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + } + + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK(RequestIO, link->handle, &link->io); + /* If we got this far, we're cool! */ + break; + + next_entry: + CS_CHECK(GetNextTuple, handle, &tuple); + } + + /* + Allocate an interrupt line. Note that this does not assign a + handler to the interrupt, unless the 'Handler' member of the + irq structure is initialized. + */ + if (link->conf.Attributes & CONF_ENABLE_IRQ) + CS_CHECK(RequestIRQ, link->handle, &link->irq); + + /* + This actually configures the PCMCIA socket -- setting up + the I/O windows and the interrupt mapping, and putting the + card and host interface into "Memory and IO" mode. + */ + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + if (link->irq.AssignedIRQ == 0) { + printk(KERN_ALERT + "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config."); + goto cs_failed; + } + + ((local_info_t*)link->priv)->eth_dev = + init_atmel_card(link->irq.AssignedIRQ, + link->io.BasePort1, + card_index == -1 ? NULL : card_table[card_index].firmware, + card_index == -1 ? 0 : (card_table[card_index].manf == MANFID_3COM), + &atmel_device, + card_present, + link); + if (!((local_info_t*)link->priv)->eth_dev) + goto cs_failed; + + /* + At this point, the dev_node_t structure(s) need to be + initialized and arranged in a linked list at link->dev. + */ + strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name ); + dev->node.major = dev->node.minor = 0; + link->dev = &dev->node; + + /* Finally, report what we've done */ + printk(KERN_INFO "%s: %s%sindex 0x%02x: Vcc %d.%d", + dev->node.dev_name, + card_index == -1 ? "" : card_table[card_index].name, + card_index == -1 ? "" : " ", + link->conf.ConfigIndex, + link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1-1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2+link->io.NumPorts2-1); + printk("\n"); + + link->state &= ~DEV_CONFIG_PENDING; + return; + + cs_failed: + cs_error(link->handle, last_fn, last_ret); + atmel_release((u_long)link); + +} /* atmel_config */ + +/*====================================================================== + + After a card is removed, atmel_release() will unregister the + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + + ======================================================================*/ + +static void atmel_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + struct net_device *dev = ((local_info_t*)link->priv)->eth_dev; + + DEBUG(0, "atmel_release(0x%p)\n", link); + + /* Unlink the device chain */ + link->dev = NULL; + + if (dev) + stop_atmel_card(dev, 0); + ((local_info_t*)link->priv)->eth_dev = 0; + + /* Don't bother checking to see if these succeed or not */ + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + if (link->irq.AssignedIRQ) + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + +} /* atmel_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. + + When a CARD_REMOVAL event is received, we immediately set a + private flag to block future accesses to this device. All the + functions that actually access the device should check this flag + to make sure the card is still present. + + ======================================================================*/ + +static int atmel_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + local_info_t *local = link->priv; + + DEBUG(1, "atmel_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + netif_device_detach(local->eth_dev); + mod_timer(&link->release, jiffies + HZ/20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + atmel_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + netif_device_detach(local->eth_dev); + CardServices(ReleaseConfiguration, link->handle); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, &link->conf); + reset_atmel_card(local->eth_dev); + netif_device_attach(local->eth_dev); + } + break; + } + return 0; +} /* atmel_event */ + +/*====================================================================*/ +static struct pcmcia_driver atmel_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "atmel_cs", + }, + .attach = atmel_attach, + .detach = atmel_detach, +}; + +static int atmel_cs_init(void) +{ + return pcmcia_register_driver(&atmel_driver); +} + +static void atmel_cs_cleanup(void) +{ + pcmcia_unregister_driver(&atmel_driver); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) + atmel_release((u_long)dev_list); + atmel_detach(dev_list); + } +} + +/* + 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. + + In addition: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +module_init(atmel_cs_init); +module_exit(atmel_cs_cleanup); diff -urN linux-2.5.70-bk10/drivers/pci/pci.h linux-2.5.70-bk11/drivers/pci/pci.h --- linux-2.5.70-bk10/drivers/pci/pci.h 2003-06-06 04:38:14.000000000 -0700 +++ linux-2.5.70-bk11/drivers/pci/pci.h 2003-06-06 04:38:24.000000000 -0700 @@ -25,7 +25,6 @@ /* Functions for PCI Hotplug drivers to use */ extern struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); extern unsigned int pci_do_scan_bus(struct pci_bus *bus); -extern void pci_remove_bus_device(struct pci_dev *dev); extern int pci_remove_device_safe(struct pci_dev *dev); extern unsigned char pci_max_busnr(void); extern unsigned char pci_bus_max_busnr(struct pci_bus *bus); diff -urN linux-2.5.70-bk10/drivers/pci/pci.ids linux-2.5.70-bk11/drivers/pci/pci.ids --- linux-2.5.70-bk10/drivers/pci/pci.ids 2003-05-26 18:00:40.000000000 -0700 +++ linux-2.5.70-bk11/drivers/pci/pci.ids 2003-06-06 04:38:24.000000000 -0700 @@ -3745,19 +3745,26 @@ 11fc Silicon Magic 11fd High Street Consultants 11fe Comtrol Corporation - 0001 RocketPort 8 Oct - 0002 RocketPort 8 Intf - 0003 RocketPort 16 Intf - 0004 RocketPort 32 Intf - 0005 RocketPort Octacable - 0006 RocketPort 8J - 0007 RocketPort 4-port - 0008 RocketPort 8-port - 0009 RocketPort 16-port - 000a RocketPort Plus Quadcable - 000b RocketPort Plus Octacable - 000c RocketPort 8-port Modem - 8015 RocketPort 4-port UART 16954 + 0001 Rocketport 32 port w/external I/F + 0002 Rocketport 8 port w/external I/F + 0003 Rocketport 16 port w/external I/F + 0004 Rocketport 4 port w/quad cable + 0005 Rocketport 8 port w/octa cable + 0006 Rocketport 8 port w/RJ11 connectors + 0007 Rocketport 4 port w/RJ11 connectors + 000a Rocketport Plus 4 port + 000b Rocketport Plus 8 port + 000c RocketModem 6 port + 000d RocketModem 4-port + 000e Rocketport Plus 2 port RS232 + 000f Rocketport Plus 2 port RS422 + 0801 Rocketport UPCI 32 port w/external I/F + 0802 Rocketport UPCI 8 port w/external I/F + 0803 Rocketport UPCI 16 port w/external I/F + 0805 Rocketport UPCI 8 port w/octa cable + 080C RocketModem III 8 port + 080D RocketModem III 4 port + 0903 Rocketport Compact PCI 16 port w/external I/F 11ff Scion Corporation 1200 CSS Corporation 1201 Vista Controls Corp diff -urN linux-2.5.70-bk10/drivers/pci/probe.c linux-2.5.70-bk11/drivers/pci/probe.c --- linux-2.5.70-bk10/drivers/pci/probe.c 2003-06-06 04:38:14.000000000 -0700 +++ linux-2.5.70-bk11/drivers/pci/probe.c 2003-06-06 04:38:24.000000000 -0700 @@ -689,7 +689,6 @@ } EXPORT_SYMBOL(pci_scan_bus_parented); -EXPORT_SYMBOL(pci_devices); EXPORT_SYMBOL(pci_root_buses); #ifdef CONFIG_HOTPLUG diff -urN linux-2.5.70-bk10/drivers/pci/search.c linux-2.5.70-bk11/drivers/pci/search.c --- linux-2.5.70-bk10/drivers/pci/search.c 2003-06-06 04:38:14.000000000 -0700 +++ linux-2.5.70-bk11/drivers/pci/search.c 2003-06-06 04:38:25.000000000 -0700 @@ -118,6 +118,34 @@ /** + * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id + * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids + * @from: Previous PCI device found in search, or %NULL for new search. + * + * Iterates through the list of known PCI devices in the reverse order of pci_find_device(). + * If a PCI device is found with a matching @vendor and @device, a pointer to + * its device structure is returned. Otherwise, %NULL is returned. + * A new search is initiated by passing %NULL to the @from argument. + * Otherwise if @from is not %NULL, searches continue from previous device on the global list. + */ +struct pci_dev * +pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from) +{ + struct list_head *n = from ? from->global_list.prev : pci_devices.prev; + + while (n != &pci_devices) { + struct pci_dev *dev = pci_dev_g(n); + if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && + (device == PCI_ANY_ID || dev->device == device)) + return dev; + n = n->prev; + } + return NULL; +} + + +/** * pci_find_class - begin or continue searching for a PCI device by class * @class: search for a PCI device with this class designation * @from: Previous PCI device found in search, or %NULL for new search. @@ -143,8 +171,20 @@ return NULL; } +/** + * pci_present - determine if there are any pci devices on this system + * + * Returns 0 if no pci devices are present, 1 if pci devices are present. + */ +int pci_present(void) +{ + return !list_empty(&pci_devices); +} + EXPORT_SYMBOL(pci_find_bus); EXPORT_SYMBOL(pci_find_class); EXPORT_SYMBOL(pci_find_device); +EXPORT_SYMBOL(pci_find_device_reverse); EXPORT_SYMBOL(pci_find_slot); EXPORT_SYMBOL(pci_find_subsys); +EXPORT_SYMBOL(pci_present); diff -urN linux-2.5.70-bk10/drivers/scsi/Kconfig linux-2.5.70-bk11/drivers/scsi/Kconfig --- linux-2.5.70-bk10/drivers/scsi/Kconfig 2003-05-26 18:00:57.000000000 -0700 +++ linux-2.5.70-bk11/drivers/scsi/Kconfig 2003-06-06 04:38:25.000000000 -0700 @@ -1559,7 +1559,7 @@ config SCSI_MESH tristate "MESH (Power Mac internal SCSI) support" - depends on ALL_PPC && SCSI + depends on PPC_PMAC && SCSI help Many Power Macintoshes and clones have a MESH (Macintosh Enhanced SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the @@ -1590,7 +1590,7 @@ config SCSI_MAC53C94 tristate "53C94 (Power Mac external SCSI) support" - depends on ALL_PPC && SCSI + depends on PPC_PMAC && SCSI help On Power Macintoshes (and clones) with two SCSI buses, the external SCSI bus is usually controlled by a 53C94 SCSI bus adaptor. Older diff -urN linux-2.5.70-bk10/drivers/serial/sunsab.c linux-2.5.70-bk11/drivers/serial/sunsab.c --- linux-2.5.70-bk10/drivers/serial/sunsab.c 2003-05-26 18:00:38.000000000 -0700 +++ linux-2.5.70-bk11/drivers/serial/sunsab.c 2003-06-06 04:38:26.000000000 -0700 @@ -231,8 +231,10 @@ set_bit(SAB82532_ALLS, &up->irqflags); } +#if 0 /* bde@nwlink.com says this check causes problems */ if (!(stat->sreg.isr1 & SAB82532_ISR1_XPR)) return; +#endif if (!(readb(&up->regs->r.star) & SAB82532_STAR_XFW)) return; @@ -242,6 +244,7 @@ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { up->interrupt_mask1 |= SAB82532_IMR1_XPR; writeb(up->interrupt_mask1, &up->regs->w.imr1); + uart_write_wakeup(&up->port); return; } diff -urN linux-2.5.70-bk10/drivers/usb/image/hpusbscsi.c linux-2.5.70-bk11/drivers/usb/image/hpusbscsi.c --- linux-2.5.70-bk10/drivers/usb/image/hpusbscsi.c 2003-06-06 04:38:14.000000000 -0700 +++ linux-2.5.70-bk11/drivers/usb/image/hpusbscsi.c 2003-06-06 04:38:26.000000000 -0700 @@ -93,17 +93,6 @@ } } - /* USB initialisation magic for the simple case */ - result = usb_set_interface(dev, altsetting->desc.bInterfaceNumber, 0); - switch (result) { - case 0: /* no error */ - break; - default: - printk(KERN_ERR "unknown error %d from usb_set_interface\n", - result); - goto out_free_controlurb; - } - /* build and submit an interrupt URB for status byte handling */ usb_fill_int_urb(new->controlurb, new->dev, usb_rcvintpipe(new->dev, new->ep_int), diff -urN linux-2.5.70-bk10/drivers/usb/input/hid-input.c linux-2.5.70-bk11/drivers/usb/input/hid-input.c --- linux-2.5.70-bk10/drivers/usb/input/hid-input.c 2003-06-06 04:38:14.000000000 -0700 +++ linux-2.5.70-bk11/drivers/usb/input/hid-input.c 2003-06-06 04:38:26.000000000 -0700 @@ -70,8 +70,11 @@ hidinput = list_entry(lh, struct hid_input, list); - for (i = 0; i < hidinput->maxfield; i++) - if (hidinput->fields[i] == field) + if (! hidinput->report) + continue; + + for (i = 0; i < hidinput->report->maxfield; i++) + if (hidinput->report->field[i] == field) return &hidinput->input; } @@ -527,7 +530,7 @@ struct hid_report *report; struct list_head *list; struct hid_input *hidinput = NULL; - int i, j; + int i, j, k; INIT_LIST_HEAD(&hid->inputs); @@ -539,57 +542,57 @@ if (i == hid->maxcollection) return -1; - report_enum = hid->report_enum + HID_INPUT_REPORT; - list = report_enum->report_list.next; - while (list != &report_enum->report_list) { - report = (struct hid_report *) list; + for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { + report_enum = hid->report_enum + k; + list = report_enum->report_list.next; + while (list != &report_enum->report_list) { + report = (struct hid_report *) list; - if (!report->maxfield) - continue; + if (!report->maxfield) + continue; - if (!hidinput) { - hidinput = kmalloc(sizeof(*hidinput), GFP_KERNEL); if (!hidinput) { - err("Out of memory during hid input probe"); - return -1; - } - memset(hidinput, 0, sizeof(*hidinput)); - - list_add_tail(&hidinput->list, &hid->inputs); + hidinput = kmalloc(sizeof(*hidinput), GFP_KERNEL); + if (!hidinput) { + err("Out of memory during hid input probe"); + return -1; + } + memset(hidinput, 0, sizeof(*hidinput)); - hidinput->input.private = hid; - hidinput->input.event = hidinput_input_event; - hidinput->input.open = hidinput_open; - hidinput->input.close = hidinput_close; - - hidinput->input.name = hid->name; - hidinput->input.phys = hid->phys; - hidinput->input.uniq = hid->uniq; - hidinput->input.id.bustype = BUS_USB; - hidinput->input.id.vendor = dev->descriptor.idVendor; - hidinput->input.id.product = dev->descriptor.idProduct; - hidinput->input.id.version = dev->descriptor.bcdDevice; - } + list_add_tail(&hidinput->list, &hid->inputs); - for (i = 0; i < report->maxfield; i++) - for (j = 0; j < report->field[i]->maxusage; j++) - hidinput_configure_usage(hidinput, report->field[i], - report->field[i]->usage + j); - - if (hid->quirks & HID_QUIRK_MULTI_INPUT) { - /* This will leave hidinput NULL, so that it - * allocates another one if we have more inputs on - * the same interface. Some devices (e.g. Happ's - * UGCI) cram a lot of unrelated inputs into the - * same interface. */ - hidinput->fields = report->field; - hidinput->maxfield = report->maxfield; + hidinput->input.private = hid; + hidinput->input.event = hidinput_input_event; + hidinput->input.open = hidinput_open; + hidinput->input.close = hidinput_close; + + hidinput->input.name = hid->name; + hidinput->input.phys = hid->phys; + hidinput->input.uniq = hid->uniq; + hidinput->input.id.bustype = BUS_USB; + hidinput->input.id.vendor = dev->descriptor.idVendor; + hidinput->input.id.product = dev->descriptor.idProduct; + hidinput->input.id.version = dev->descriptor.bcdDevice; + } + + for (i = 0; i < report->maxfield; i++) + for (j = 0; j < report->field[i]->maxusage; j++) + hidinput_configure_usage(hidinput, report->field[i], + report->field[i]->usage + j); + + if (hid->quirks & HID_QUIRK_MULTI_INPUT) { + /* This will leave hidinput NULL, so that it + * allocates another one if we have more inputs on + * the same interface. Some devices (e.g. Happ's + * UGCI) cram a lot of unrelated inputs into the + * same interface. */ + hidinput->report = report; + input_register_device(&hidinput->input); + hidinput = NULL; + } - input_register_device(&hidinput->input); - hidinput = NULL; + list = list->next; } - - list = list->next; } /* This only gets called when we are a single-input (most of the diff -urN linux-2.5.70-bk10/drivers/usb/input/hid.h linux-2.5.70-bk11/drivers/usb/input/hid.h --- linux-2.5.70-bk10/drivers/usb/input/hid.h 2003-06-06 04:38:14.000000000 -0700 +++ linux-2.5.70-bk11/drivers/usb/input/hid.h 2003-06-06 04:38:26.000000000 -0700 @@ -324,8 +324,7 @@ struct hid_input { struct list_head list; - struct hid_field **fields; - int maxfield; + struct hid_report *report; struct input_dev input; }; diff -urN linux-2.5.70-bk10/drivers/usb/serial/empeg.c linux-2.5.70-bk11/drivers/usb/serial/empeg.c --- linux-2.5.70-bk10/drivers/usb/serial/empeg.c 2003-06-06 04:38:15.000000000 -0700 +++ linux-2.5.70-bk11/drivers/usb/serial/empeg.c 2003-06-06 04:38:27.000000000 -0700 @@ -460,14 +460,15 @@ static int empeg_startup (struct usb_serial *serial) { + int r; dbg("%s", __FUNCTION__); dbg("%s - Set config to 1", __FUNCTION__); - usb_set_configuration (serial->dev, 1); + r = usb_set_configuration (serial->dev, 1); /* continue on with initialization */ - return 0; + return r; } diff -urN linux-2.5.70-bk10/drivers/video/Kconfig linux-2.5.70-bk11/drivers/video/Kconfig --- linux-2.5.70-bk10/drivers/video/Kconfig 2003-05-26 18:00:21.000000000 -0700 +++ linux-2.5.70-bk11/drivers/video/Kconfig 2003-06-06 04:38:28.000000000 -0700 @@ -235,28 +235,28 @@ config FB_OF bool "Open Firmware frame buffer device support" - depends on FB && (PPC64 || (PPC && ALL_PPC)) + depends on FB && (PPC64 || PPC_OF) help Say Y if you want support with Open Firmware for your graphics board. config FB_CONTROL bool "Apple \"control\" display support" - depends on FB && PPC && ALL_PPC + depends on FB && PPC_PMAC help This driver supports a frame buffer for the graphics adapter in the Power Macintosh 7300 and others. config FB_PLATINUM bool "Apple \"platinum\" display support" - depends on FB && PPC && ALL_PPC + depends on FB && PPC_PMAC help This driver supports a frame buffer for the "platinum" graphics adapter in some Power Macintoshes. config FB_VALKYRIE bool "Apple \"valkyrie\" display support" - depends on FB && (MAC || PPC && ALL_PPC) + depends on FB && (MAC || PPC_PMAC) help This driver supports a frame buffer for the "valkyrie" graphics adapter in some Power Macintoshes. diff -urN linux-2.5.70-bk10/drivers/video/aty/aty128fb.c linux-2.5.70-bk11/drivers/video/aty/aty128fb.c --- linux-2.5.70-bk10/drivers/video/aty/aty128fb.c 2003-05-26 18:00:39.000000000 -0700 +++ linux-2.5.70-bk11/drivers/video/aty/aty128fb.c 2003-06-06 04:38:28.000000000 -0700 @@ -59,7 +59,7 @@ #include #include -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC #include #include #include "../macmodes.h" @@ -93,7 +93,7 @@ #define DBG(fmt, args...) #endif -#ifndef CONFIG_ALL_PPC +#ifndef CONFIG_PPC_PMAC /* default mode */ static struct fb_var_screeninfo default_var __initdata = { /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ @@ -103,7 +103,7 @@ 0, FB_VMODE_NONINTERLACED }; -#else /* CONFIG_ALL_PPC */ +#else /* CONFIG_PPC_PMAC */ /* default to 1024x768 at 75Hz on PPC - this will work * on the iMac, the usual 640x480 @ 60Hz doesn't. */ static struct fb_var_screeninfo default_var = { @@ -114,7 +114,7 @@ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }; -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ /* default modedb mode */ /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ @@ -259,7 +259,7 @@ static char *mode_option __initdata = NULL; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC static int default_vmode __initdata = VMODE_1024_768_60; static int default_cmode __initdata = CMODE_8; #endif @@ -1434,7 +1434,7 @@ continue; } #endif -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* vmode and cmode deprecated */ if (!strncmp(this_opt, "vmode:", 6)) { unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); @@ -1459,7 +1459,7 @@ } continue; } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ mode_option = this_opt; } return 0; @@ -1543,7 +1543,7 @@ #endif var = default_var; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC if (_machine == _MACH_Pmac) { if (mode_option) { if (!mac_find_mode(&var, info, mode_option, 8)) @@ -1582,7 +1582,7 @@ var = default_var; } } else -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ { if (fb_find_mode(&var, info, mode_option, NULL, 0, &defaultmode, 8) == 0) @@ -1872,7 +1872,7 @@ static void __init aty128_timings(struct aty128fb_par *par) { -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF /* instead of a table lookup, assume OF has properly * setup the PLL registers and use their values * to set the XCLK values and reference divider values */ @@ -1886,7 +1886,7 @@ if (!par->constants.dotclock) par->constants.dotclock = 2950; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV); xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7; Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8; diff -urN linux-2.5.70-bk10/drivers/video/cirrusfb.c linux-2.5.70-bk11/drivers/video/cirrusfb.c --- linux-2.5.70-bk10/drivers/video/cirrusfb.c 2003-05-26 18:00:56.000000000 -0700 +++ linux-2.5.70-bk11/drivers/video/cirrusfb.c 2003-06-06 04:38:28.000000000 -0700 @@ -56,7 +56,7 @@ #ifdef CONFIG_AMIGA #include #endif -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PREP #include #define isPReP (_machine == _MACH_prep) #else @@ -2395,7 +2395,7 @@ -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PREP #define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000) #define PREP_IO_BASE ((volatile unsigned char *) 0x80000000) static void __init get_prep_addrs (unsigned long *display, unsigned long *registers) @@ -2408,7 +2408,7 @@ DPRINTK ("EXIT\n"); } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PREP */ @@ -2543,7 +2543,7 @@ pcibios_write_config_dword (0, pdev->devfn, PCI_BASE_ADDRESS_0, 0x00000000); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PREP get_prep_addrs (&board_addr, &info->fbregs_phys); #endif } else { diff -urN linux-2.5.70-bk10/drivers/video/fbmon.c linux-2.5.70-bk11/drivers/video/fbmon.c --- linux-2.5.70-bk10/drivers/video/fbmon.c 2003-05-26 18:00:56.000000000 -0700 +++ linux-2.5.70-bk11/drivers/video/fbmon.c 2003-06-06 04:38:28.000000000 -0700 @@ -29,7 +29,7 @@ #include #include #include -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF #include #include #endif @@ -828,7 +828,7 @@ printk("========================================\n"); } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF char *get_EDID_from_OF(struct pci_dev *pdev) { static char *propnames[] = @@ -1256,7 +1256,7 @@ #ifdef CONFIG_X86 EXPORT_SYMBOL(get_EDID_from_BIOS); #endif -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF EXPORT_SYMBOL(get_EDID_from_OF); #endif EXPORT_SYMBOL(fb_get_monitor_limits); diff -urN linux-2.5.70-bk10/drivers/video/matrox/matroxfb_base.c linux-2.5.70-bk11/drivers/video/matrox/matroxfb_base.c --- linux-2.5.70-bk10/drivers/video/matrox/matroxfb_base.c 2003-06-06 04:38:15.000000000 -0700 +++ linux-2.5.70-bk11/drivers/video/matrox/matroxfb_base.c 2003-06-06 04:38:28.000000000 -0700 @@ -115,7 +115,7 @@ #include #include -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC unsigned char nvram_read_byte(int); static int default_vmode = VMODE_NVRAM; static int default_cmode = CMODE_NVRAM; @@ -1763,7 +1763,7 @@ } /* FIXME: Where to move this?! */ -#if defined(CONFIG_ALL_PPC) +#if defined(CONFIG_PPC_PMAC) #ifndef MODULE if (_machine == _MACH_Pmac) { struct fb_var_screeninfo var; @@ -1783,7 +1783,7 @@ } } #endif /* !MODULE */ -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ vesafb_defined.xres_virtual = vesafb_defined.xres; if (nopan) { vesafb_defined.yres_virtual = vesafb_defined.yres; @@ -2270,7 +2270,7 @@ dfp_type = simple_strtoul(this_opt+4, NULL, 0); dfp = 1; } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC else if (!strncmp(this_opt, "vmode:", 6)) { unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); if (vmode > 0 && vmode <= VMODE_MAX) @@ -2441,7 +2441,7 @@ MODULE_PARM_DESC(dfp, "Specifies whether to use digital flat panel interface of G200/G400 (0 or 1) (default=0)"); MODULE_PARM(dfp_type, "i"); MODULE_PARM_DESC(dfp_type, "Specifies DFP interface type (0 to 255) (default=read from hardware)"); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC MODULE_PARM(vmode, "i"); MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)"); MODULE_PARM(cmode, "i"); diff -urN linux-2.5.70-bk10/drivers/video/matrox/matroxfb_base.h linux-2.5.70-bk11/drivers/video/matrox/matroxfb_base.h --- linux-2.5.70-bk10/drivers/video/matrox/matroxfb_base.h 2003-06-06 04:38:15.000000000 -0700 +++ linux-2.5.70-bk11/drivers/video/matrox/matroxfb_base.h 2003-06-06 04:38:28.000000000 -0700 @@ -52,7 +52,7 @@ #include "../console/fbcon.h" -#if defined(CONFIG_ALL_PPC) +#if defined(CONFIG_PPC_PMAC) #include #include #include