From: Alan Cox Date: Fri, 23 Nov 2007 20:11:58 +0000 (-0500) Subject: Linux 2.0.36pre8 X-Git-Tag: 2.0.36pre8 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=be7aede9ae21ceeca198e30f82bf653c0e2aeebd;p=history.git Linux 2.0.36pre8 Bug Fixes Large Memory Linux 2.0.36 uses the newer bios calls to automatically size memory above 64Mbytes, where supported by the BIOS. Readv/Writev Processes issuing a readv or writev to a device that did not have the relevant read/write operation could cause an Oops and potentially a crash. UDMA Drives Report Bad CRC (cable errors) as a cable error. Handling of such errors was correct. pipe syscall error The pipe call could return ENFILE not -1 and errno= -ENFILE. Fixed. AIC7xxx The 2.0.36 kernel contains the 5.0.20 release of the AIC7xxx driver. This should cure most of the remaining problems with the older chipsets. Users with the latest AIC7xxx devices will have to wait for the next driver version to become available or try the beta test driver. Procfs permissions fix A process with root file rights can now read all /proc files. Daylight Savings in SMB The SMB file system honours daylight savings time. EATA SCSI/Ultrastor 14f/34f Reverse scan order support and configurable extended geometry. Increased the busy timeout. Build fixes Use relative paths for sound, remove trampoline.hex on a make clean, support the newer versioned symbols as part of a multi object file module. Oops handling A small fencepost error in Oops handling on syscall return has been cured. TLan 1.0 The Thunderlan driver has been updated to the 1.0 release. Delay loops The delay loop code has been modified to eliminate most of the remaining cache/branch prediction and other variants to its performance. 5.25" floppy An incorrect floppy table entry has been altered, and a potential crash on unload fixed. Iomega ZIP driver Handle 23.D firmware funnies. Cyclades Serial Upgraded driver from vendor, with assorted bugs fixed. Printer Driver The correction in the printer handling upset the Epson Stylus 800. The driver know has a LPSTRICT option that can be set for printers that need absolute strict NBUSY handling. Beeper gets stuck The case where the beeper decides to beep forever has been cured. 3c509 ethernet Upgraded to v1.16. Fixes ID port clash with sound cards, waiting for discard messages and recovers faster from transmit errors. 3c59x driver Updated 3c59x ethernet driver. This should cure the skb_push panics some people saw with 3c59x/3c90x drivers under load. Lance driver Module unload bugs in the lance driver have been fixed. Plip driver Messages without severity levels now have appropriate levels. AHA1542 Allow the use of DMA 0 on newer motherboards. SHM swap off A case where the machine might crash when turning swapping off has been fixed. MMAP security Linux did not allow a writable mmap of an append only file. It did however allow a readonly mmap of such a file then an mprotect. Fixed. NAKAMICH MJ-5.16S This SCSI device has been added to the blacklist. Single lun blacklisting A bug in the single lun blacklisting has been fixed. SCSI CAM division by zero A corrupt geometry could cause the kernel to divide by zero and crash. Sound blaster Don't report a DMA channel 0 for the MPU Sequencer If there are no synths or midi devices do not lock the sequencer busy forever. Autofs Fix a small glitch in the directory hash. ISOfs Fix a fencepost error in the iso fs size checks. Vfat fs Disallow periods at the end of names. NFS file system Support FIFO's over NFS. Handle kill of nfsiod for module unload. NFS root IFF_MULTICAST could be incorrectly not set. Non modular soundmodem/baycom These devices only worked as modules. They now work compiled in. Memory leak in networking A very obscure leak in the networking code has been fixed. TCP select TCP select for urgent data now has correct semantics. Previously it could do the wrong thing. TCP SIGIO SIGIO on an incoming connection is now correctly issued on the completion of the three way handshake. Enhancements ISDN The Isdn4linux layer is signifcantly upgraded. The new driver set adds support for the Teles 16.3c, Teles PCI, Teles S0Box, Creatix S0Box, Compaq ISDN S0 ISA, ELSA Quickstep 1000PCI, Elsa Quickstep 3000, Elsa Quickstep 3000PCI, Eicon.Diehl Diva 2.0 ISA/PCI (not Pro), Eicon.Diehl Diva Piccola, AsusCom ISDNLink 128K, Dynalink IS64PH, HFC-2BS0 based cards, Sedlbauer Speed Card(Speed win, teledat 100), Sedlbauer Speed Star PCMCIA, USR Sportster Internal TA, ITH MIC 16 ISA, Traverse NETjet PCI, Niccy PnP/PCI Shaper The shaper device provides a simple traffic limiting driver for Linux 2.0.x. For full traffic shaping watch for Linux 2.2 coming soon.. Tulip The tulip driver has been upgraded to 0.89H which should also support the clone PNIC and MXIC tulip devices. Extended CPUID/Chip identification The Cyrix/AMD extended CPUID mode is supported. Cyrix processors are identified even when CPUID is not available. The Intel Celeron Mendicino is recognized. K6's with the random oops bug are normally now detected. The K6 cpu deadlock problem isn't detected as we know no way to check for it except to try it. Multi-Tech driver Driver for multi-tech 4/8 port modem and serial cards.(Experimental). EtherExpress The Compaq LTE should now be recognized (experimental) Intel 440GX The 440GX chipset is known to the PCI data tables. Nvidia NVidia/SGS Thomson is known to the PCI data tables. SCSI medium changers These are no long reported as unknown device types. ROSE networking The ROSE network layer has been updated. Other Bigger system call table To support add ons that use syscalls in the new range. Hooks for dumping Kernel hooks for optional threaded core dump module. --- diff --git a/Documentation/Changes b/Documentation/Changes index efb08999a284..d2cde64a9d70 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -17,10 +17,6 @@ Boldt's (boldt@math.ucsb.edu) Configure.help file, among other sources, and was originally written and maintained by Alessandro Sigala (ssigala@globalnet.it). - There is now a web page based on this material, thanks to John -Taylor. Check out http://www.cviog.uga.edu/LinuxBleed.html if you -prefer a HTML-ized shopping list. - Para aquellos que prefieran una version en castellano de este documento, consultad la traduccion de Alfredo Sanjuan en http://slug.ctv.es/~alfredo/Cambios.html (Spanish translation). diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 8d3a79af8f6f..e836ee8c7676 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -1194,22 +1194,6 @@ CONFIG_IP_MASQUERADE_IPAUTOFW and other information, is available at ftp://ftp.netis.com/pub/members/rlynch/. -IP: ipportfw masquerade and virtual server support -CONFIG_IP_MASQUERADE_IPPFVS - ippfvs is port forwarding & virtual server program in Linux kernel - by Wensong Zhang, based on IP masquerading and Steven Clarke's - port forwarding codes. It can dynamically forward a connection on - given ports from outside to one server in a cluster of servers - inside a firewall, the round-robin secheduling or weighted - round-robin scheduling algorithm is used to choose which server - the connection is redirected to. This function can be used to build - a virtual internet server on a cluster of servers, such as scalable - web server. - For information and source of ippfvsadm administration program, - please visit the following URL: - http://proxy.iinchina.net/~wensong/ippfvs/ - If you want this, say Y. - IP: ICMP masquerading CONFIG_IP_MASQUERADE_ICMP The basic masquerade code described for CONFIG_IP_MASQUERADE only diff --git a/Documentation/ippfvsadm.c b/Documentation/ippfvsadm.c deleted file mode 100644 index 5a90c4753317..000000000000 --- a/Documentation/ippfvsadm.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - - * ippfvsadm - Port Fowarding & Virtual Server ADMinistration program v1.0 - * - * Copyright (c) 1998 Wensong Zhang - * All rights reserved. - * - * Author: Wensong Zhang - * - * This program is derived from Steven Clarke's ipportfw program. - * - * portfw - Port Forwarding Table Editing v1.1 - * - * Copyright (c) 1997 Steven Clarke - * All rights reserved. - * - * Author: Steven Clarke - * - * Keble College - * Oxford - * OX1 3PG - * - * WWW: http://www.monmouth.demon.co.uk/ - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define IP_PORTFW_NONE 0 -#define IP_PORTFW_LIST 10000 -#define DEFAULT_WEIGHT 1 -#define IPPROTO_NONE 65535 - -long string_to_number (char *str, int min, int max); -int parse_addressport (char *name, __u32 * raddr, __u16 * rport); -int do_setsockopt (int cmd, struct ip_portfw_edits *data, int length); -void exit_error (int status, char *msg); -void exit_display_help (void); -void list_forwarding (void); - -char *program; - -int -main (int argc, char *argv[]) -{ - int c; - int command = IP_PORTFW_NONE; - struct ip_portfw_edits pfw; - - pfw.protocol = IPPROTO_NONE; - pfw.raddr = 0; - pfw.rport = 0; - pfw.laddr = 0; - pfw.lport = 0; - pfw.weight = 0; - - program = argv[0]; - - while ((c = getopt (argc, argv, "ADCLt:u:R:w:h")) != -1) - switch (c) - { - case 'A': - if (command != IP_PORTFW_NONE) - exit_error (2, "multiple commands specified"); - command = IP_PORTFW_ADD; - break; - case 'D': - if (command != IP_PORTFW_NONE) - exit_error (2, "multiple commands specified"); - command = IP_PORTFW_DEL; - break; - case 'C': - if (command != IP_PORTFW_NONE) - exit_error (2, "multiple commands specified"); - command = IP_PORTFW_FLUSH; - break; - case 'L': - if (command != IP_PORTFW_NONE) - exit_error (2, "multiple commands specified"); - command = IP_PORTFW_LIST; - break; - - case 't': - case 'u': - if (pfw.protocol != IPPROTO_NONE) - exit_error (2, "multiple protocols specified"); - pfw.protocol = (c == 't' ? IPPROTO_TCP : IPPROTO_UDP); - if (parse_addressport (optarg, &pfw.laddr, &pfw.lport) == -1) - exit_error (2, "illegal virtual server address:port specified"); - break; - case 'R': - if (pfw.raddr != 0 || pfw.rport != 0) - exit_error (2, "multiple destinations specified"); - if (parse_addressport (optarg, &pfw.raddr, &pfw.rport) == -1) - exit_error (2, "illegal destination specified"); - break; - case 'w': - if (pfw.weight != 0) - exit_error (2, "multiple server weights specified"); - pfw.weight = string_to_number (optarg, SERVER_WEIGHT_MIN, SERVER_WEIGHT_MAX); - if (pfw.weight == -1) - exit_error (2, "illegal weight specified"); - break; - case 'h': - case '?': - default: - exit_display_help (); - } - - if (pfw.weight == 0) - pfw.weight = DEFAULT_WEIGHT; - - if (optind < argc) - exit_error (2, "unknown arguments found on commandline"); - - if (command == IP_PORTFW_NONE) - exit_display_help (); - - else if (command == IP_PORTFW_ADD && - (pfw.protocol == IPPROTO_NONE || pfw.lport == 0 || - pfw.rport == 0 || pfw.raddr == 0)) - exit_error (2, "insufficient options specified"); - - else if (command == IP_PORTFW_DEL && - (pfw.protocol == IPPROTO_NONE || pfw.lport == 0)) - exit_error (2, "insufficient options specified"); - - else if ((command == IP_PORTFW_FLUSH || command == IP_PORTFW_LIST) && - (pfw.protocol != IPPROTO_NONE || pfw.lport != 0 || - pfw.rport != 0 || pfw.raddr != 0)) - exit_error (2, "incompatible options specified"); - - if (command == IP_PORTFW_LIST) - list_forwarding (); - else - exit (do_setsockopt (command, &pfw, sizeof (pfw))); -} - - -long -string_to_number (char *str, int min, int max) -{ - char *end; - long number; - - number = strtol (str, &end, 10); - if (*end == '\0' && end != str) - { - if (min <= number && number <= max) - return number; - else - return -1; - } - else - return -1; -} - - -int -parse_addressport (char *name, __u32 * raddr, __u16 * rport) -{ - char buf[23]; /* xxx.xxx.xxx.xxx:ppppp\0 */ - char *p, *q; - int onebyte, i; - long l; - - strncpy (buf, name, sizeof (buf) - 1); - if ((p = strchr (buf, ':')) == NULL) - return -1; - - *p = '\0'; - if ((l = string_to_number (p + 1, IP_PORTFW_PORT_MIN, IP_PORTFW_PORT_MAX)) == -1) - return -1; - else - *rport = l; - - p = buf; - *raddr = 0; - for (i = 0; i < 3; i++) - { - if ((q = strchr (p, '.')) == NULL) - return -1; - else - { - *q = '\0'; - if ((onebyte = string_to_number (p, 0, 255)) == -1) - return -1; - else - *raddr = (*raddr << 8) + onebyte; - } - p = q + 1; - } - - /* we've checked 3 bytes, now we check the last one */ - if ((onebyte = string_to_number (p, 0, 255)) == -1) - return -1; - else - *raddr = (*raddr << 8) + onebyte; - - return 0; -} - - -int -do_setsockopt (int cmd, struct ip_portfw_edits *data, int length) -{ - static int sockfd = -1; - int ret; - - if (sockfd == -1) - { - if ((sockfd = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) == -1) - { - perror ("ippfvsadm: socket creation failed"); - exit (1); - } - } - - ret = setsockopt (sockfd, IPPROTO_IP, cmd, (char *) data, length); - if (ret) - perror ("ippfvsadm: setsockopt failed"); - - return ret; -} - - -void -exit_error (int status, char *msg) -{ - fprintf (stderr, "%s: %s\n", program, msg); - exit (status); -} - -void -list_forwarding (void) -{ - char buffer[256]; - - FILE *handle; - handle = fopen ("/proc/net/ip_portfw", "r"); - if (!handle) - { - printf ("Could not open /proc/net/ip_portfw\n"); - printf ("Are you sure you have Port Forwarding & Virtual Server support installed?\n"); - exit (1); - } - - while (!feof (handle)) - if (fgets (buffer, 256, handle)) - printf ("%s", buffer); - fclose (handle); - -} - -void -exit_display_help (void) -{ - printf ("%s v1.0 1998/5/26\n\n" - "Usage: %s -A -[t|u] l.l.l.l:lport -R a.a.a.a:rport [-w weight]\n" - " %s -D -[t|u] l.l.l.l:lport -R a.a.a.a:rport\n" - " %s -C\n" - " %s -L\n\n" - "Commands:\n" - " -A To add a real server\n" - " -D To delete a real server\n" - " -C To clear the table\n" - " -L To list the table\n\n" - "Options:\n" - " t means TCP protocol, and u indicates UDP protocol.\n" - " l.l.l.l:lport are the IP address and port of the virtual server.\n" - " a.a.a.a:rport are the IP address and port of the real server.\n" - " weight is a value to indicate the processing capacity of a real server.\n", - program, program, program, program, program); - - exit (0); -} diff --git a/Documentation/isdn/README.TimRu.De b/Documentation/isdn/README.TimRu.De deleted file mode 100644 index e3f86ace2cca..000000000000 --- a/Documentation/isdn/README.TimRu.De +++ /dev/null @@ -1,296 +0,0 @@ ---( Version: 11.10.1997 )-- - -TimRu-Erweiterungen: -==================== - -1. erfolglose Anwahlversuche per ICMP zurueckmelden ---------------------------------------------------- - -isdnctrl dialtimeout - name: Name des Interfaces - timeout: -1: kein Waehl-Timeout - 0: jede Telefonnummer dialmax-mal probieren - >0: Zeitraum in Sekunden, in dem die Anwahl versucht wird - - isdnctrl dialtimeout bewirkt, dass die Anwahl der Gegenstelle im Fehler- - fall nicht unbegrenzt versucht wird, sondern entweder nach einer bestimmten - Anzahl von Versuchen oder nach einem bestimmten Zeitraum abgebrochen wird - und alle ausstehenden Pakete fuer den durch isdnctrl dialwait bestimmten - Zeitraum mit ICMP_NET_UNREACHABLE beantwortet werden. - - -isdnctrl dialwait - name: Name des Interfaces - seconds: 0: keine Waehl-Unterdrueckung im Fehlerfall - >0: Zeit in Sekunden, in der nach einem erfolglosen Anwahl- - versuch Pakete mit ICMP_NET_UNREACHABLE beantwortet werden - - -1.1 einzelne Interfaces stoppen / starten ------------------------------------------ - -isdnctrl status - name: Name des Interfaces - status: on: Interface einschalten - off: Interface ausschalten - - Dieser Befehl wirkt wie 'isdnctrl system on/off' auf Interface-Ebene. - - -2. bessere Kontrolle ueber Aufbau und Hangup einer Verbindung -------------------------------------------------------------- - -isdnctrl bringup -isdnctrl keepup in -isdnctrl keepup out -isdnctrl keepup both - cmd: addrule: Regel am Ende der Regelliste anfuegen - insrule: Regel am Anfang der Regelliste einfuegen - delrule: Regel loeschen - default: Was tun, wenn keine Regel passt? - showrules: alle Regeln anzeigen - flushrules: alle Regeln einer Art loeschen (bringup, ...) - flushallrules: alle Regeln loeschen - - name: Name des Interfaces - seconds: Mindester Hangup-Timeout ab jetzt - rule: Regel, auf die ein Paket passen muss, damit die Verbindung - aufgebaut oder der Hangup-Timeout verlaengert wird - - - Eine passende Bringup-Regel erlaubt den Aufbau der Verbindung, - wenn ihr Timeout > 0 ist. Eine Bringup-Regel mit einen Timeout == 0 - verhindert einen Verbindungsaufbau. Dieser Timeout muss eigentlich nur - so gross sein, dass die Verbindung zum Gegenrechner erfolgreich - zustande kommt, da das ausloesende Datenpaket danach durch die - Keepup-Logik 'geht' und der Hangup-Timeout erneut berechnet wird. - - Eine passende Keepup-Regel verlaengert den Hangup-Timeout, wobei - nach eingehenden und ausgehenden Paketen unterschieden werden kann. - - Die Kontrolle eines Paketes stoppt bei der ersten passenden Regel, falls - keine Regel anwendbar ist, gilt die Default-Regel. - - Die Regeln haben folgenden Aufbau: - ip/icmp / / - ip/tcp / / - ip/udp / / - ip/* / / - ip/any / / - - ipx/* - ipx/any - - ppp/ipcp - ppp/ipxcp - ppp/ccp - ppp/lcp - ppp/chap - ppp/pap - ppp/lqr - ppp/* - ppp/any - - */* - any - - - src: Absender-Adresse des Paketes als Nummer oder Name - dst: Empfaenger-Adresse des Paketes als Nummer oder Name - mask: Subnet-Maske als Anzahl Bits oder als Maske - type: ICMP-Message-Type als Nummer - port: Portnummer als Nummer oder Name - - - Wildcards ('*', 'any') sind ueberall erlaubt. - - Fuer und gilt: - : Host-Adresse als Nummer oder Name, - Subnet-Mask /32 - /: Host-Adresse als Nummer oder Name, - Subnet-Mask als Anzahl Bits oder Maske - : Netzwerk-Adresse als Nummer oder Name, - Subnet-Mask /32 - /: Host-Adresse als Nummer oder Name, - Subnet-Mask als Anzahl Bits oder Maske - 0.0.0.0/0 - 0/0 - * - any: Wildcard, passt auf jede Adresse. - - Fuer gilt: - -: alle Ports von bis , numerische Angabe - -: alle Ports von bis 65535, numerische Angabe - -: alle Ports von 0 bis , numerische Angabe - : ein Port als Nummer oder Name - -, * - oder any: alle Ports - - Beginnt die Regel mit einem '!' oder mit 'not', so dreht sich ihre Aussage um: - falls sie NICHT passt, wird die Verbindung aufgebaut, bzw. der - Hangup-Timeout verlaengert. - - - Default-Regeln werden folgendermassen angegeben: - - isdnctrl default bringup - name: Name des Interfaces - timeout: 0: Verbindung wird nicht aufgebaut - >0: Verbindung wird aufgebaut, anfaenglicher Timeout - ist . - - isdnctrl default keepup in - isdnctrl default keepup out - isdnctrl default keepup both - name: Name des Interfaces - seconds: Mindester Hangup-Timeout - - -3. Budget-Erweiterungen ------------------------ - -Diese Erweiterung erlaubt es, bestimmte 'Verbrauchswerte' pro -Zeitraum zu limitieren. Falls ein Budget aufgebraucht ist, findet -keine Anwahl mehr statt und eine bestehende Verbindung wird unterbrochen. -Sobald wieder alle Budgets verfuegbar sind, werden wieder Verbindungen -zugelassen. -Die Gebuehrenimpuls-Zaehlung setzt momentan auf der Uebertragung der -CINF-Pakete, also der Gebuehreninformation waehrend der Verbindung auf. -Unmittelbar nach Aufbau der Verbindung wird der erste Gebuehrenimpuls -'angenommen'. -Fuer ISDN-Anschluesse, bei denen die Gebuehren erst am Ende der Ver- -bindung uebertragen werden, faellt uns bestimmt auch noch was ein ;-). - -isdnctrl budget - setzt die Werte eines bestimmten Budgets. Ein aufgebrauchtes - Budget wird unmittelbar wieder aktiviert. - - budget-type: dial: Anzahl der Anwahlversuche (erfolgreich oder - erfolglos) pro Periode - charge: Anzahl der Gebuehreneinheiten pro Periode - online: Online-Zeit pro Periode - - amount: Hoehe des Budgets. Bei 'dial' oder 'charge' - ist das die Anzahl Anwahlen oder Einheiten, bei 'online' - eine Zeitangabe (s.u.) - - period: Dauer der Periode in folgendem Format ( steht fuer eine - natuerliche Zahl): - - - s - sec, Sekunden - - m - min, Minuten - - h - hour, Stunden - - d - day, Tage - - w - week, Wochen (a 7 Tage) - - M - month, Monate (a 30 Tage) - - y - year, Jahre (a 365 Tage) - - Diese Angaben koennen miteinander kombiniert werden, z.B.: - - 2h30m15 - 2hour,30min,15sec - 1M2week,1day,8h - - -isdnctrl budget off - schaltet die Kontrolle des entsprechenden Budgets aus - -isdnctrl budget showbudgets - zeigt die momentaten Budgets an - -isdnctrl budget savebudgets - gibt die momentaten Budgets in einen Format aus, das vom Befehl 'restore- - budgets' wieder eingelesen kann - -isdnctrl budget restorebudgets ... - setzt die Budgets wieder auf die vorher mit 'savebudgets' ausgegebenen - Werte. Damit koennen Budgets auch ueber den Reboot der Maschine hinaus - Gueltigkeit haben. - - -Hier ein Beispiel fuer die TimRu-Erweiterung: - - # Alle Regeln loeschen - isdnctrl flushallrules ippp0 - - # Default: jeder Datenverkehr setzt den Hangup-Timeout auf 60 Sek. - isdnctrl default ippp0 keepup both 60 - - # FTP und Telnet erhoehen den Timeout auf 5 Minuten - isdnctrl addrule ippp0 keepup both 300 ip/tcp 0/0 20-23 0/0 - - - # Anzeige der Regeln: - isdnctrl showrules ippp0 - - # ... erzeugt folgende Ausgabe: - -Timeout rules for interface ippp0: -Default bringup policy: true -Default huptimeout for incoming packets: 60 sec. -Default huptimeout for outgoing packets: 60 sec. - -Current huptimeout: 60 sec. -Time until hangup: 45 sec. - -Keepup-rules for incoming ip-packets: -1-1-0 keepup_in 300 ip/tcp 0/0 20-23 0/0 * - -Keepup-rules for outgoing ip-packets: -2-1-0 keepup_out 300 ip/tcp 0/0 * 0/0 20-23 - - -Hier ein Beispiel fuer die Budget-Erweiterung: - - # Hoechstens 60 Anwahlversuche pro Stunde - isdnctrl budget ippp0 dial 60 1h - - # Hoechstens 3000 Einheiten pro Monat - isdnctrl budget ippp0 charge 3000 1M - - # Hoechstens 8 Stunden online pro Tag - isdnctrl budget ippp0 online 8h 1d - - # Anzeige der Budgets: - isdnctrl showbudgets ippp0 - - # ... erzeugt nach kurzer Zeit folgende Ausgabe: - - -Budgets for interface ippp0: - -TYPE AMOUNT PERIOD USED SINCE -dial 60 1h 1 01.07.1997, 17:43:40 -charge 3000 1M 2 01.07.1997, 17:43:49 -online 8h 1d 2m26s 01.07.1997, 17:43:57 - - -Zum Nachfuehren der Budgets ueber einen laengeren Zeitraum koennte man -folgende Methode verwenden: - -beim Herunterfahren oder per 'cron' jede Minute: - - INTERFACES="ippp0 ippp1 ippp2" - for i in $INTERFACES; do - isdnctrl savebudgets $i > /var/isdn/saved-budgets/$i - done - - -und dann beim Neustart: - - for f in /var/isdn/saved-budgets/*; do - isdnctrl restorebudgets ${f##*/} `cat $f` - done diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index fe9b129b85de..bcebba70ad63 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -372,7 +372,7 @@ static struct cpu_model_info intel_models[] = { NULL, NULL, NULL, NULL }}, { 6, { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", - NULL, "Pentium II (Deschutes)", NULL, NULL, NULL, NULL, NULL, NULL, + NULL, "Pentium II (Deschutes)", "Celeron (Mendocino)", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }}, }; @@ -381,11 +381,21 @@ static const char * Intelmodel(void) const char *p = "386 SX/DX"; /* default to a 386 */ int i; + /* + * Old 486SX has no CPU ID. Set the model to 2 for this + * case. + */ + + if( x86==4 && x86_model == 0 && hard_math == 0) + x86_model = 2; + for (i=0; icard].base_addr + (cy_chip_offset[channel>>2] <flags & ASYNC_INITIALIZED) { - /* Waiting for on-board buffers to be empty before closing - the port */ - cy_wait_until_sent(tty, info->timeout); - } + /* Stop accepting input */ + channel &= 0x03; + cy_writeb((ulong)base_addr+(CyCAR<flags & ASYNC_INITIALIZED) { + /* Waiting for on-board buffers to be empty before closing + the port */ + cy_wait_until_sent(tty, info->timeout); + } } else { #ifdef Z_WAKE /* Waiting for on-board buffers to be empty before closing the port */ @@ -4699,7 +4706,7 @@ cy_detect_pci(void)) unsigned long pci_intr_ctrl; unsigned char cy_pci_irq; uclong cy_pci_addr0, cy_pci_addr1, cy_pci_addr2; - unsigned short i,j,cy_pci_nchan; + unsigned short i,j,cy_pci_nchan, plx_ver; unsigned short device_id,dev_index = 0,board_index = 0; uclong mailbox; uclong Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0; @@ -4823,11 +4830,27 @@ cy_detect_pci(void)) cy_card[j].num_chips = cy_pci_nchan/4; IRQ_cards[cy_pci_irq] = &cy_card[j]; - /* enable interrupts in the PCI interface */ - outw(inw(cy_pci_addr1+0x68)|0x0900,cy_pci_addr1+0x68); - pci_intr_ctrl = (unsigned long) - (inw(cy_pci_addr1+0x68) + /* enable interrupts in the PCI interface */ + plx_ver = cy_readb(cy_pci_addr2 + CyPLX_VER) & 0x0f; + switch (plx_ver) { + case PLX_9050: + + outw(inw(cy_pci_addr1+0x4c)|0x0040,cy_pci_addr1+0x4c); + pci_intr_ctrl = (unsigned long) + (inw(cy_pci_addr1+0x4c) + | inw(cy_pci_addr1+0x4e)<<16); + break; + + case PLX_9060: + case PLX_9080: + default: /* Old boards, use PLX_9060 */ + + outw(inw(cy_pci_addr1+0x68)|0x0900,cy_pci_addr1+0x68); + pci_intr_ctrl = (unsigned long) + (inw(cy_pci_addr1+0x68) | inw(cy_pci_addr1+0x6a)<<16); + break; + } /* print message */ printk("Cyclom-Y/PCI #%d: 0x%lx-0x%lx, IRQ%d, ", diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c new file mode 100644 index 000000000000..de2383c99b9a --- /dev/null +++ b/drivers/char/isicom.c @@ -0,0 +1,1928 @@ +/* + * 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. + * + * Original driver code supplied by Multi-Tech + * + * Changes + * 1/9/98 alan@redhat.com Merge to 2.0.x kernel tree + * Obtain and use official major/minors + * Loader switched to a misc device + * (fixed range check bug as a side effect) + * Printk clean up + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "isicom.h" + +static int isicom_refcount = 0; +static int prev_card = 3; /* start servicing isi_card[0] */ +static struct isi_board * irq_to_board[16] = { NULL, }; +static struct tty_driver isicom_normal, isicom_callout; +static struct tty_struct * isicom_table[PORT_COUNT] = { NULL, }; +static struct termios * isicom_termios[PORT_COUNT] = { NULL, }; +static struct termios * isicom_termios_locked[PORT_COUNT] = { NULL, }; + +static struct isi_board isi_card[BOARD_COUNT]; +static struct isi_port isi_ports[PORT_COUNT]; + +DECLARE_TASK_QUEUE(tq_isicom); + +static struct timer_list tx; +static char re_schedule = 1; +#ifdef ISICOM_DEBUG +unsigned long tx_count = 0; +#endif + +static int ISILoad_open(struct inode *inode, struct file *filp); +static void ISILoad_release(struct inode *inode, struct file *filp); +static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); + +static void isicom_tx(unsigned long _data); +static void isicom_start(struct tty_struct * tty); + +static unsigned char * tmp_buf = 0; +static struct semaphore tmp_buf_sem = MUTEX; + +/* baud index mappings from linux defns to isi */ + +static char linuxb_to_isib[] = { + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17, + 18, 19 +}; + +/* + * Firmware loader driver specific routines + * + */ + +static struct file_operations ISILoad_fops = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + ISILoad_ioctl, + NULL, /* mmap */ + ISILoad_open, + ISILoad_release, + NULL, /* fsync */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ +}; + +struct miscdevice isiloader_device = { + ISILOAD_MISC_MINOR, "isictl", &ISILoad_fops +}; + + +extern inline int WaitTillCardIsFree(unsigned short base) +{ + unsigned long count=0; + while( (!(inw(base+0xe) & 0x1)) && (count++ < 6000000)); + if (inw(base+0xe)&0x1) + return 0; + else + return 1; +} + +static int ISILoad_open(struct inode *inode, struct file *filp) +{ +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISILoad:Card%d Opened!!!\n",MINOR(inode->i_rdev)+1); +#endif + return 0; +} + +static void ISILoad_release(struct inode *inode, struct file *filp) +{ +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISILoad:Card%d Close(Release)d\n",MINOR(inode->i_rdev)+1); +#endif +} + +static int ISILoad_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + unsigned int card, i, j, signature, status; + unsigned short error, word_count, base; + bin_frame frame; + /* exec_record exec_rec; */ + + i=get_user((int *)arg); + if(i<0 || i >= BOARD_COUNT) + return -ENXIO; + + card=i; + base=isi_card[card].base; + + if(base==0) + return -ENXIO; + + switch(cmd) { + case MIOCTL_RESET_CARD: + if (!suser()) + return -EPERM; + error=verify_area(VERIFY_WRITE, (void *) arg, sizeof(int)); + if (error) + return error; + + printk(KERN_DEBUG "ISILoad:Resetting Card%d at 0x%x ",card+1,base); + + inw(base+0x8); + + for(i=jiffies+HZ/100;i>jiffies;); + + outw(0,base+0x8); /* Reset */ + + for(j=1;j<=3;j++) { + for(i=jiffies+HZ;i>jiffies;); + printk("."); + } + signature=(inw(base+0x4)) & 0xff; + + if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) { +#ifdef ISICOM_DEBUG + printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe)); +#endif + printk("\nISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); + return -EIO; + } + + switch(signature) { + case 0xa5: + case 0xbb: + case 0xdd: isi_card[card].port_count = 8; + isi_card[card].shift_count = 12; + break; + + case 0xcc: isi_card[card].port_count = 16; + isi_card[card].shift_count = 11; + break; + + default: printk("ISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base); +#ifdef ISICOM_DEBUG + printk("Sig=0x%x\n",signature); +#endif + return -EIO; + } + printk("-Done\n"); + put_user(signature,(unsigned int*)arg); + return 0; + + case MIOCTL_LOAD_FIRMWARE: + if (!suser()) + return -EPERM; + error=verify_area(VERIFY_READ, (void *) arg, sizeof(bin_frame)); + if (error) + return error; + + memcpy_fromfs(&frame, (void *) arg, sizeof(bin_frame)); + + if (WaitTillCardIsFree(base)) + return -EIO; + + outw(0xf0,base); /* start upload sequence */ + outw(0x00,base); + outw((frame.addr), base);/* lsb of adderess */ + + word_count=(frame.count >> 1) + frame.count % 2; + outw(word_count, base); + InterruptTheCard(base); + + for(i=0;i<=0x2f;i++); /* a wee bit of delay */ + + if (WaitTillCardIsFree(base)) + return -EIO; + + if ((status=inw(base+0x4))!=0) { + printk(KERN_WARNING "ISILoad:Card%d rejected load header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n", + card+1, frame.addr, frame.count, status); + return -EIO; + } + outsw(base, (void *) frame.bin_data, word_count); + + InterruptTheCard(base); + + for(i=0;i<=0x0f;i++); /* another wee bit of delay */ + + if (WaitTillCardIsFree(base)) + return -EIO; + + if ((status=inw(base+0x4))!=0) { + printk(KERN_ERR "ISILoad:Card%d got out of sync.Card Status:0x%x\n",card+1, status); + return -EIO; + } + return 0; + + case MIOCTL_READ_FIRMWARE: + if (!suser()) + return -EPERM; + error=verify_area(VERIFY_READ, (void *) arg, sizeof(bin_header)); + if (error) + return error; + + memcpy_fromfs(&frame, (void *) arg, sizeof(bin_header)); + + if (WaitTillCardIsFree(base)) + return -EIO; + + outw(0xf1,base); /* start download sequence */ + outw(0x00,base); + outw((frame.addr), base);/* lsb of adderess */ + + word_count=(frame.count >> 1) + frame.count % 2; + outw(word_count+1, base); + InterruptTheCard(base); + + for(i=0;i<=0xf;i++); /* a wee bit of delay */ + + if (WaitTillCardIsFree(base)) + return -EIO; + + if ((status=inw(base+0x4))!=0) { + printk(KERN_WARNING "ISILoad:Card%d rejected verify header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n", + card+1, frame.addr, frame.count, status); + return -EIO; + } + + inw(base); + insw(base, frame.bin_data, word_count); + InterruptTheCard(base); + + for(i=0;i<=0x0f;i++); /* another wee bit of delay */ + + if (WaitTillCardIsFree(base)) + return -EIO; + + if ((status=inw(base+0x4))!=0) { + printk(KERN_ERR "ISILoad:Card%d verify got out of sync.Card Status:0x%x\n",card+1, status); + return -EIO; + } + error=verify_area(VERIFY_WRITE, (void *) arg, sizeof(bin_frame)); + if (error) + return error; + memcpy_tofs((void *) arg, &frame, sizeof(bin_frame)); + + return 0; + + case MIOCTL_XFER_CTRL: + if (!suser()) + return -EPERM; + if (WaitTillCardIsFree(base)) + return -EIO; + + outw(0xf2, base); + outw(0x800, base); + outw(0x0, base); + outw(0x0, base); + InterruptTheCard(base); + + isi_card[card].status |= FIRMWARE_LOADED; + return 0; + + default: +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISILoad: Received Ioctl cmd 0x%x.\n", cmd); +#endif + return -ENOIOCTLCMD; + + } + +} + + +/* + * ISICOM Driver specific routines ... + * + */ + +static inline int isicom_paranoia_check(struct isi_port const * port, kdev_t dev, + const char * routine) +{ +#ifdef ISICOM_DEBUG + static const char * badmagic = + KERN_WARNING "ISICOM: Warning: bad isicom magic for dev %s in %s.\n"; + static const char * badport = + KERN_WARNING "ISICOM: Warning: NULL isicom port for dev %s in %s.\n"; + if (!port) { + printk(badport, kdevname(dev), routine); + return 1; + } + if (port->magic != ISICOM_MAGIC) { + printk(badmagic, kdevname(dev), routine); + return 1; + } +#endif + return 0; +} + +extern inline void schedule_bh(struct isi_port * port) +{ + queue_task_irq_off(&port->bh_tqueue, &tq_isicom); + mark_bh(ISICOM_BH); +} + +/* Transmitter */ + +static void isicom_tx(unsigned long _data) +{ + short count = (BOARD_COUNT-1), card, base; + short txcount, wait, wrd; + struct isi_port * port; + struct tty_struct * tty; + unsigned long flags; + +#ifdef ISICOM_DEBUG + ++tx_count; +#endif + + /* find next active board */ + card = (prev_card + 1) % 4; + while(count-- > 0) { + if (isi_card[card].status & BOARD_ACTIVE) + break; + card = (card + 1) % 4; + } + if (!(isi_card[card].status & BOARD_ACTIVE)) + goto sched_again; + + prev_card = card; + + count = isi_card[card].port_count; + port = isi_card[card].ports; + base = isi_card[card].base; + for (;count > 0;count--, port++) { + /* port not active or tx disabled to force flow control */ + if (!(port->status & ISI_TXOK)) + continue; + + tty = port->tty; + save_flags(flags); cli(); + txcount = MIN(TX_SIZE, port->xmit_cnt); + if ((txcount <= 0) || tty->stopped || tty->hw_stopped) { + restore_flags(flags); + continue; + } + wait = 300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + restore_flags(flags); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_tx:Card(0x%x) found busy.\n", + card); +#endif + continue; + } + if (!(inw(base + 0x02) & (1 << port->channel))) { + restore_flags(flags); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_tx: cannot tx to 0x%x:%d.\n", + base, port->channel + 1); +#endif + continue; + } +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: txing %d bytes, port%d.\n", + txcount, port->channel+1); +#endif + outw((port->channel << isi_card[card].shift_count) | txcount + , base); + while (1) { + wrd = port->xmit_buf[port->xmit_tail++]; + port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1); + port->xmit_cnt--; + if (--txcount > 0) { + wrd |= (port->xmit_buf[port->xmit_tail++] << 8); + port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1); + port->xmit_cnt--; + outw(wrd, base); + if (--txcount <= 0) break; + } + else { + outw(wrd, base); + break; + } + } + InterruptTheCard(base); + if (port->xmit_cnt <= 0) + port->status &= ~ISI_TXOK; + if (port->xmit_cnt <= WAKEUP_CHARS) + schedule_bh(port); + restore_flags(flags); + } + + /* schedule another tx for hopefully in about 10ms */ +sched_again: + if (!re_schedule) + return; + init_timer(&tx); + tx.expires = jiffies + 1; + tx.data = 0; + tx.function = isicom_tx; + add_timer(&tx); + + return; +} + + /* Interrupt handlers */ +static void do_isicom_bh(void) +{ + run_task_queue(&tq_isicom); +} + + + +static void isicom_bottomhalf(void * data) +{ + struct isi_port * port = (struct isi_port *) data; + struct tty_struct * tty = port->tty; + + if (!tty) + return; + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); +} + +/* main interrupt handler routine */ +static void isicom_interrupt(int irq, void * dev_id, struct pt_regs * regs) +{ + struct isi_board * card; + struct isi_port * port; + struct tty_struct * tty; + unsigned short base, header, word_count, count; + unsigned char channel; + short byte_count; + + card = irq_to_board[irq]; + if (!card || !(card->status & FIRMWARE_LOADED)) { + printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq); + return; + } + base = card->base; + + inw(base); /* get the dummy word out */ + header = inw(base); + channel = (header & 0x7800) >> card->shift_count; + byte_count = header & 0xff; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM:Intr:(0x%x:%d).\n", base, channel+1); +#endif + if ((channel+1) > card->port_count) { + printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%x): %d(channel) > port_count.\n", + base, channel+1); + ClearInterrupt(base); + return; + } + port = card->ports + channel; + if (!(port->flags & ASYNC_INITIALIZED)) { + ClearInterrupt(base); + return; + } + + tty = port->tty; + + if (header & 0x8000) { /* Status Packet */ + header = inw(base); + switch(header & 0xff) { + case 0: /* Change in EIA signals */ + + if (port->flags & ASYNC_CHECK_CD) { + if (port->status & ISI_DCD) { + if (!(header & ISI_DCD)) { + /* Carrier has been lost */ +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: interrupt: DCD->low.\n"); +#endif + port->status &= ~ISI_DCD; + if (!((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_CALLOUT_NOHUP))) + queue_task_irq_off(&port->hangup_tq, + &tq_scheduler); + } + } + else { + if (header & ISI_DCD) { + /* Carrier has been detected */ +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: interrupt: DCD->high.\n"); +#endif + port->status |= ISI_DCD; + wake_up_interruptible(&port->open_wait); + } + } + } + else { + if (header & ISI_DCD) + port->status |= ISI_DCD; + else + port->status &= ~ISI_DCD; + } + + if (port->flags & ASYNC_CTS_FLOW) { + if (port->tty->hw_stopped) { + if (header & ISI_CTS) { + port->tty->hw_stopped = 0; + /* start tx ing */ + port->status |= (ISI_TXOK | ISI_CTS); + schedule_bh(port); + } + } + else { + if (!(header & ISI_CTS)) { + port->tty->hw_stopped = 1; + /* stop tx ing */ + port->status &= ~(ISI_TXOK | ISI_CTS); + } + } + } + else { + if (header & ISI_CTS) + port->status |= ISI_CTS; + else + port->status &= ~ISI_CTS; + } + + if (header & ISI_DSR) + port->status |= ISI_DSR; + else + port->status &= ~ISI_DSR; + + if (header & ISI_RI) + port->status |= ISI_RI; + else + port->status &= ~ISI_RI; + + break; + + case 1: /* Received Break !!! */ + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + break; + *tty->flip.flag_buf_ptr++ = TTY_BREAK; + /* dunno if this is right */ + *tty->flip.char_buf_ptr++ = 0; + tty->flip.count++; + if (port->flags & ASYNC_SAK) + do_SAK(tty); + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + break; + + case 2: /* Statistics */ + printk(KERN_DEBUG "ISICOM: isicom_interrupt: stats!!!.\n"); + break; + + default: + printk(KERN_WARNING "ISICOM: Intr: Unknown code in status packet.\n"); + break; + } + } + else { /* Data Packet */ + count = MIN(byte_count, (TTY_FLIPBUF_SIZE - tty->flip.count)); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: Intr: Can rx %d of %d bytes.\n", + count, byte_count); +#endif + word_count = count >> 1; + insw(base, tty->flip.char_buf_ptr, word_count); + tty->flip.char_buf_ptr += (word_count << 1); + byte_count -= (word_count << 1); + if (count % 2) { + *tty->flip.char_buf_ptr++ = (char)(inw(base) & 0xff); + byte_count -= 2; + } + memset(tty->flip.flag_buf_ptr, 0, count); + tty->flip.flag_buf_ptr += count; + tty->flip.count += count; + + if (byte_count > 0) + printk(KERN_DEBUG "ISICOM: Intr(0x%x:%d): Flip buffer overflow! dropping bytes...\n", + base, channel+1); + while(byte_count > 0) { /* drain out unread xtra data */ + inw(base); + byte_count -= 2; + } + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + } + ClearInterrupt(base); + return; +} + + /* called with interrupts disabled */ +static void isicom_config_port(struct isi_port * port) +{ + struct isi_board * card = port->card; + struct tty_struct * tty; + unsigned long baud; + unsigned short channel_setup, wait, base = card->base; + unsigned short channel = port->channel, shift_count = card->shift_count; + unsigned char flow_ctrl; + + if (!(tty = port->tty) || !tty->termios) + return; + baud = C_BAUD(tty); + if (baud & CBAUDEX) { + baud &= ~CBAUDEX; + + /* if CBAUDEX bit is on and the baud is set to either 50 or 75 + * then the card is programmed for 57.6Kbps or 115Kbps + * respectively. + */ + + if (baud < 1 || baud > 2) + port->tty->termios->c_cflag &= ~CBAUDEX; + else + baud += 15; + } + if (baud == 15) { + + /* the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set + * by the set_serial_info ioctl ... this is done by + * the 'setserial' utility. + */ + + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + baud++; /* 57.6 Kbps */ + if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + baud +=2; /* 115 Kbps */ + } + if (linuxb_to_isib[baud] == -1) { + /* hang up */ + drop_dtr(port); + return; + } + else + raise_dtr(port); + + wait = 100; + while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); + if (!wait) { + printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at channel setup.\n"); + return; + } + outw(0x8000 | (channel << shift_count) |0x03, base); + outw(linuxb_to_isib[baud] << 8 | 0x03, base); + channel_setup = 0; + switch(C_CSIZE(tty)) { + case CS5: + channel_setup |= ISICOM_CS5; + break; + case CS6: + channel_setup |= ISICOM_CS6; + break; + case CS7: + channel_setup |= ISICOM_CS7; + break; + case CS8: + channel_setup |= ISICOM_CS8; + break; + } + + if (C_CSTOPB(tty)) + channel_setup |= ISICOM_2SB; + + if (C_PARENB(tty)) + channel_setup |= ISICOM_EVPAR; + if (C_PARODD(tty)) + channel_setup |= ISICOM_ODPAR; + outw(channel_setup, base); + InterruptTheCard(base); + + if (C_CLOCAL(tty)) + port->flags &= ~ASYNC_CHECK_CD; + else + port->flags |= ASYNC_CHECK_CD; + + /* flow control settings ...*/ + flow_ctrl = 0; + port->flags &= ~ASYNC_CTS_FLOW; + if (C_CRTSCTS(tty)) { + port->flags |= ASYNC_CTS_FLOW; + flow_ctrl |= ISICOM_CTSRTS; + } + if (I_IXON(tty)) + flow_ctrl |= ISICOM_RESPOND_XONXOFF; + if (I_IXOFF(tty)) + flow_ctrl |= ISICOM_INITIATE_XONXOFF; + + wait = 100; + while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); + if (!wait) { + printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at flow setup.\n"); + return; + } + outw(0x8000 | (channel << shift_count) |0x04, base); + outw(flow_ctrl << 8 | 0x05, base); + outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base); + InterruptTheCard(base); + + /* rx enabled -> enable port for rx on the card */ + if (C_CREAD(tty)) { + card->port_status |= (1 << channel); + outw(card->port_status, base + 0x02); + } + +} + +/* open et all */ + +extern inline void isicom_setup_board(struct isi_board * bp) +{ + int channel; + struct isi_port * port; + unsigned long flags; + + if (bp->status & BOARD_ACTIVE) + return; + port = bp->ports; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts start, port_count %d...\n", bp->port_count); +#endif + for(channel = 0; channel < bp->port_count; channel++, port++) { + save_flags(flags); cli(); + drop_dtr_rts(port); + restore_flags(flags); + } +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts stop...\n"); +#endif + + bp->status |= BOARD_ACTIVE; + MOD_INC_USE_COUNT; + return; +} + +static int isicom_setup_port(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned long flags; + + if (port->flags & ASYNC_INITIALIZED) + return 0; + if (!port->xmit_buf) { + unsigned long page; + + if (!(page = get_free_page(GFP_KERNEL))) + return -ENOMEM; + + if (port->xmit_buf) { + free_page(page); + return -ERESTARTSYS; + } + port->xmit_buf = (unsigned char *) page; + } + save_flags(flags); cli(); + if (port->tty) + clear_bit(TTY_IO_ERROR, &port->tty->flags); + if (port->count == 1) + card->count++; + + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + + /* discard any residual data */ + kill_queue(port, ISICOM_KILLTX | ISICOM_KILLRX); + + isicom_config_port(port); + port->flags |= ASYNC_INITIALIZED; + + restore_flags(flags); + + return 0; +} + +static int block_til_ready(struct tty_struct * tty, struct file * filp, struct isi_port * port) +{ + int do_clocal = 0, retval; + struct wait_queue wait = { current, NULL }; + + /* block if port is in the process of being closed */ + + if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready: close in progress.\n"); +#endif + interruptible_sleep_on(&port->close_wait); + if (port->flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; + } + + /* trying to open a callout device... check for constraints */ + + if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: bl_ti_rdy: callout open.\n"); +#endif + if (port->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_SESSION_LOCKOUT) && + (port->session != current->session)) + return -EBUSY; + + if ((port->flags & ASYNC_CALLOUT_ACTIVE) && + (port->flags & ASYNC_PGRP_LOCKOUT) && + (port->pgrp != current->pgrp)) + return -EBUSY; + port->flags |= ASYNC_CALLOUT_ACTIVE; + cli(); + raise_dtr_rts(port); + sti(); + return 0; + } + + /* if non-blocking mode is set ... */ + + if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready: non-block mode.\n"); +#endif + if (port->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + port->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + if (port->flags & ASYNC_CALLOUT_ACTIVE) { + if (port->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (C_CLOCAL(tty)) + do_clocal = 1; + } +#ifdef ISICOM_DEBUG + if (do_clocal) + printk(KERN_DEBUG "ISICOM: block_til_ready: CLOCAL set.\n"); +#endif + + /* block waiting for DCD to be asserted, and while + callout dev is busy */ + retval = 0; + add_wait_queue(&port->open_wait, &wait); + cli(); + if (!tty_hung_up_p(filp)) + port->count--; + sti(); + port->blocked_open++; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready: waiting for DCD...\n"); +#endif + while (1) { + cli(); + if (!(port->flags & ASYNC_CALLOUT_ACTIVE)) + raise_dtr_rts(port); + + sti(); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { + if (port->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready: tty_hung_up_p || not init.\n"); +#endif + break; + } + if (!(port->flags & ASYNC_CALLOUT_ACTIVE) && + !(port->flags & ASYNC_CLOSING) && + (do_clocal || (port->status & ISI_DCD))) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready: do_clocal || DCD.\n"); +#endif + break; + } + if (current->signal & ~current->blocked) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready: sig blocked.\n"); +#endif + retval = -ERESTARTSYS; + break; + } + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&port->open_wait, &wait); + if (!tty_hung_up_p(filp)) + port->count++; + port->blocked_open--; + if (retval) + return retval; + port->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +static int isicom_open(struct tty_struct * tty, struct file * filp) +{ + struct isi_port * port; + struct isi_board * card; + unsigned int line, board; + unsigned long flags; + int error; + +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: open start!!!.\n"); +#endif + line = MINOR(tty->device) - tty->driver.minor_start; + +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "line = %d.\n", line); +#endif + + if ((line < 0) || (line > (PORT_COUNT-1))) + return -ENODEV; + board = BOARD(line); + +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "board = %d.\n", board); +#endif + + card = &isi_card[board]; + if (!(card->status & FIRMWARE_LOADED)) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG"ISICOM: Firmware not loaded to card%d.\n", board); +#endif + return -ENODEV; + } + + /* open on higher 8 dev files on a 8 port card !!! */ + if (card->port_count == 8) + if (line > ((board * 16)+7)) { + printk(KERN_ERR "ISICOM: Opened >8 on a 8 port card.\n"); + return -ENODEV; + } + port = &isi_ports[line]; + if (isicom_paranoia_check(port, tty->device, "isicom_open")) + return -ENODEV; + +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_setup_board ...\n"); +#endif + isicom_setup_board(card); + + port->count++; + tty->driver_data = port; + port->tty = tty; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_setup_port ...\n"); +#endif + if ((error = isicom_setup_port(port))!=0) + return error; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: block_til_ready ...\n"); +#endif + if ((error = block_til_ready(tty, filp, port))!=0) + return error; + + if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = port->normal_termios; + else + *tty->termios = port->callout_termios; + save_flags(flags); cli(); + isicom_config_port(port); + restore_flags(flags); + } + + port->session = current->session; + port->pgrp = current->pgrp; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: open end!!!.\n"); +#endif + return 0; +} + +/* close et all */ + +extern inline void isicom_shutdown_board(struct isi_board * bp) +{ + int channel; + struct isi_port * port; + + if (!(bp->status & BOARD_ACTIVE)) + return; + bp->status &= ~BOARD_ACTIVE; + port = bp->ports; + for(channel = 0; channel < bp->port_count; channel++, port++) { + drop_dtr_rts(port); + } + MOD_DEC_USE_COUNT; +} + +static void isicom_shutdown_port(struct isi_port * port) +{ + struct isi_board * card = port->card; + struct tty_struct * tty; + + if (!(port->flags & ASYNC_INITIALIZED)) + return; + if (port->xmit_buf) { + free_page((unsigned long) port->xmit_buf); + port->xmit_buf = NULL; + } + if (!(tty = port->tty) || C_HUPCL(tty)) + /* drop dtr on this port */ + drop_dtr(port); + + /* any other port uninits */ + + if (tty) + set_bit(TTY_IO_ERROR, &tty->flags); + port->flags &= ~ASYNC_INITIALIZED; + + if (--card->count < 0) { + printk(KERN_DEBUG "ISICOM: isicom_shutdown_port: bad board(0x%x) count %d.\n", + card->base, card->count); + card->count = 0; + } + + /* last port was closed , shutdown that boad too */ + if (!card->count) + isicom_shutdown_board(card); +} + +static void isicom_close(struct tty_struct * tty, struct file * filp) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + struct isi_board * card = port->card; + unsigned long flags; + + if (!port) + return; + if (isicom_paranoia_check(port, tty->device, "isicom_close")) + return; + +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: Close start!!!.\n"); +#endif + + save_flags(flags); cli(); + if (tty_hung_up_p(filp)) { + restore_flags(flags); + return; + } + + if ((tty->count == 1) && (port->count != 1)) { + printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count" + "tty->count = 1 port count = %d.\n", + card->base, port->count); + port->count = 1; + } + if (--port->count < 0) { + printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count for" + "channel%d = %d", card->base, port->channel, + port->count); + port->count = 0; + } + + if (port->count) { + restore_flags(flags); + return; + } + port->flags |= ASYNC_CLOSING; + /* + * save termios struct since callout and dialin termios may be + * different. + */ + if (port->flags & ASYNC_NORMAL_ACTIVE) + port->normal_termios = *tty->termios; + if (port->flags & ASYNC_CALLOUT_ACTIVE) + port->callout_termios = *tty->termios; + + tty->closing = 1; + if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, port->closing_wait); + /* indicate to the card that no more data can be received + on this port */ + if (port->flags & ASYNC_INITIALIZED) { + card->port_status &= ~(1 << port->channel); + outw(card->port_status, card->base + 0x02); + } + isicom_shutdown_port(port); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + port->tty = 0; + if (port->blocked_open) { + if (port->close_delay) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + port->close_delay; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: scheduling until time out.\n"); +#endif + schedule(); + } + wake_up_interruptible(&port->open_wait); + } + port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | + ASYNC_CLOSING); + wake_up_interruptible(&port->close_wait); + restore_flags(flags); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: Close end!!!.\n"); +#endif +} + +/* write et all */ +static int isicom_write(struct tty_struct * tty, int from_user, + const unsigned char * buf, int count) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + unsigned long flags; + int cnt, total = 0; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_write for port%d: %d bytes.\n", + port->channel+1, count); +#endif + if (isicom_paranoia_check(port, tty->device, "isicom_write")) + return 0; + + if (!tty || !port->xmit_buf || !tmp_buf) + return 0; + if (from_user) + down(&tmp_buf_sem); /* acquire xclusive access to tmp_buf */ + + save_flags(flags); + while(1) { + cli(); + cnt = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + if (cnt <= 0) + break; + + if (from_user) { + /* the following may block for paging... hence + enabling interrupts but tx routine may have + created more space in xmit_buf when the ctrl + gets back here + sti(); */ + memcpy_fromfs(tmp_buf, buf, cnt); +/* cli();*/ + cnt = MIN(cnt, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1, + SERIAL_XMIT_SIZE - port->xmit_head)); + memcpy(port->xmit_buf + port->xmit_head, tmp_buf, cnt); + } + else + memcpy(port->xmit_buf + port->xmit_head, buf, cnt); + port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - 1); + port->xmit_cnt += cnt; + restore_flags(flags); + buf += cnt; + count -= cnt; + total += cnt; + } + if (from_user) + up(&tmp_buf_sem); + if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped) + port->status |= ISI_TXOK; + restore_flags(flags); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: isicom_write %d bytes written.\n", total); +#endif + return total; +} + +/* put_char et all */ +static void isicom_put_char(struct tty_struct * tty, unsigned char ch) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + unsigned long flags; + + if (isicom_paranoia_check(port, tty->device, "isicom_put_char")) + return; + + if (!tty || !port->xmit_buf) + return; +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: put_char, port %d, char %c.\n", port->channel+1, ch); +#endif + + save_flags(flags); cli(); + + if (port->xmit_cnt >= (SERIAL_XMIT_SIZE - 1)) { + restore_flags(flags); + return; + } + + port->xmit_buf[port->xmit_head++] = ch; + port->xmit_head &= (SERIAL_XMIT_SIZE - 1); + port->xmit_cnt++; + restore_flags(flags); +} + +/* flush_chars et all */ +static void isicom_flush_chars(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + + if (isicom_paranoia_check(port, tty->device, "isicom_flush_chars")) + return; + + if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !port->xmit_buf) + return; + + /* this tells the transmitter to consider this port for + data output to the card ... that's the best we can do. */ + port->status |= ISI_TXOK; +} + +/* write_room et all */ +static int isicom_write_room(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + int free; + if (isicom_paranoia_check(port, tty->device, "isicom_write_room")) + return 0; + + free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1; + if (free < 0) + free = 0; + return free; +} + +/* chars_in_buffer et all */ +static int isicom_chars_in_buffer(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + if (isicom_paranoia_check(port, tty->device, "isicom_chars_in_buffer")) + return 0; + return port->xmit_cnt; +} + +/* ioctl et all */ +extern inline void isicom_send_break(struct isi_port * port, unsigned long length) +{ + struct isi_board * card = port->card; + short wait = 10; + unsigned short base = card->base; + unsigned long flags; + + save_flags(flags); cli(); + while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0)); + if (!wait) { + printk(KERN_DEBUG "ISICOM: Card found busy in isicom_send_break.\n"); + return; + } + outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base); + outw((length & 0xff) << 8 | 0x00, base); + outw((length & 0xff00), base); + InterruptTheCard(base); + restore_flags(flags); +} + +static int isicom_get_modem_info(struct isi_port * port, unsigned int * value) +{ + /* just send the port status */ + unsigned int info; + unsigned short status = port->status; + + info = ((status & ISI_RTS) ? TIOCM_RTS : 0) | + ((status & ISI_DTR) ? TIOCM_DTR : 0) | + ((status & ISI_DCD) ? TIOCM_CAR : 0) | + ((status & ISI_DSR) ? TIOCM_DSR : 0) | + ((status & ISI_CTS) ? TIOCM_CTS : 0); + put_user(info, (unsigned long *) value); + return 0; +} + +static int isicom_set_modem_info(struct isi_port * port, unsigned int cmd, + unsigned int * value) +{ + unsigned int arg; + unsigned long flags; + + arg = get_user(value); + save_flags(flags); cli(); + switch(cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + raise_rts(port); + if (arg & TIOCM_DTR) + raise_dtr(port); + break; + + case TIOCMBIC: + if (arg & TIOCM_RTS) + drop_rts(port); + if (arg & TIOCM_DTR) + drop_dtr(port); + break; + + case TIOCMSET: + if (arg & TIOCM_RTS) + raise_rts(port); + else + drop_rts(port); + + if (arg & TIOCM_DTR) + raise_dtr(port); + else + drop_dtr(port); + break; + + default: + restore_flags(flags); + return -EINVAL; + } + restore_flags(flags); + return 0; +} + +static int isicom_set_serial_info(struct isi_port * port, + struct serial_struct * info) +{ + struct serial_struct newinfo; + unsigned long flags; + int reconfig_port; + + memcpy_fromfs(&newinfo, info, sizeof(newinfo)); + reconfig_port = ((port->flags & ASYNC_SPD_MASK) != + (newinfo.flags & ASYNC_SPD_MASK)); + + if (!suser()) { + if ((newinfo.close_delay != port->close_delay) || + (newinfo.closing_wait != port->closing_wait) || + ((newinfo.flags & ~ASYNC_USR_MASK) != + (port->flags & ~ASYNC_USR_MASK))) + return -EPERM; + port->flags = ((port->flags & ~ ASYNC_USR_MASK) | + (newinfo.flags & ASYNC_USR_MASK)); + } + else { + port->close_delay = newinfo.close_delay; + port->closing_wait = newinfo.closing_wait; + port->flags = ((port->flags & ~ASYNC_FLAGS) | + (newinfo.flags & ASYNC_FLAGS)); + } + if (reconfig_port) { + save_flags(flags); cli(); + isicom_config_port(port); + restore_flags(flags); + } + return 0; +} + +static int isicom_get_serial_info(struct isi_port * port, + struct serial_struct * info) +{ + struct serial_struct out_info; + + memset(&out_info, 0, sizeof(out_info)); +/* out_info.type = ? */ + out_info.line = port - isi_ports; + out_info.port = port->card->base; + out_info.irq = port->card->irq; + out_info.flags = port->flags; +/* out_info.baud_base = ? */ + out_info.close_delay = port->close_delay; + out_info.closing_wait = port->closing_wait; + memcpy_tofs(info, &out_info, sizeof(out_info)); + return 0; +} + +static int isicom_ioctl(struct tty_struct * tty, struct file * filp, + unsigned int cmd, unsigned long arg) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + int retval, error; + + if (isicom_paranoia_check(port, tty->device, "isicom_ioctl")) + return -ENODEV; + + switch(cmd) { + case TCSBRK: + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (!arg) + isicom_send_break(port, HZ/4); + return 0; + + case TCSBRKP: + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4); + return 0; + + case TIOCGSOFTCAR: + error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); + if (error) + return error; + put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); + return 0; + + case TIOCSSOFTCAR: + error = verify_area(VERIFY_READ, (void *) arg, sizeof(long)); + if (error) + return error; + arg = get_user((unsigned long *) arg); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; + + case TIOCMGET: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int)); + if (error) + return error; + return isicom_get_modem_info(port, (unsigned int*) arg); + + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + error = verify_area(VERIFY_READ, (void *) arg, + sizeof(unsigned int)); + if (error) + return error; + return isicom_set_modem_info(port, cmd, + (unsigned int *) arg); + + case TIOCGSERIAL: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct)); + if (error) + return error; + return isicom_get_serial_info(port, + (struct serial_struct *) arg); + + case TIOCSSERIAL: + error = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct serial_struct)); + if (error) + return error; + return isicom_set_serial_info(port, + (struct serial_struct *) arg); + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +/* set_termios et all */ +static void isicom_set_termios(struct tty_struct * tty, struct termios * old_termios) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + unsigned long flags; + + if (isicom_paranoia_check(port, tty->device, "isicom_set_termios")) + return; + + if (tty->termios->c_cflag == old_termios->c_cflag && + tty->termios->c_iflag == old_termios->c_iflag) + return; + + save_flags(flags); cli(); + isicom_config_port(port); + restore_flags(flags); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + isicom_start(tty); + } +} + +/* throttle et all */ +static void isicom_throttle(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + struct isi_board * card = port->card; + unsigned long flags; + + if (isicom_paranoia_check(port, tty->device, "isicom_throttle")) + return; + + /* tell the card that this port cannot handle any more data for now */ + save_flags(flags); cli(); + card->port_status &= ~(1 << port->channel); + outw(card->port_status, card->base + 0x02); + restore_flags(flags); +} + +/* unthrottle et all */ +static void isicom_unthrottle(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + struct isi_board * card = port->card; + unsigned long flags; + + if (isicom_paranoia_check(port, tty->device, "isicom_unthrottle")) + return; + + /* tell the card that this port is ready to accept more data */ + save_flags(flags); cli(); + card->port_status |= (1 << port->channel); + outw(card->port_status, card->base + 0x02); + restore_flags(flags); +} + +/* stop et all */ +static void isicom_stop(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + + if (isicom_paranoia_check(port, tty->device, "isicom_stop")) + return; + + /* this tells the transmitter not to consider this port for + data output to the card. */ + port->status &= ~ISI_TXOK; +} + +/* start et all */ +static void isicom_start(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + + if (isicom_paranoia_check(port, tty->device, "isicom_start")) + return; + + /* this tells the transmitter to consider this port for + data output to the card. */ + port->status |= ISI_TXOK; +} + +/* hangup et all */ +static void do_isicom_hangup(void * data) +{ + struct isi_port * port = (struct isi_port *) data; + struct tty_struct * tty; + + tty = port->tty; + if (!tty) + return; + + tty_hangup(tty); +} + +static void isicom_hangup(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + + if (isicom_paranoia_check(port, tty->device, "isicom_hangup")) + return; + + isicom_shutdown_port(port); + port->count = 0; + port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + port->tty = 0; + wake_up_interruptible(&port->open_wait); +} + +/* flush_buffer et all */ +static void isicom_flush_buffer(struct tty_struct * tty) +{ + struct isi_port * port = (struct isi_port *) tty->driver_data; + unsigned long flags; + + if (isicom_paranoia_check(port, tty->device, "isicom_flush_buffer")) + return; + + save_flags(flags); cli(); + port->xmit_cnt = port->xmit_head = port->xmit_tail = 0; + restore_flags(flags); + + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + + +static int register_ioregion(void) +{ + int count, done=0; + for (count=0; count < BOARD_COUNT; count++ ) { + if (isi_card[count].base) { + if (check_region(isi_card[count].base,16)) { + printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x is busy. Card%d will be disabled.\n", + isi_card[count].base,isi_card[count].base+15,count+1); + isi_card[count].base=0; + } + else { + request_region(isi_card[count].base,16,ISICOM_NAME); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x requested for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1); +#endif + done++; + } + } + } + return done; +} + +static void unregister_ioregion(void) +{ + int count; + for (count=0; count < BOARD_COUNT; count++ ) + if (isi_card[count].base) { + release_region(isi_card[count].base,16); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x released for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1); +#endif + } +} + +static int register_drivers(void) +{ + int error; + + /* tty driver structure initialization */ + memset(&isicom_normal, 0, sizeof(struct tty_driver)); + isicom_normal.magic = TTY_DRIVER_MAGIC; + isicom_normal.name = "ttyM"; + isicom_normal.major = ISICOM_NMAJOR; + isicom_normal.minor_start = 0; + isicom_normal.num = PORT_COUNT; + isicom_normal.type = TTY_DRIVER_TYPE_SERIAL; + isicom_normal.subtype = SERIAL_TYPE_NORMAL; + isicom_normal.init_termios = tty_std_termios; + isicom_normal.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL |CLOCAL; + isicom_normal.flags = TTY_DRIVER_REAL_RAW; + isicom_normal.refcount = &isicom_refcount; + + isicom_normal.table = isicom_table; + isicom_normal.termios = isicom_termios; + isicom_normal.termios_locked = isicom_termios_locked; + + isicom_normal.open = isicom_open; + isicom_normal.close = isicom_close; + isicom_normal.write = isicom_write; + isicom_normal.put_char = isicom_put_char; + isicom_normal.flush_chars = isicom_flush_chars; + isicom_normal.write_room = isicom_write_room; + isicom_normal.chars_in_buffer = isicom_chars_in_buffer; + isicom_normal.ioctl = isicom_ioctl; + isicom_normal.set_termios = isicom_set_termios; + isicom_normal.throttle = isicom_throttle; + isicom_normal.unthrottle = isicom_unthrottle; + isicom_normal.stop = isicom_stop; + isicom_normal.start = isicom_start; + isicom_normal.hangup = isicom_hangup; + isicom_normal.flush_buffer = isicom_flush_buffer; + + /* callout device */ + + isicom_callout = isicom_normal; + isicom_callout.name = "cum"; + isicom_callout.major = ISICOM_CMAJOR; + isicom_callout.subtype = SERIAL_TYPE_CALLOUT; + + if ((error=tty_register_driver(&isicom_normal))!=0) { + printk(KERN_DEBUG "ISICOM: Couldn't register the dialin driver, error=%d\n", + error); + return error; + } + if ((error=tty_register_driver(&isicom_callout))!=0) { + tty_unregister_driver(&isicom_normal); + printk(KERN_DEBUG "ISICOM: Couldn't register the callout driver, error=%d\n", + error); + return error; + } + return 0; +} + +static void unregister_drivers(void) +{ + int error; + if ((error=tty_unregister_driver(&isicom_callout))!=0) + printk(KERN_DEBUG "ISICOM: couldn't unregister callout driver error=%d.\n",error); + if (tty_unregister_driver(&isicom_normal)) + printk(KERN_DEBUG "ISICOM: couldn't unregister normal driver error=%d.\n",error); +} + +static int register_isr(void) +{ + int count, done=0; + for (count=0; count < BOARD_COUNT; count++ ) { + if (isi_card[count].base) { + if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT, ISICOM_NAME, NULL)) { + printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n", + isi_card[count].irq, count+1); + release_region(isi_card[count].base,16); + isi_card[count].base=0; + } + else { + printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n", + count+1, isi_card[count].base, isi_card[count].irq); + + irq_to_board[isi_card[count].irq]=&isi_card[count]; + done++; + } + } + } + return done; +} + +static void unregister_isr(void) +{ + int count; + for (count=0; count < BOARD_COUNT; count++ ) + if (isi_card[count].base) { + free_irq(isi_card[count].irq, NULL); +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1); +#endif + } +} + +static int isicom_init(void) +{ + int card, channel, base; + struct isi_port * port; + unsigned long page; + + if (!tmp_buf) { + page = get_free_page(GFP_KERNEL); + if (!page) { +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: Couldn't allocate page for tmp_buf.\n"); +#else + printk(KERN_ERR "ISICOM: Not enough memory...\n"); +#endif + return 0; + } + tmp_buf = (unsigned char *) page; + } + + if (!register_ioregion()) + { + printk(KERN_ERR "ISICOM: All required I/O space found busy.\n"); + free_page((unsigned long)tmp_buf); + return 0; + } + if (register_drivers()) + { + unregister_ioregion(); + free_page((unsigned long)tmp_buf); + return 0; + } + if (!register_isr()) + { + unregister_drivers(); + /* ioports already uregistered in register_isr */ + free_page((unsigned long)tmp_buf); + return 0; + } + + /* initialize bottom half */ + init_bh(ISICOM_BH, do_isicom_bh); + + + memset(isi_ports, 0, sizeof(isi_ports)); + for (card = 0; card < BOARD_COUNT; card++) { + port = &isi_ports[card * 16]; + isi_card[card].ports = port; + base = isi_card[card].base; + for (channel = 0; channel < 16; channel++, port++) { + port->magic = ISICOM_MAGIC; + port->card = &isi_card[card]; + port->channel = channel; + port->normal_termios = isicom_normal.init_termios; + port->callout_termios = isicom_callout.init_termios; + port->close_delay = 50 * HZ/100; + port->closing_wait = 3000 * HZ/100; + port->hangup_tq.routine = do_isicom_hangup; + port->hangup_tq.data = port; + port->bh_tqueue.routine = isicom_bottomhalf; + port->bh_tqueue.data = port; + port->status = 0; + + /* . . . */ + } + } + + return 1; +} + +/* + * Insmod can set static symbols so keep these static + */ + +static int ISIBase1=0, ISIBase2=0, ISIBase3=0, ISIBase4=0; +static int Irq1=0, Irq2=0, Irq3=0, Irq4=0; + +int init_module(void) +{ + int retval, card; + + isi_card[0].base=ISIBase1; + isi_card[1].base=ISIBase2; + isi_card[2].base=ISIBase3; + isi_card[3].base=ISIBase4; + + isi_card[0].irq=Irq1; + isi_card[1].irq=Irq2; + isi_card[2].irq=Irq3; + isi_card[3].irq=Irq4; + + for (card=0 ;card < BOARD_COUNT; card++) { + if (!((isi_card[card].irq==2)||(isi_card[card].irq==3)|| + (isi_card[card].irq==4)||(isi_card[card].irq==5)|| + (isi_card[card].irq==7)||(isi_card[card].irq==10)|| + (isi_card[card].irq==11)||(isi_card[card].irq==12)|| + (isi_card[card].irq==15))) { + + if (isi_card[card].base) { + printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n", + isi_card[card].irq, card+1); + isi_card[card].base=0; + } + } + } + + if (!(isi_card[0].base || isi_card[1].base || isi_card[2].base || isi_card[3].base)) { + printk(KERN_ERR "ISICOM: No valid card configuration. Driver cannot be initialized...\n"); + return -EIO; + } + retval=misc_register(&isiloader_device); + if (retval<0) { + printk(KERN_ERR "ISICOM: Unable to register firmware loader driver.\n"); + return -EIO; + } + + if (!isicom_init()) { + if (misc_deregister(&isiloader_device)) + printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n"); + return -EIO; + } + + init_timer(&tx); + tx.expires = jiffies + 1; + tx.data = 0; + tx.function = isicom_tx; + re_schedule = 1; + add_timer(&tx); + + return 0; +} + +void cleanup_module(void) +{ + re_schedule = 0; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + HZ; + schedule(); + disable_bh(ISICOM_BH); + +#ifdef ISICOM_DEBUG + printk("ISICOM: isicom_tx tx_count = %ld.\n", tx_count); +#endif + +#ifdef ISICOM_DEBUG + printk("ISICOM: uregistering isr ...\n"); +#endif + unregister_isr(); + +#ifdef ISICOM_DEBUG + printk("ISICOM: unregistering drivers ...\n"); +#endif + unregister_drivers(); + +#ifdef ISICOM_DEBUG + printk("ISICOM: unregistering ioregion ...\n"); +#endif + unregister_ioregion(); + +#ifdef ISICOM_DEBUG + printk("ISICOM: freeing tmp_buf ...\n"); +#endif + free_page((unsigned long)tmp_buf); + +#ifdef ISICOM_DEBUG + printk("ISICOM: unregistering firmware loader ...\n"); +#endif + if (misc_deregister(&isiloader_device)) + printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n"); +} diff --git a/drivers/char/isicom.h b/drivers/char/isicom.h new file mode 100644 index 000000000000..040d2f05b097 --- /dev/null +++ b/drivers/char/isicom.h @@ -0,0 +1,300 @@ +#ifndef ISICOM_H +#define ISICOM_H + +/*#define ISICOM_DEBUG*/ +/*#define ISICOM_DEBUG_DTR_RTS*/ + + + +/* + * Firmware Loader definitions ... + */ + +#define ISILOAD_MISC_MINOR 155 /* /dev/isctl */ +#define ISILOAD_NAME "ISILoad" + +#define MultiTech ('M'<<8) +#define MIOCTL_LOAD_FIRMWARE (MultiTech | 0x01) +#define MIOCTL_READ_FIRMWARE (MultiTech | 0x02) +#define MIOCTL_XFER_CTRL (MultiTech | 0x03) +#define MIOCTL_RESET_CARD (MultiTech | 0x04) + +#define DATA_SIZE 16 + +typedef struct { + unsigned short exec_segment; + unsigned short exec_addr; +} exec_record; + +typedef struct { + int board; /* Board to load */ + unsigned short addr; + unsigned short count; +} bin_header; + +typedef struct { + int board; /* Board to load */ + unsigned short addr; + unsigned short count; + unsigned short segment; + unsigned char bin_data[DATA_SIZE]; +} bin_frame; + +#ifdef __KERNEL__ + +/* + * ISICOM Driver definitions ... + * + */ + +#define ISICOM_NAME "ISICom" + +/* + * These are now officially allocated numbers + */ + +#define ISICOM_NMAJOR 112 /* normal */ +#define ISICOM_CMAJOR 113 /* callout */ +#define ISICOM_MAGIC (('M' << 8) | 'T') + +#define ISICOM_BH 16 /* bottom half entry # */ + +#define WAKEUP_CHARS 256 /* hard coded for now */ +#define TX_SIZE 254 + +#define BOARD_COUNT 4 +#define PORT_COUNT (BOARD_COUNT*16) + +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 + +/* character sizes */ + +#define ISICOM_CS5 0x0000 +#define ISICOM_CS6 0x0001 +#define ISICOM_CS7 0x0002 +#define ISICOM_CS8 0x0003 + +/* stop bits */ + +#define ISICOM_1SB 0x0000 +#define ISICOM_2SB 0x0004 + +/* parity */ + +#define ISICOM_NOPAR 0x0000 +#define ISICOM_ODPAR 0x0008 +#define ISICOM_EVPAR 0x0018 + +/* flow control */ + +#define ISICOM_CTSRTS 0x03 +#define ISICOM_INITIATE_XONXOFF 0x04 +#define ISICOM_RESPOND_XONXOFF 0x08 + +#define InterruptTheCard(base) (outw(0,(base)+0xc)) +#define ClearInterrupt(base) (inw((base)+0x0a)) + +#define BOARD(line) (((line) >> 4) & 0x3) +#define MIN(a, b) ( (a) < (b) ? (a) : (b) ) + + /* isi kill queue bitmap */ + +#define ISICOM_KILLTX 0x01 +#define ISICOM_KILLRX 0x02 + + /* isi_board status bitmap */ + +#define FIRMWARE_LOADED 0x0001 +#define BOARD_ACTIVE 0x0002 + + /* isi_port status bitmap */ + +#define ISI_CTS 0x1000 +#define ISI_DSR 0x2000 +#define ISI_RI 0x4000 +#define ISI_DCD 0x8000 +#define ISI_DTR 0x0100 +#define ISI_RTS 0x0200 + + +#define ISI_TXOK 0x0001 + +struct isi_board { + unsigned short base; + unsigned char irq; + unsigned char port_count; + unsigned short status; + unsigned short port_status; /* each bit represents a single port */ + unsigned short shift_count; + struct isi_port * ports; + signed char count; +}; + +struct isi_port { + unsigned short magic; + unsigned int flags; + int count; + int blocked_open; + int close_delay; + unsigned short channel; + unsigned short status; + unsigned short closing_wait; + long session; + long pgrp; + struct isi_board * card; + struct tty_struct * tty; + struct wait_queue * close_wait; + struct wait_queue * open_wait; + struct tq_struct hangup_tq; + struct tq_struct bh_tqueue; + unsigned char * xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct termios normal_termios; + struct termios callout_termios; +}; + + +/* + * ISI Card specific ops ... + */ + +extern inline void raise_dtr(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in raise_dtr.\n"); + return; + } +#ifdef ISICOM_DEBUG_DTR_RTS + printk(KERN_DEBUG "ISICOM: raise_dtr.\n"); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0504, base); + InterruptTheCard(base); + port->status |= ISI_DTR; +} +extern inline void drop_dtr(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in drop_dtr.\n"); + return; + } +#ifdef ISICOM_DEBUG_DTR_RTS + printk(KERN_DEBUG "ISICOM: drop_dtr.\n"); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0404, base); + InterruptTheCard(base); + port->status &= ~ISI_DTR; +} +extern inline void raise_rts(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in raise_rts.\n"); + return; + } +#ifdef ISICOM_DEBUG_DTR_RTS + printk(KERN_DEBUG "ISICOM: raise_rts.\n"); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0a04, base); + InterruptTheCard(base); + port->status |= ISI_RTS; +} +extern inline void drop_rts(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in drop_rts.\n"); + return; + } +#ifdef ISICOM_DEBUG_DTR_RTS + printk(KERN_DEBUG "ISICOM: drop_rts.\n"); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0804, base); + InterruptTheCard(base); + port->status &= ~ISI_RTS; +} +extern inline void raise_dtr_rts(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in raise_dtr_rts.\n"); + return; + } +#ifdef ISICOM_DEBUG_DTR_RTS + printk(KERN_DEBUG "ISICOM: raise_dtr_rts.\n"); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0f04, base); + InterruptTheCard(base); + port->status |= (ISI_DTR | ISI_RTS); +} +extern inline void drop_dtr_rts(struct isi_port * port) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in drop_dtr_rts.\n"); + return; + } +#ifdef ISICOM_DEBUG_DTR_RTS + printk(KERN_DEBUG "ISICOM: drop_dtr_rts.\n"); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw(0x0c04, base); + InterruptTheCard(base); + port->status &= ~(ISI_RTS | ISI_DTR); +} + +extern inline void kill_queue(struct isi_port * port, short queue) +{ + struct isi_board * card = port->card; + unsigned short base = card->base; + unsigned char channel = port->channel; + short wait=300; + while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0)); + if (wait <= 0) { + printk(KERN_WARNING "ISICOM: Card found busy in kill_queue.\n"); + return; + } +#ifdef ISICOM_DEBUG + printk(KERN_DEBUG "ISICOM: kill_queue 0x%x.\n", queue); +#endif + outw(0x8000 | (channel << card->shift_count) | 0x02 , base); + outw((queue << 8) | 0x06, base); + InterruptTheCard(base); +} + +#endif /* __KERNEL__ */ + +#endif /* ISICOM_H */ \ No newline at end of file diff --git a/drivers/char/lp.c b/drivers/char/lp.c index 96fe95824f82..d1b8edd71f38 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -89,12 +89,18 @@ static inline int lp_char_polled(char lpchar, int minor) while(wait != LP_WAIT(minor)) wait++; /* control port takes strobe high */ outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor ))); - /* Wait until NBUSY line goes high */ - count = 0; - do { - status = LP_S(minor); - count++; - } while (LP_READY(minor, status) && (countend_head; end_sector = largest->end_sector & 0x3f; + if( end_head + 1 == 0 || end_sector == 0 ) return -1; + #ifdef DEBUG printk ("scsicam_bios_param : end at h = %d, c = %d, s = %d\n", end_head, end_cyl, end_sector); diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile index d5dfa70aedc0..9e856fdb9f8e 100644 --- a/drivers/sound/Makefile +++ b/drivers/sound/Makefile @@ -146,11 +146,10 @@ sound.o: local.h $(FIXEDOBJS) sound.a $(LD) -r -o sound.o $(FIXEDOBJS) sound.a modules: local.h sound.o - ln -fs `pwd`/sound.o $(TOPDIR)/modules/sound.o - + ln -fs ../drivers/sound/sound.o $(TOPDIR)/modules/sound.o lowlevel/lowlevel.o: dummy - cd lowlevel;make + cd lowlevel; make ifdef USE_DEPEND # diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index e8506e6f3d62..ee279b39bdd1 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -16,6 +16,7 @@ * * Changes: * + * R. Drahtmueller : Set IFF_MULTICAST in dev->flags if applicable. * Alan Cox : Removed get_address name clash with FPU. * Alan Cox : Reformatted a bit. * Gero Kuhlmann : Code cleanup @@ -179,7 +180,11 @@ static int root_dev_open(void) (!user_dev_name[0] || !strcmp(dev->name, user_dev_name))) { /* First up the interface */ old_flags = dev->flags; +#ifdef CONFIG_IP_MULTICAST + dev->flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING | IFF_MULTICAST; +#else dev->flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING; +#endif if (!(old_flags & IFF_UP) && dev_open(dev)) { dev->flags = old_flags; continue; diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h index 8ce98f5b5eaa..34c4b5e64313 100644 --- a/include/linux/cyclades.h +++ b/include/linux/cyclades.h @@ -754,6 +754,13 @@ struct cyclades_port { #define CyTBPR (0x72*2) #define CyTCOR (0x76*2) +/* Custom Registers */ + +#define CyPLX_VER (0x3400) +#define PLX_9050 0x11 +#define PLX_9060 0x12 +#define PLX_9080 0x13 + /***************************************************************************/ #endif /* __KERNEL__ */ diff --git a/include/linux/ip_fw.h b/include/linux/ip_fw.h index 1b5e989aea6a..9ac441707cac 100644 --- a/include/linux/ip_fw.h +++ b/include/linux/ip_fw.h @@ -131,9 +131,6 @@ struct ip_fw #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW #define IP_FW_AUTOFW 5 #endif -#ifdef CONFIG_IP_MASQUERADE_IPPFVS -#define IP_FW_PORTFW 6 -#endif #define IP_FW_INSERT (IP_FW_BASE_CTL) #define IP_FW_APPEND (IP_FW_BASE_CTL+1) @@ -180,12 +177,6 @@ struct ip_fw #define IP_AUTOFW_FLUSH (IP_FW_FLUSH | (IP_FW_AUTOFW << IP_FW_SHIFT)) #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ -#ifdef CONFIG_IP_MASQUERADE_IPPFVS -#define IP_PORTFW_ADD (IP_FW_APPEND | (IP_FW_PORTFW << IP_FW_SHIFT)) -#define IP_PORTFW_DEL (IP_FW_DELETE | (IP_FW_PORTFW << IP_FW_SHIFT)) -#define IP_PORTFW_FLUSH (IP_FW_FLUSH | (IP_FW_PORTFW << IP_FW_SHIFT)) -#endif /* CONFIG_IP_MASQUERADE_IPPFVS */ - struct ip_fwpkt { struct iphdr fwp_iph; /* IP header */ @@ -228,9 +219,6 @@ extern int ip_fw_ctl(int, void *, int); #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW extern int ip_autofw_ctl(int, void *, int); #endif -#ifdef CONFIG_IP_MASQUERADE_IPPFVS -extern int ip_portfw_ctl(int, void *, int); -#endif #ifdef CONFIG_IP_ACCT extern struct ip_fw *ip_acct_chain; extern int ip_acct_ctl(int, void *, int); @@ -265,42 +253,4 @@ struct ip_autofw { struct timer_list timer; }; #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ - -#ifdef CONFIG_IP_MASQUERADE_IPPFVS - -#define IP_PORTFW_PORT_MIN 1 -#define IP_PORTFW_PORT_MAX 60999 -#define SERVER_WEIGHT_MIN 1 -#define SERVER_WEIGHT_MAX 1000 - -/* contains info about a real server */ -struct server { - struct server *next; /* next real server for the virtual server */ - __u32 ip; /* ip address of the real server */ - __u16 port; /* port number of service on the real server */ - int connections; /* number of alive connections (TCP only) */ - short weight; /* to indicate server's processing capacity */ -}; - - -struct ip_portfw { - struct ip_portfw *next; - __u32 laddr; - __u16 lport; - struct server *sr_lst; /* server list */ - struct server *curr_sr; /* current server used in simple round-robbin scheduling algorithm */ -}; - -struct ip_portfw_edits { - __u16 protocol; /* Which protocol are we talking? */ - __u32 laddr, raddr; /* Local and remote address */ - __u16 lport, rport; /* Local and remote port */ - short weight; /* Server weight */ -}; -#endif /* CONFIG_IP_MASQUERADE_IPPFVS */ #endif /* _IP_FW_H */ - - - - - diff --git a/include/linux/lp.h b/include/linux/lp.h index 2a1282c8add2..c34df2cc55cf 100644 --- a/include/linux/lp.h +++ b/include/linux/lp.h @@ -20,6 +20,7 @@ #define LP_ABORT 0x0040 #define LP_CAREFUL 0x0080 #define LP_ABORTOPEN 0x0100 +#define LP_STRICT 0x0200 /* timeout for each character. This is relative to bus cycles -- it * is the count in a busy loop. THIS IS THE VALUE TO CHANGE if you @@ -70,6 +71,7 @@ #define LPRESET 0x060c /* reset printer */ #define LPGETSTATS 0x060d /* get statistics (struct lp_stats) */ #define LPGETFLAGS 0x060e /* get status flags */ +#define LPSTRICT 0x060f /* enable/disable strict compliance */ /* timeout for printk'ing a timeout, in jiffies (100ths of a second). This is also used for re-checking error conditions if LP_ABORT is diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 998809741154..fc1a4b8f5a9b 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -105,7 +105,6 @@ enum net_directory_inos { PROC_NET_STRIP_STATUS, PROC_NET_STRIP_TRACE, PROC_NET_IPAUTOFW, - PROC_NET_IPPORTFW, PROC_NET_RS_NODES, PROC_NET_RS_NEIGH, PROC_NET_RS_ROUTES, diff --git a/include/net/ip_masq.h b/include/net/ip_masq.h index 416b2b4b6980..ccfb646c38b2 100644 --- a/include/net/ip_masq.h +++ b/include/net/ip_masq.h @@ -84,9 +84,6 @@ struct ip_masq { void *app_data; /* Application private data */ unsigned flags; /* status flags */ struct ip_masq *control; /* Corresponding control connection */ -#ifdef CONFIG_IP_MASQUERADE_IPPFVS - struct server *real_server; /* Which real server is chosen? */ -#endif /* CONFIG_IP_MASQUERADE_IPPFVS */ }; /* diff --git a/net/ipv4/Config.in b/net/ipv4/Config.in index 2acbb5adfe1e..3d1ac2cfb96f 100644 --- a/net/ipv4/Config.in +++ b/net/ipv4/Config.in @@ -16,7 +16,6 @@ if [ "$CONFIG_FIREWALL" = "y" ]; then comment 'Protocol-specific masquerading support will be built as modules.' if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'IP: ipautofw masquerading (EXPERIMENTAL)' CONFIG_IP_MASQUERADE_IPAUTOFW - bool 'IP: ipportfw masq & virtual server support' CONFIG_IP_MASQUERADE_IPPFVS fi bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP fi diff --git a/net/ipv4/ip_fw.c b/net/ipv4/ip_fw.c index 4665bf417863..63f6ebd19486 100644 --- a/net/ipv4/ip_fw.c +++ b/net/ipv4/ip_fw.c @@ -977,170 +977,6 @@ int ip_autofw_ctl(int stage, void *m, int len) #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ - -#ifdef CONFIG_IP_MASQUERADE_IPPFVS -extern struct ip_portfw *ipportfw_lst[2]; - -int ip_portfw_del(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr) -{ - int prot = (protocol == IPPROTO_TCP); - struct ip_portfw *pf; - struct ip_portfw **pf_p; - - if (!ipportfw_lst[prot]) - return 1; - - for (pf_p = &ipportfw_lst[prot]; *pf_p; pf_p = &(*pf_p)->next) { - pf = *pf_p; - if (pf->lport == lport && pf->laddr == laddr) { - struct server *s; - struct server **sp; - for (sp = &pf->sr_lst; *sp; sp = &(*sp)->next) { - s = *sp; - if (s->ip == raddr && s->port == rport) { - *sp = s->next; - kfree_s(s, sizeof(*s)); - if (!pf->sr_lst) { - /* No real server exists now, and remove the entry in the port forwarding table */ - *pf_p = pf->next; - kfree_s(pf, sizeof(*pf)); - } - return 0; - } - } - } - } - - /* Entry not found so return an error */ - return 1; -} - -void ip_portfw_flush(void) -{ - int prot; - struct ip_portfw *c, *n; - struct server *s, *sn; - - for (prot = 0; prot < 2; prot++) { - c = ipportfw_lst[prot]; - ipportfw_lst[prot] = NULL; - for (; c; c = n) { - n = c->next; - s = c->sr_lst; - while (s) { - sn = s->next; - kfree_s(s, sizeof(*s)); - s = sn; - } - kfree_s(c, sizeof(*c)); - } - } -} - -int ip_portfw_add(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, short weight) -{ - struct ip_portfw *pf, *newportfw; - struct server *s, *newserv; - int prot = (protocol == IPPROTO_TCP); - - for (pf = ipportfw_lst[prot]; pf; pf = pf->next) { - if (lport == pf->lport && laddr == pf->laddr) { - for (s = pf->sr_lst; s; s = s->next) { - if (s->ip == raddr && s->port == rport) { - s->weight = weight; - return 0; - } - } - newserv = (struct server *) kmalloc(sizeof(struct server), GFP_ATOMIC); - if (!newserv) - return 1; - - newserv->ip = raddr; - newserv->port = rport; - newserv->weight = weight; - newserv->connections = 0; - - /* insert the new real server in the server list */ - newserv->next = pf->sr_lst; - pf->sr_lst = newserv; - return 0; - } - } - - newserv = (struct server *) kmalloc(sizeof(struct server), GFP_ATOMIC); - if (!newserv) - return 1; - - newserv->ip = raddr; - newserv->port = rport; - newserv->weight = weight; - newserv->connections = 0; - newserv->next = NULL; - - newportfw = (struct ip_portfw *) - kmalloc(sizeof(struct ip_portfw), GFP_ATOMIC); - - if (!newportfw) - return 1; - - newportfw->laddr = laddr; - newportfw->lport = lport; - newportfw->sr_lst = newserv; - newportfw->curr_sr = NULL; - - /* insert the new entry into the port forwarding table */ - newportfw->next = ipportfw_lst[prot]; - ipportfw_lst[prot] = newportfw; - return 0; -} - -int ip_portfw_ctl(int cmd, void *m, int len) -{ - unsigned long flags; - int failed; - struct ip_portfw_edits *mm = (struct ip_portfw_edits *) m; - - /* Don't trust the lusers - plenty of error checking! */ - - if (cmd != IP_PORTFW_ADD && cmd != IP_PORTFW_DEL - && cmd != IP_PORTFW_FLUSH) - return (EINVAL); - - if (cmd != IP_PORTFW_FLUSH) { - if (mm->lport < IP_PORTFW_PORT_MIN || mm->lport > IP_PORTFW_PORT_MAX) - return (EINVAL); - - if (mm->protocol != IPPROTO_TCP && mm->protocol != IPPROTO_UDP) - return (EINVAL); - } - if (cmd == IP_PORTFW_ADD) { - save_flags(flags); - cli(); - failed = ip_portfw_add(mm->protocol, - htons(mm->lport), htonl(mm->laddr), - htons(mm->rport), htonl(mm->raddr), - mm->weight); - restore_flags(flags); - return (failed ? ENOMEM : 0); - } else if (cmd == IP_PORTFW_DEL) { - save_flags(flags); - cli(); - failed = ip_portfw_del(mm->protocol, - htons(mm->lport), htonl(mm->laddr), - htons(mm->rport), htonl(mm->raddr)); - restore_flags(flags); - return (failed ? EINVAL : 0); - } else if (cmd == IP_PORTFW_FLUSH) { - save_flags(flags); - cli(); - ip_portfw_flush(); - restore_flags(flags); - return 0; - } else - return (EINVAL); /* This should have avoided in ip_sockglue.c */ -} -#endif /* CONFIG_IP_MASQUERADE_IPPFVS */ - #ifdef CONFIG_IP_FIREWALL int ip_fw_ctl(int stage, void *m, int len) { diff --git a/net/ipv4/ip_masq.c b/net/ipv4/ip_masq.c index e21c451bf00d..6c485e45842e 100644 --- a/net/ipv4/ip_masq.c +++ b/net/ipv4/ip_masq.c @@ -20,8 +20,6 @@ * Delian Delchev : Added support for ICMP requests and replys * Nigel Metheringham : ICMP in ICMP handling, tidy ups, bug fixes, made ICMP optional * Juan Jose Ciarlante : re-assign maddr if no packet received from outside - * Steven Clarke : Added Port Forwarding - * Wensong Zhang : Added virtual server support * */ @@ -45,15 +43,7 @@ #include #include -#ifdef CONFIG_IP_MASQUERADE_IPPFVS -/* - * Use a big hash table size for virtual server, which will reduce conflicts - * in the hash table when there are thousands of masqueraded connections. - */ -#define IP_MASQ_TAB_SIZE 2048 -#else #define IP_MASQ_TAB_SIZE 256 /* must be power of 2 */ -#endif /* CONFIG_IP_MASQUERADE_IPPFVS */ /* * Implement IP packet masquerading @@ -259,64 +249,6 @@ void ip_autofw_update_in (__u32 where, __u16 port, __u16 protocol) #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ -#ifdef CONFIG_IP_MASQUERADE_IPPFVS - -struct ip_portfw *ipportfw_lst[2]; - -struct server *ip_portfw_lookup(__u16 protocol, __u16 lport, __u32 laddr) -{ - int prot = (protocol == IPPROTO_TCP); - struct ip_portfw *n; - unsigned long flags; - int least_load, curr_load; - struct server *least, *curr; - - save_flags(flags); - cli(); - for (n = ipportfw_lst[prot]; n; n = n->next) { - if (lport == n->lport && laddr == n->laddr) { - /* Weighted Round-Robin Scheduling Algorithm */ - least = n->sr_lst; - least_load = least->connections / least->weight; - - for(curr = least->next; curr; curr=curr->next) { - curr_load = curr->connections / curr->weight; - if(curr_load < least_load) { - least_load = curr_load; - least = curr; - } - } - - least->connections++; - - restore_flags(flags); - return least; - } - } - restore_flags(flags); - return NULL; -} - -int ip_portfw_check(__u16 protocol, __u16 lport, __u32 laddr) -{ - int prot = (protocol == IPPROTO_TCP); - struct ip_portfw *n; - unsigned long flags; - int found = 0; - - save_flags(flags); - cli(); - for (n = ipportfw_lst[prot]; n; n = n->next) { - if (lport == n->lport && laddr == n->laddr) { - found = 1; - break; - } - } - restore_flags(flags); - return found; -} -#endif /* CONFIG_IP_MASQUERADE_IPPFVS */ - /* * Returns hash value */ @@ -640,12 +572,6 @@ static void masq_expire(unsigned long data) ip_masq_free_ports[masq_proto_num(ms->protocol)]++; if (ms->protocol != IPPROTO_ICMP) ip_masq_unbind_app(ms); -#ifdef CONFIG_IP_MASQUERADE_IPPFVS - /* if not null, decrease the real server's alive connection count */ - if (ms->real_server) - ms->real_server->connections--; -#endif /* CONFIG_IP_MASQUERADE_IPPFVS */ - kfree_s(ms,sizeof(*ms)); } @@ -773,58 +699,6 @@ struct ip_masq * ip_masq_new(struct device *dev, int proto, __u32 saddr, __u16 s return (ip_masq_new_enh(dev, proto, saddr, sport, daddr, dport, mflags, 0) ); } - -#ifdef CONFIG_IP_MASQUERADE_IPPFVS - -/* - * New form of ip_masq creation which creates masqs for Port Forwarding & - * Virtual Server. The routine is sufficiently different to ip_masq_new - * to require its own function. - */ - -struct ip_masq *ip_masq_new_pfvs(struct device *dev, int proto, - struct server *rserver, - __u32 saddr, __u16 sport, - __u32 laddr, __u16 lport) -{ - struct ip_masq *ms; - static int n_fails = 0; - unsigned long flags; - - ms = (struct ip_masq *) kmalloc(sizeof(struct ip_masq), GFP_ATOMIC); - if (ms == NULL) { - if (++n_fails < 5) - printk("ip_masq_new_s(proto=%s): no memory available.\n", masq_proto_name(proto)); - return NULL; - } - memset(ms, 0, sizeof(*ms)); - init_timer(&ms->timer); - ms->timer.data = (unsigned long) ms; - ms->timer.function = masq_expire; - ms->protocol = proto; - ms->saddr = rserver->ip; - ms->sport = rserver->port; - ms->daddr = saddr; - ms->dport = sport; - ms->maddr = laddr; - ms->mport = lport; - ms->flags = 0; - ms->app_data = NULL; - ms->control = NULL; - ms->real_server = rserver; - - ip_masq_free_ports[masq_proto_num(proto)]++; - - save_flags(flags); - cli(); - ip_masq_hash(ms); - restore_flags(flags); - - return ms; -} -#endif /* CONFIG_IP_MASQUERADE_IPPFVS */ - - /* * Set masq expiration (deletion) and adds timer, * if timeout==0 cancel expiration. @@ -1491,10 +1365,6 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev) struct ip_autofw *af; #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ -#ifdef CONFIG_IP_MASQUERADE_IPPFVS - struct server *rserver; /* real server chosen for this connection */ -#endif /* CONFIG_IP_MASQUERADE_IPPFVS */ - switch (iph->protocol) { case IPPROTO_ICMP: return(ip_fw_demasq_icmp(skb_p, dev)); @@ -1510,9 +1380,6 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev) && !ip_autofw_check_direct(portptr[1], iph->protocol) && !ip_autofw_check_port(portptr[1], iph->protocol) #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ -#ifdef CONFIG_IP_MASQUERADE_IPPFVS - && !ip_portfw_check(iph->protocol, portptr[1], iph->daddr) -#endif /* CONFIG_IP_MASQUERADE_IPPFVS */ ) return 0; @@ -1581,24 +1448,6 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev) } #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ -#ifdef CONFIG_IP_MASQUERADE_IPPFVS - /* If no entry exists in the masquerading table, and the port is - involved in port forwarding & virtual server table, - create a new entry in the masquerading table */ - if ((ms == NULL) && - (iph->protocol == IPPROTO_TCP || iph->protocol == IPPROTO_UDP) && - (rserver = ip_portfw_lookup(iph->protocol, portptr[1], iph->daddr))) { -#ifdef DEBUG_CONFIG_IP_MASQUERADE - printk("ippfvs: Forwarding %s %1X:%X ==> %1X:%X\n", - masq_proto_name(iph->protocol), - ntohl(iph->daddr), ntohs(portptr[1]), - ntohl(rserver->raddr), ntohs(rserver->rport)); -#endif - ms = ip_masq_new_pfvs(dev, iph->protocol, rserver, - iph->saddr, portptr[0], iph->daddr, portptr[1]); - } -#endif /* CONFIG_IP_MASQUERADE_IPPFVS */ - if (ms != NULL) { #ifdef CONFIG_IP_MASQUERADE_IPAUTOFW @@ -1753,71 +1602,6 @@ static int ip_autofw_procinfo(char *buffer, char **start, off_t offset, } #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ - -#ifdef CONFIG_IP_MASQUERADE_IPPFVS -static int ip_portfw_procinfo(char *buffer, char **start, off_t offset, - int length, int unused) -{ - off_t pos = 0, begin = 0; - struct ip_portfw *pf; - struct server *s; - unsigned long flags; - int ind, raddr, laddr; - int len = 0, last_len = 0; - - len = sprintf(buffer, "IP Port Forwarding & Virtual Server Table\n"); - len += sprintf(buffer + len, "Protocol Local Addr:Port ==> \n"); - len += sprintf(buffer + len, "\t\t\tRemote Addr:Port \tWeight \tConnections\n"); - len += sprintf(buffer + len, "\t\t\t...\n"); - - save_flags(flags); - cli(); - - for (ind = 0; ind < 2; ind++) { - for (pf = ipportfw_lst[ind]; pf; pf = pf->next) { - laddr = ntohl(pf->laddr); - len += sprintf(buffer + len, "%s %d.%d.%d.%d:%d ==>\n", - strProt[ind], - (laddr >> 24) & 255, (laddr >> 16) & 255, - (laddr >> 8) & 255, laddr & 255, - ntohs(pf->lport)); - if (len >= length) - goto done; - - for (s = pf->sr_lst; s; s = s->next) { - raddr = ntohl(s->ip); - len += sprintf(buffer + len, - "\t\t\t%d.%d.%d.%d:%d \t%d\t%d\n", - (raddr >> 24) & 255, (raddr >> 16) & 255, - (raddr >> 8) & 255, raddr & 255, - ntohs(s->port), s->weight, s->connections); - if (len >= length) - goto done; - } - - pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; - } else if (pos > offset + length) { - len = last_len; - break; - } - last_len = len; - - } - } - done: - restore_flags(flags); - *start = buffer + (offset - begin); - len -= (offset - begin); - if (len > length) - len = length; - return len; -} -#endif /* CONFIG_IP_MASQUERADE_IPPFVS */ - - static int ip_msqhst_procinfo(char *buffer, char **start, off_t offset, int length, int unused) { @@ -1903,14 +1687,6 @@ int ip_masq_init(void) ip_autofw_procinfo }); #endif /* CONFIG_IP_MASQUERADE_IPAUTOFW */ -#ifdef CONFIG_IP_MASQUERADE_IPPFVS - proc_net_register(&(struct proc_dir_entry) { - PROC_NET_IPPORTFW, 9, "ip_portfw", - S_IFREG | S_IRUGO, 1, 0, 0, - 0, &proc_net_inode_operations, - ip_portfw_procinfo - }); -#endif /* CONFIG_IP_MASQUERADE_IPPFVS */ #endif ip_masq_app_init(); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 0552d348ed77..6784ca56b963 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -423,22 +423,6 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt err=ip_autofw_ctl(optname, &tmp_fw,optlen); return -err; /* -0 is 0 after all */ -#endif -#ifdef CONFIG_IP_MASQUERADE_IPPFVS - case IP_PORTFW_ADD: - case IP_PORTFW_DEL: - case IP_PORTFW_FLUSH: - if(!suser()) - return -EPERM; - if(optlen>sizeof(tmp_fw) || optlen<1) - return -EINVAL; - err=verify_area(VERIFY_READ,optval,optlen); - if(err) - return err; - memcpy_fromfs(&tmp_fw,optval,optlen); - err=ip_portfw_ctl(optname, &tmp_fw,optlen); - return -err; /* -0 is 0 after all */ - #endif #ifdef CONFIG_IP_ACCT case IP_ACCT_INSERT: diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 22ae4bfc45cc..12310ac81316 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -546,7 +546,10 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb, /* If the socket is dead, don't accept the connection. */ if (!sk->dead) { - sk->data_ready(sk,0); + /* + * This must wait for 3 way completion. + * sk->data_ready(sk,0); + */ } else { @@ -889,7 +892,7 @@ static int tcp_conn_request_fake(struct sock *sk, struct sk_buff *skb, /* If the socket is dead, don't accept the connection. */ if (!sk->dead) { - sk->data_ready(sk,0); + /*sk->data_ready(sk,0); */ } else {