diff -Naurp linux-2.4.20-wolk4.1s/Changelog.rmap linux-2.4.20-wolk4.2-fullkernel/Changelog.rmap --- linux-2.4.20-wolk4.1s/Changelog.rmap 2003-05-15 21:52:18.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/Changelog.rmap 2003-06-01 18:15:45.000000000 +0200 @@ -1,10 +1,10 @@ -The ninth maintenance release of the 15th version of the reverse +The tenth maintenance release of the 15th version of the reverse mapping based VM is now available. This is an attempt at making a more robust and flexible VM subsystem, while cleaning up a lot of code at the same time. The patch is available from: - http://surriel.com/patches/2.4/2.4.21-pre7-rmap15i + http://surriel.com/patches/2.4/2.4.21-pre7-rmap15j and http://linuxvm.bkbits.net/ @@ -13,6 +13,11 @@ My big TODO items for a next release are - add pte-highmem defines for more architectures - highmem tweaks +rmap 15j: + - agressive inode reclaim on highmem boxes (me) + - OOM killer tweaks, hopefully better now (me) + - better higher-order page allocations (me) + - small updates and tweaks rmap 15i: - drop behind only drops really new pages (Arjan van de Ven) - lots of VM tuning left and right (Arjan, Ingo, me) diff -Naurp linux-2.4.20-wolk4.1s/Documentation/Configure.help linux-2.4.20-wolk4.2-fullkernel/Documentation/Configure.help --- linux-2.4.20-wolk4.1s/Documentation/Configure.help 2003-05-20 09:56:53.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/Documentation/Configure.help 2003-06-05 23:30:41.000000000 +0200 @@ -1388,23 +1388,6 @@ CONFIG_X86_UP_APIC If you have a system with several CPUs, you do not need to say Y here: the local APIC will be used automatically. -Try to reclaim buffers under memory pressure -CONFIG_RMAP_BUFFER_RECLAIM - If you have memory pressure on your machine, especially with highmem - machines, Linux uses almost all of its memory for buffers. This is - horribly braindamaged, thus you are wasting your memory only for buffers - where the memory is better needed for something else. - - With this option turned on, the VM (rmap) tries to reclaim buffers - under memory pressure so your applications won't suffer any shortage - of memory because the buffers gets freed. - - It is safe to say Y here, however, if you are just using this kernel - for your desktop and don't expect any memory pressure nor you have any - application which needs tons of memory, say N here. - - If unsure, say Y. - Preemptible Kernel CONFIG_PREEMPT This option reduces the latency of the kernel when reacting to @@ -1488,6 +1471,13 @@ CONFIG_HZ this back to 100 and try again. You can also try using HZ=200. This should work ok. + + --------------------------------------------------------------- + For all of you unbelievers out there: Use 200 HZ if you want to + compare -ck with -wolk. Otherwise you'll comparing apples with + elephants! - So make up your mind first! + --------------------------------------------------------------- + If unsure, leave the default 100. Memory eXpansion Technology (MXT) Support @@ -2248,15 +2238,23 @@ CONFIG_BLK_DEV_ELEVATOR_LOWLAT recommended to say Y here. With this option set, you can have reasonable I/O throughput and still have interactive behaviour of your kernel without stops or pauses during heavy IO. - This decreases throughput slightly (~40%), but this is + This decreases throughput slightly (~20%), but this is irrelevant for most desktop usage. + --------------------------------------------------------------- + For all of you unbelievers out there: This setting is the SAME + as -ck uses with its 'Desktop Tuning patches'. So if you want + to compare -ck with -wolk, select this option. Otherwise you'll + comparing apples with elephants! - So make up your mind first! + --------------------------------------------------------------- + + For the interested ones: ------------------------ nr_requests: 32 - read_passovers: 0 - write_passovers: 0 - max_bomb_segments: 1 + read_passovers: 128 + write_passovers: 256 + max_bomb_segments: 2 bdflush: 30/50, 500, 0, 0, 5*HZ, 30*HZ, 60, 20, 0 You can, for sure, lower the latency much more but you'll experience @@ -4785,173 +4783,6 @@ CONFIG_IP_NF_COMPAT_IPFWADM If you want to compile it as a module, say M here and read . If unsure, say `N'. -IP: virtual server support -CONFIG_IP_VS - IP Virtual Server support will let you build a high-performance - virtual server based on cluster of two or more real servers. This - option must be enabled for at least one of the clustered computers - that will take care of intercepting incomming connections to a - single IP address and scheduling them to real servers. - - Three request dispatching techniques are implemented, they are - virtual server via NAT, virtual server via tunneling and virtual - server via direct routing. The several scheduling algorithms can - be used to choose which server the connection is directed to, - thus load balancing can be achieved among the servers. For more - information and its administration program, please visit the - following URL: - http://www.linuxvirtualserver.org/ - - If you want to compile it in kernel, say Y. If you want to compile - it as a module, say M here and read Documentation/modules.txt. If - unsure, say N. - -IP virtual server debugging -CONFIG_IP_VS_DEBUG - Say Y here if you want to get additional messages useful in - debugging the IP virtual server code. You can change the debug - level in /proc/sys/net/ipv4/vs/debug_level - -IPVS connection hash table size (the Nth power of 2) -CONFIG_IP_VS_TAB_BITS - The IPVS connection hash table uses the chaining scheme to handle - hash collisions. Using a big IPVS connection hash table will greatly - reduce conflicts when there are hundreds of thousands of connections - in the hash table. - - Note the table size must be power of 2. The table size will be the - value of 2 to the your input number power. The number to choose is - from 8 to 20, the default number is 12, which means the table size - is 4096. Don't input the number too small, otherwise you will lose - performance on it. You can adapt the table size yourself, according - to your virtual server application. It is good to set the table size - not far less than the number of connections per second multiplying - average lasting time of connection in the table. For example, your - virtual server gets 200 connections per second, the connection lasts - for 200 seconds in average in the connection table, the table size - should be not far less than 200x200, it is good to set the table - size 32768 (2**15). - - Another note that each connection occupies 128 bytes effectively and - each hash entry uses 8 bytes, so you can estimate how much memory is - needed for your box. - -IPVS: round-robin scheduling -CONFIG_IP_VS_RR - The robin-robin scheduling algorithm simply directs network - connections to different real servers in a round-robin manner. - - If you want to compile it in kernel, say Y. If you want to compile - it as a module, say M here and read Documentation/modules.txt. If - unsure, say N. - -IPVS: weighted round-robin scheduling -CONFIG_IP_VS_WRR - The weighted robin-robin scheduling algorithm directs network - connections to different real servers based on server weights - in a round-robin manner. Servers with higher weights receive - new connections first than those with less weights, and servers - with higher weights get more connections than those with less - weights and servers with equal weights get equal connections. - - If you want to compile it in kernel, say Y. If you want to compile - it as a module, say M here and read Documentation/modules.txt. If - unsure, say N. - -IPVS: least-connection scheduling -CONFIG_IP_VS_LC - The least-connection scheduling algorithm directs network - connections to the server with the least number of active - connections. - - If you want to compile it in kernel, say Y. If you want to compile - it as a module, say M here and read Documentation/modules.txt. If - unsure, say N. - -IPVS: weighted least-connection scheduling -CONFIG_IP_VS_WLC - The weighted least-connection scheduling algorithm directs network - connections to the server with the least active connections - normalized by the server weight. - - If you want to compile it in kernel, say Y. If you want to compile - it as a module, say M here and read Documentation/modules.txt. If - unsure, say N. - -IPVS: locality-based least-connection scheduling -CONFIG_IP_VS_LBLC - The locality-based least-connection scheduling algorithm is for - destination IP load balancing. It is usually used in cache cluster. - This algorithm usually directs packet destined for an IP address to - its server if the server is alive and under load. If the server is - overloaded (its active connection numbers is larger than its weight) - and there is a server in its half load, then allocate the weighted - least-connection server to this IP address. - - If you want to compile it in kernel, say Y. If you want to compile - it as a module, say M here and read Documentation/modules.txt. If - unsure, say N. - -IPVS: locality-based least-connection with replication scheduling -CONFIG_IP_VS_LBLCR - The locality-based least-connection with replication scheduling - algorithm is also for destination IP load balancing. It is - usually used in cache cluster. It differs from the LBLC scheduling - as follows: the load balancer maintains mappings from a target - to a set of server nodes that can serve the target. Requests for - a target are assigned to the least-connection node in the target's - server set. If all the node in the server set are over loaded, - it picks up a least-connection node in the cluster and adds it - in the sever set for the target. If the server set has not been - modified for the specified time, the most loaded node is removed - from the server set, in order to avoid high degree of replication. - - If you want to compile it in kernel, say Y. If you want to compile - it as a module, say M here and read Documentation/modules.txt. If - unsure, say N. - -IPVS: destination hashing scheduling -CONFIG_IP_VS_DH - The destination hashing scheduling algorithm assigns network - connections to the servers through looking up a statically assigned - hash table by their destination IP addresses. - - If you want to compile it in kernel, say Y. If you want to compile - it as a module, say M here and read Documentation/modules.txt. If - unsure, say N. - -IPVS: source hashing scheduling -CONFIG_IP_VS_SH - The source hashing scheduling algorithm assigns network - connections to the servers through looking up a statically assigned - hash table by their source IP addresses. - - If you want to compile it in kernel, say Y. If you want to compile - it as a module, say M here and read Documentation/modules.txt. If - unsure, say N. - -IPVS: FTP protocol helper -CONFIG_IP_VS_FTP - FTP is a protocol that transfers IP address and/or port number in - the payload. In the virtual server via Network Address Translation, - the IP address and port number of real servers cannot be sent to - clients in ftp connections directly, so FTP protocol helper is - required for tracking the connection and mangling it back to that of - virtual service. - - If you want to compile it in kernel, say Y. If you want to compile - it as a module, say M here and read Documentation/modules.txt. If - unsure, say N. - -FTP protocol support -CONFIG_IP_VS_FTP - Tracking FTP connections is problematic: special helpers are - required for tracking them, and doing masquerading and other forms - of Network Address Translation on them. - - If you want to compile it as a module, say M here and read - Documentation/modules.txt. If unsure, say `Y'. - EUI64 address check (EXPERIMENTAL) CONFIG_IP6_NF_MATCH_EUI64 This module performs checking on the IPv6 source address @@ -5174,6 +5005,190 @@ CONFIG_IP6_NF_TARGET_LOG If you want to compile it as a module, say M here and read . If unsure, say `N'. +IP: virtual server support +CONFIG_IP_VS + IP Virtual Server support will let you build a high-performance + virtual server based on cluster of two or more real servers. This + option must be enabled for at least one of the clustered computers + that will take care of intercepting incomming connections to a + single IP address and scheduling them to real servers. + + Three request dispatching techniques are implemented, they are + virtual server via NAT, virtual server via tunneling and virtual + server via direct routing. The several scheduling algorithms can + be used to choose which server the connection is directed to, + thus load balancing can be achieved among the servers. For more + information and its administration program, please visit the + following URL: + http://www.linuxvirtualserver.org/ + + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. If + unsure, say N. + +IP virtual server debugging +CONFIG_IP_VS_DEBUG + Say Y here if you want to get additional messages useful in + debugging the IP virtual server code. You can change the debug + level in /proc/sys/net/ipv4/vs/debug_level + +IPVS connection hash table size (the Nth power of 2) +CONFIG_IP_VS_TAB_BITS + The IPVS connection hash table uses the chaining scheme to handle + hash collisions. Using a big IPVS connection hash table will greatly + reduce conflicts when there are hundreds of thousands of connections + in the hash table. + + Note the table size must be power of 2. The table size will be the + value of 2 to the your input number power. The number to choose is + from 8 to 20, the default number is 12, which means the table size + is 4096. Don't input the number too small, otherwise you will lose + performance on it. You can adapt the table size yourself, according + to your virtual server application. It is good to set the table size + not far less than the number of connections per second multiplying + average lasting time of connection in the table. For example, your + virtual server gets 200 connections per second, the connection lasts + for 200 seconds in average in the connection table, the table size + should be not far less than 200x200, it is good to set the table + size 32768 (2**15). + + Another note that each connection occupies 128 bytes effectively and + each hash entry uses 8 bytes, so you can estimate how much memory is + needed for your box. + +IPVS: round-robin scheduling +CONFIG_IP_VS_RR + The robin-robin scheduling algorithm simply directs network + connections to different real servers in a round-robin manner. + + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. If + unsure, say N. + +IPVS: weighted round-robin scheduling +CONFIG_IP_VS_WRR + The weighted robin-robin scheduling algorithm directs network + connections to different real servers based on server weights + in a round-robin manner. Servers with higher weights receive + new connections first than those with less weights, and servers + with higher weights get more connections than those with less + weights and servers with equal weights get equal connections. + + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. If + unsure, say N. + +IPVS: least-connection scheduling +CONFIG_IP_VS_LC + The least-connection scheduling algorithm directs network + connections to the server with the least number of active + connections. + + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. If + unsure, say N. + +IPVS: weighted least-connection scheduling +CONFIG_IP_VS_WLC + The weighted least-connection scheduling algorithm directs network + connections to the server with the least active connections + normalized by the server weight. + + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. If + unsure, say N. + +IPVS: locality-based least-connection scheduling +CONFIG_IP_VS_LBLC + The locality-based least-connection scheduling algorithm is for + destination IP load balancing. It is usually used in cache cluster. + This algorithm usually directs packet destined for an IP address to + its server if the server is alive and under load. If the server is + overloaded (its active connection numbers is larger than its weight) + and there is a server in its half load, then allocate the weighted + least-connection server to this IP address. + + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. If + unsure, say N. + +IPVS: locality-based least-connection with replication scheduling +CONFIG_IP_VS_LBLCR + The locality-based least-connection with replication scheduling + algorithm is also for destination IP load balancing. It is + usually used in cache cluster. It differs from the LBLC scheduling + as follows: the load balancer maintains mappings from a target + to a set of server nodes that can serve the target. Requests for + a target are assigned to the least-connection node in the target's + server set. If all the node in the server set are over loaded, + it picks up a least-connection node in the cluster and adds it + in the sever set for the target. If the server set has not been + modified for the specified time, the most loaded node is removed + from the server set, in order to avoid high degree of replication. + + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. If + unsure, say N. + +IPVS: destination hashing scheduling +CONFIG_IP_VS_DH + The destination hashing scheduling algorithm assigns network + connections to the servers through looking up a statically assigned + hash table by their destination IP addresses. + + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. If + unsure, say N. + +IPVS: source hashing scheduling +CONFIG_IP_VS_SH + The source hashing scheduling algorithm assigns network + connections to the servers through looking up a statically assigned + hash table by their source IP addresses. + + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. If + unsure, say N. + +IPVS: shortest expected delay scheduling +CONFIG_IP_VS_SED + The shortest expected delay scheduling algorithm assigns network + connections to the server with the shortest expected delay. The + expected delay that the job will experience is (Ci + 1) / Ui if + sent to the ith server, in which Ci is the number of connections + on the the ith server and Ui is the fixed service rate (weight) + of the ith server. + + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. If + unsure, say N. + +IPVS: never queue scheduling +CONFIG_IP_VS_NQ + The never queue scheduling algorithm adopts a two-speed model. + When there is an idle server available, the job will be sent to + the idle server, instead of waiting for a fast one. When there + is no idle server available, the job will be sent to the server + that minimize its expected delay (The Shortest Expected Delay + scheduling algorithm). + + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. If + unsure, say N. + +IPVS: FTP protocol helper +CONFIG_IP_VS_FTP + FTP is a protocol that transfers IP address and/or port number in + the payload. In the virtual server via Network Address Translation, + the IP address and port number of real servers cannot be sent to + clients in ftp connections directly, so FTP protocol helper is + required for tracking the connection and mangling it back to that of + virtual service. + + If you want to compile it in kernel, say Y. If you want to compile + it as a module, say M here and read Documentation/modules.txt. If + unsure, say N. + SYN flood protection CONFIG_SYN_COOKIES Normal TCP/IP networking is open to an attack known as "SYN @@ -5775,6 +5790,14 @@ CONFIG_AGP_SWORKS Say Y here to support the Serverworks AGP card. See for product descriptions and images. +NVIDIA chipset support +CONFIG_AGP_NVIDIA + This option gives you AGP support for the GLX component of the + XFree86 4.x on NVIDIA nForce/nForce2 chipsets. + + You should say Y here if you use XFree86 3.3.6 or 4.x and want to + use GLX or DRI. If unsure, say N. + ALI chipset support CONFIG_AGP_ALI This option gives you AGP support for the GLX component of the @@ -6352,7 +6375,7 @@ CONFIG_SCHED_SERVER To name them here: min_timeslice = (10 * HZ) / 1000; - max_timeslice = (300 * HZ) / 1000; + max_timeslice = (200 * HZ) / 1000; child_penalty = 50; parent_penalty = 100; prio_bonus_ratio = 25; @@ -11011,6 +11034,18 @@ CONFIG_SCSI_IZIP_SLOW_CTR Generally, saying N is fine. +SCSI MONITOR support +CONFIG_CHR_DEV_SM + This driver provides a SCSI hotplug agent with information about + comings and goings in the SCSI subsystem. Lists of attached and + recently detached devices as well as a host list are available. + + If you want to compile this as a module ( = code which can be + inserted in and removed from the running kernel whenever you want), + say M here and read Documentation/modules.txt and + Documentation/scsi.txt. The module will be called scsimon.o. + If unsure, say N. + SCSI debugging host simulator CONFIG_SCSI_DEBUG This is a host adapter simulator that can be programmed to simulate @@ -24952,6 +24987,8 @@ CONFIG_BLUEZ HCI Device drivers (interface to the hardware) L2CAP Module (L2CAP protocol) SCO Module (SCO links) + RFCOMM Module (RFCOMM protocol) + BNEP Module (BNEP protocol) Say Y here to enable Linux Bluetooth support and to build BlueZ Core layer. @@ -24980,6 +25017,19 @@ CONFIG_BLUEZ_SCO Say Y here to compile SCO support into the kernel or say M to compile it as module (sco.o). +RFCOMM protocol support +CONFIG_BLUEZ_RFCOMM + RFCOMM provides connection oriented stream transport. RFCOMM + support is required for Dialup Networking, OBEX and other Bluetooth + applications. + + Say Y here to compile RFCOMM support into the kernel or say M to + compile it as module (rfcomm.o). + +RFCOMM TTY emulation support +CONFIG_BLUEZ_RFCOMM_TTY + This option enables TTY emulation support for RFCOMM channels. + BNEP protocol support CONFIG_BLUEZ_BNEP BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet @@ -24993,6 +25043,14 @@ CONFIG_BLUEZ_BNEP Say Y here to compile BNEP support into the kernel or say M to compile it as module (bnep.o). +BNEP multicast filter support +CONFIG_BLUEZ_BNEP_MC_FILTER + This option enables the multicast filter support for BNEP. + +BNEP protocol filter support +CONFIG_BLUEZ_BNEP_PROTO_FILTER + This option enables the protocol filter support for BNEP. + HCI UART driver CONFIG_BLUEZ_HCIUART Bluetooth HCI UART driver. @@ -25007,11 +25065,26 @@ CONFIG_BLUEZ_HCIUART HCI UART (H4) protocol support CONFIG_BLUEZ_HCIUART_H4 UART (H4) is serial protocol for communication between Bluetooth - device and host. This protocol is required for most UART based - Bluetooth device (including PCMCIA and CF). + device and host. This protocol is required for most Bluetooth devices + with UART interface, including PCMCIA and CF cards. Say Y here to compile support for HCI UART (H4) protocol. +HCI BCSP protocol support +CONFIG_BLUEZ_HCIUART_BCSP + BCSP (BlueCore Serial Protocol) is serial protocol for communication + between Bluetooth device and host. This protocol is required for non + USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and + CF cards. + + Say Y here to compile support for HCI BCSP protocol. + +HCI BCSP transmit CRC with every BCSP packet +CONFIG_BLUEZ_HCIUART_BCSP_TXCRC + If you say Y here, a 16-bit CRC checksum will be transmitted along with + every BCSP (BlueCore Serial Protocol) packet sent to the Bluetooth chip. + This increases reliability, but slightly reduces efficiency. + HCI USB driver CONFIG_BLUEZ_HCIUSB Bluetooth HCI USB driver. @@ -25021,12 +25094,21 @@ CONFIG_BLUEZ_HCIUSB Say Y here to compile support for Bluetooth USB devices into the kernel or say M to compile it as module (hci_usb.o). +HCI USB SCO (voice) support +CONFIG_BLUEZ_USB_SCO + This option enables the SCO support in the HCI USB driver. You need this + to transmit voice data with your Bluetooth USB device. And your device + must also support sending SCO data over the HCI layer, because some of + them sends the SCO data to an internal PCM adapter. + + Say Y here to compile support for HCI SCO data. + HCI USB zero packet support CONFIG_BLUEZ_USB_ZERO_PACKET - Support for USB zero packets. This option is provided only as a work around for buggy Bluetooth USB - devices. Do _not_ enable it unless you know for sure that your device + devices. Do NOT enable it unless you know for sure that your device requires zero packets. + Most people should say N here. HCI VHCI Virtual HCI device driver @@ -25073,6 +25155,20 @@ CONFIG_BLUEZ_HCIBLUECARD Say Y here to compile support for HCI BlueCard devices into the kernel or say M to compile it as module (bluecard_cs.o). +HCI UART (PC Card) device driver +CONFIG_BLUEZ_HCIBTUART + Bluetooth HCI UART (PC Card) driver. + This driver provides support for Bluetooth PCMCIA devices with + an UART interface: + Xircom CreditCard Bluetooth Adapter + Xircom RealPort2 Bluetooth Adapter + Sphinx PICO Card + H-Soft blue+Card + Cyber-blue Compact Flash Card + + Say Y here to compile support for HCI UART devices into the + kernel or say M to compile it as module (btuart_cs.o). + # The following options are for Linux when running on the Hitachi # SuperH family of RISC microprocessors. diff -Naurp linux-2.4.20-wolk4.1s/Documentation/fb/vesafb.txt linux-2.4.20-wolk4.2-fullkernel/Documentation/fb/vesafb.txt --- linux-2.4.20-wolk4.1s/Documentation/fb/vesafb.txt 2000-07-28 21:50:51.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/Documentation/fb/vesafb.txt 2003-06-02 17:21:08.000000000 +0200 @@ -146,6 +146,11 @@ pmipal Use the protected mode interface mtrr setup memory type range registers for the vesafb framebuffer. +vram:n remap 'n' MiB of video RAM. If 0 or not specified, remap memory + according to video mode. (2.5.66 patch/idea by Antonino Daplas + reversed to give override possibility (allocate more fb memory + than the kernel would) to 2.4 by tmb@iki.fi) + Have fun! diff -Naurp linux-2.4.20-wolk4.1s/Documentation/kernel-parameters.txt linux-2.4.20-wolk4.2-fullkernel/Documentation/kernel-parameters.txt --- linux-2.4.20-wolk4.1s/Documentation/kernel-parameters.txt 2003-05-15 21:52:18.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/Documentation/kernel-parameters.txt 2003-06-02 17:20:59.000000000 +0200 @@ -16,6 +16,7 @@ restrictions referred to are that the re AX25 Appropriate AX.25 support is enabled. BADMEM Support for faulty RAM chips is enabled (successor of BadRAM). CD Appropriate CD support is enabled. + CPUFREQ Appropriate cpufreq driver is enabled DEVFS devfs support is enabled. DRM Direct Rendering Management support is enabled. EFI EFI Partitioning (GPT) is enabled @@ -584,6 +585,11 @@ running once the system is up. specialix= [HW,SERIAL] Specialix multi-serial port adapter. + speedstep_default= [CPUFREQ,SPEEDSTEP] Force cpufreq to specific + speed, integer from include/linux/cpufreq.h + CPUFREQ_POLICY_* (CPUFREQ_POLICY_GOVERNOR not + supported) + sscape= [HW,SOUND] st= [HW,SCSI] SCSI tape parameters (buffers, etc.). diff -Naurp linux-2.4.20-wolk4.1s/Makefile linux-2.4.20-wolk4.2-fullkernel/Makefile --- linux-2.4.20-wolk4.1s/Makefile 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/Makefile 2003-06-02 17:24:46.000000000 +0200 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 20 -EXTRAVERSION = -wolk4.1s +EXTRAVERSION = -wolk4.2s KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -Naurp linux-2.4.20-wolk4.1s/REPORTING-BUGS linux-2.4.20-wolk4.2-fullkernel/REPORTING-BUGS --- linux-2.4.20-wolk4.1s/REPORTING-BUGS 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/REPORTING-BUGS 2003-06-02 17:32:11.000000000 +0200 @@ -60,7 +60,11 @@ WOLK SPECIFIC OR IN OTHER WORDS: THE RIG 19. Every other bug report without enough informations will be deleted! -20. Read below too! +20. Does your problem occur with 2.4.20 vanilla? If not, use the _same_ + .config for your WOLK tree and try again. If the problem persists, + then tell me. + +21. Read below too! diff -Naurp linux-2.4.20-wolk4.1s/TODO linux-2.4.20-wolk4.2-fullkernel/TODO --- linux-2.4.20-wolk4.1s/TODO 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/TODO 2003-06-04 02:09:37.000000000 +0200 @@ -0,0 +1,7 @@ + in the O(1) page launder code pages being swapped out need to go in this order: +<-- matt_ has quit (Client Quit) + inactive dirty ----> inactive laundry ----> inactive clean + meaning that when IO is scheduled they go to the laundry list + and when IO is finished, they need to go to the clean list + this also means that the laundry balancing code needs to be able to deal properly with pages on which IO has finished + I have a feeling it's not quite correct yet ... diff -Naurp linux-2.4.20-wolk4.1s/VERSION linux-2.4.20-wolk4.2-fullkernel/VERSION --- linux-2.4.20-wolk4.1s/VERSION 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/VERSION 2003-06-02 17:24:44.000000000 +0200 @@ -1 +1 @@ -WOLK v4.1s "Server Edition" FINAL, based on 2.4.20 +WOLK v4.2s "Server Edition" FINAL, based on 2.4.20 diff -Naurp linux-2.4.20-wolk4.1s/WOLK-CHANGELOG linux-2.4.20-wolk4.2-fullkernel/WOLK-CHANGELOG --- linux-2.4.20-wolk4.1s/WOLK-CHANGELOG 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/WOLK-CHANGELOG 2003-06-05 22:58:20.000000000 +0200 @@ -1,3 +1,61 @@ +Changelog from v4.1s -> v4.2s +----------------------------- +o re-add: Scheduler Tunables (/proc/sys/sched): I need it! +o add: SCSI monitoring support +o add: Parallel Port SCSI adapters +o add: RFCOMM protocol support +o add: an hook to trigger a rescan of the scsi devices + echo "scsi scan-new-devices" >/proc/scsi/scsi ++ fixed: 3com 3c90x wrong module init/exit stuff +o fixed: RMAP: better higher-order page allocation +o fixed: RMAP: OOM tweak +o fixed: RMAP: minor smp fix backported from 2.5 +o fixed: RMAP: agressive inode reclaim when we're low on low memory + and inodes are taking up lots of low memory. +o fixed: RMAP: O(1) page launder bug fix, free buffer heads instead + of reactivating the page +o fixed: RMAP: if we can't clear page->buffers but the page wasn't + locked, move it back to the inactive_dirty list +o fixed: RMAP: OOM killer braindamage fix fix +o fixed: RMAP: potential infinite loop in inode pruning +o fixed: ext3fs deadlock using journal_create while mount +o fixed: race in search_exception_table() (Module stuff) +o fixed: erroneous fsync on last opener at close() +o fixed: long outstanding bug (15 months) that will make your mouse hang, + keyboard stuck, no possibility to work with your desktop while + high disk i/o. +o fixed: blk-atomic + varyio wasn't right in its first version, the + refile had to be a few lines below +o fixed: race between truncate and the page faults +o fixed: wrong DeviceMapper stuff which was left from dcache-fastwalk :( +o fixed: IOPERM system call I/O port access vulnerability fix +o fixed: AIC7xxx gcc v3.3.x compile errors ++ fixed: USB storage problems +o fixed: 'make xconfig' always sets CONFIG_ATM to y +o fixed: UP set_task_state and set_current_state to ensure that we don't + re-order loads around the store for setting task->state. +o fixed: sys_munmap for a mapping near the end of the physical address + space frees pages still in use +o fixed: TIOCCONS +o fixed: writing to /dev/console returns ESPIPE +o fixed: vmalloc increase for 128MB frame buffer with VESA fb driver +o fixed: non-working APIC on SiS chipsets +o fixed: eepro100 DoS attack and after that, the card is dead +o fixed: SG side effect introduced by last "off by one" fix +o updated: rmap VM v15j +o updated: eepro100 PCI IDs +o updated: NVIDIA chipset support (nForce/nForce2) +o updated: HostAP driver v0.03 +o updated: AIC7xxx v6.2.36 / AIC79xx v1.3.10 (v2003-06-03) +o updated: IPVS v1.0.9 +o updated: Encrypted Virtual File System (EVFS) v0.3 +o updated: Super FreeS/WAN v1.99.7.2 Final +o changed: make ksoftirqd cpuid match 2.5 +o changed: make migration id match 2.5 +o changed: sync wakeup on UP too like SMP has +o removed: gcc 3.3* inlining bug fix. gcc 3.3 does this correct now + + Changelog from v4.0s -> v4.1s ----------------------------- o fixed: hashing exploits in ipv4 routing, IP conntrack, and TCP synq diff -Naurp linux-2.4.20-wolk4.1s/WOLK-README linux-2.4.20-wolk4.2-fullkernel/WOLK-README --- linux-2.4.20-wolk4.1s/WOLK-README 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/WOLK-README 2003-06-03 13:33:34.000000000 +0200 @@ -1,4 +1,4 @@ -Kernel - patched - WOLK v4.1s - Base: Linux kernel 2.4.20 +Kernel - patched - WOLK v4.2s - Base: Linux kernel 2.4.20 located at http://sf.net/projects/wolk by Marc-Christian Petersen -------------------------------------------------------------------------- diff -Naurp linux-2.4.20-wolk4.1s/arch/all/Config-TWEAKS.in linux-2.4.20-wolk4.2-fullkernel/arch/all/Config-TWEAKS.in --- linux-2.4.20-wolk4.1s/arch/all/Config-TWEAKS.in 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/all/Config-TWEAKS.in 2003-06-04 01:30:02.000000000 +0200 @@ -33,12 +33,6 @@ if [ "$CONFIG_X86" = "y" -o "$CONFIG_ARM fi -# RMAP -if [ "$CONFIG_NOHIGHMEM" = "n" ]; then - bool 'RMAP: Try to reclaim buffers under memory pressure' CONFIG_RMAP_BUFFER_RECLAIM -fi - - # Memory Pools bool 'Enable Memory Pools' CONFIG_MEMORYPOOL if [ "$CONFIG_MEMORYPOOL" = "n" ]; then diff -Naurp linux-2.4.20-wolk4.1s/arch/i386/Makefile linux-2.4.20-wolk4.2-fullkernel/arch/i386/Makefile --- linux-2.4.20-wolk4.1s/arch/i386/Makefile 2003-05-15 21:52:19.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/i386/Makefile 2003-06-02 17:24:45.000000000 +0200 @@ -141,7 +141,7 @@ endif MAKEBOOT = $(MAKE) -C arch/$(ARCH)/boot arch/i386/vmlinux.lds: arch/i386/vmlinux.lds.S FORCE - $(CPP) -C -P -I$(HPATH) -imacros $(HPATH)/asm-i386/page_offset.h -Ui386 arch/i386/vmlinux.lds.S >arch/i386/vmlinux.lds + $(CPP) -C -P -I$(HPATH) -imacros $(HPATH)/linux/config.h -imacros $(HPATH)/asm-i386/segment.h -imacros $(HPATH)/asm-i386/page_offset.h -Ui386 arch/i386/vmlinux.lds.S >arch/i386/vmlinux.lds vmlinux: arch/i386/vmlinux.lds diff -Naurp linux-2.4.20-wolk4.1s/arch/i386/defconfig linux-2.4.20-wolk4.2-fullkernel/arch/i386/defconfig --- linux-2.4.20-wolk4.1s/arch/i386/defconfig 2003-05-15 21:52:19.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/i386/defconfig 2003-06-02 17:24:31.000000000 +0200 @@ -673,6 +673,7 @@ CONFIG_AGP_AMD=y CONFIG_AGP_AMD_8151=y CONFIG_AGP_SIS=y CONFIG_AGP_ALI=y +CONFIG_AGP_NVIDIA=y CONFIG_AGP_SWORKS=y # diff -Naurp linux-2.4.20-wolk4.1s/arch/i386/kernel/apm.c linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/apm.c --- linux-2.4.20-wolk4.1s/arch/i386/kernel/apm.c 2003-05-15 21:52:19.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/apm.c 2003-06-02 17:20:59.000000000 +0200 @@ -614,7 +614,7 @@ static u8 apm_bios_call(u32 func, u32 eb __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" - "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" + "lcall *%%ss:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" "setc %%al\n\t" "popl %%ebp\n\t" "popl %%edi\n\t" @@ -666,7 +666,7 @@ static u8 apm_bios_call_simple(u32 func, __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" - "lcall %%cs:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" + "lcall *%%ss:" SYMBOL_NAME_STR(apm_bios_entry) "\n\t" "setc %%bl\n\t" "popl %%ebp\n\t" "popl %%edi\n\t" diff -Naurp linux-2.4.20-wolk4.1s/arch/i386/kernel/entry.S linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/entry.S --- linux-2.4.20-wolk4.1s/arch/i386/kernel/entry.S 2003-05-15 21:52:19.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/entry.S 2003-06-02 17:32:11.000000000 +0200 @@ -822,7 +822,7 @@ ENTRY(sys_call_table) .long SYMBOL_NAME(sys_ni_syscall) /* 250 sys_alloc_hugepages */ .long SYMBOL_NAME(sys_ni_syscall) /* sys_free_hugepages */ .long SYMBOL_NAME(sys_ni_syscall) /* sys_exit_group */ - .long SYMBOL_NAME(sys_sched_hint) + .long SYMBOL_NAME(sys_ni_syscall) .long SYMBOL_NAME(sys_epoll_create) .long SYMBOL_NAME(sys_epoll_ctl) /* 255 sys_epoll_ctl */ .long SYMBOL_NAME(sys_epoll_wait) diff -Naurp linux-2.4.20-wolk4.1s/arch/i386/kernel/io_apic.c linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/io_apic.c --- linux-2.4.20-wolk4.1s/arch/i386/kernel/io_apic.c 2003-05-15 21:52:19.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/io_apic.c 2003-06-02 17:23:42.000000000 +0200 @@ -49,6 +49,11 @@ static spinlock_t ioapic_lock = SPIN_LOC unsigned int int_dest_addr_mode = APIC_DEST_LOGICAL; unsigned char int_delivery_mode = dest_LowestPrio; +/* + * Is the SiS APIC rmw bug present ? + * -1 = don't know, 0 = no, 1 = yes + */ +int sis_apic_bug = -1; /* * # of IRQ routing registers @@ -129,7 +134,7 @@ static void __init replace_pin_at_irq(un break; \ reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ reg ACTION; \ - io_apic_modify(entry->apic, reg); \ + io_apic_modify(entry->apic, 0x10 + R + pin*2, reg); \ if (!entry->next) \ break; \ entry = irq_2_pin + entry->next; \ @@ -222,13 +227,18 @@ extern unsigned long irq_affinity [NR_IR #define IRQ_ALLOWED(cpu,allowed_mask) \ ((1UL << cpu) & (allowed_mask)) +#define ksoftirqd_is_running(phys_id) (cpu_curr(phys_id) == ksoftirqd_task(phys_id)) +#define __irq_idle_cpu(phys_id) (idle_cpu(phys_id) || ksoftirqd_is_running(phys_id)) +#define irq_idle_cpu(phys_id) (__irq_idle_cpu(phys_id) && \ + (smp_num_siblings <= 1 || __irq_idle_cpu(cpu_sibling_map[phys_id]))) + static unsigned long move(unsigned int curr_cpu, unsigned long allowed_mask, unsigned long now, int direction) { unsigned int cpu = curr_cpu; unsigned int phys_id; phys_id = cpu_logical_map(cpu); - if (IRQ_ALLOWED(phys_id, allowed_mask) && idle_cpu(phys_id)) + if (IRQ_ALLOWED(phys_id, allowed_mask) && irq_idle_cpu(phys_id)) return cpu; goto inside; @@ -248,7 +258,7 @@ inside: } phys_id = cpu_logical_map(cpu); - } while (!IRQ_ALLOWED(phys_id, allowed_mask) || !idle_cpu(phys_id)); + } while (!IRQ_ALLOWED(phys_id, allowed_mask) || !irq_idle_cpu(phys_id)); return cpu; } @@ -1759,6 +1769,18 @@ void __init setup_IO_APIC(void) print_IO_APIC(); } +/* + * Called after all the initialization is done. If we didnt find any + * APIC bugs then we can allow the modify fast path + */ + +static int __init io_apic_bug_finalize(void) +{ + if(sis_apic_bug == -1) + sis_apic_bug = 0; + return 0; +} +late_initcall(io_apic_bug_finalize); /* -------------------------------------------------------------------------- ACPI-based IOAPIC Configuration diff -Naurp linux-2.4.20-wolk4.1s/arch/i386/kernel/ioport.c linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/ioport.c --- linux-2.4.20-wolk4.1s/arch/i386/kernel/ioport.c 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/ioport.c 2003-06-02 17:22:35.000000000 +0200 @@ -122,9 +122,10 @@ asmlinkage int sys_ioperm(unsigned long if (tss->bitmap == IO_BITMAP_OFFSET) { /* already active? */ set_bitmap(tss->io_bitmap, from, num, !turn_on); } else { - memcpy(tss->io_bitmap, t->io_bitmap, IO_BITMAP_SIZE); + memcpy(tss->io_bitmap, t->io_bitmap, IO_BITMAP_BYTES); tss->bitmap = IO_BITMAP_OFFSET; /* Activate it in the TSS */ } + preempt_enable(); return 0; diff -Naurp linux-2.4.20-wolk4.1s/arch/i386/kernel/process.c linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/process.c --- linux-2.4.20-wolk4.1s/arch/i386/kernel/process.c 2003-05-15 21:52:20.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/process.c 2003-06-02 17:20:58.000000000 +0200 @@ -1045,7 +1045,7 @@ void __switch_to(struct task_struct *pre * is not really acceptable.] */ memcpy(tss->io_bitmap, next->io_bitmap, - IO_BITMAP_SIZE*sizeof(unsigned long)); + IO_BITMAP_BYTES); tss->bitmap = IO_BITMAP_OFFSET; } else /* diff -Naurp linux-2.4.20-wolk4.1s/arch/i386/kernel/speedstep.c linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/speedstep.c --- linux-2.4.20-wolk4.1s/arch/i386/kernel/speedstep.c 2003-05-15 21:52:20.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/speedstep.c 2003-06-02 17:04:21.000000000 +0200 @@ -49,6 +49,7 @@ static struct pci_dev */ static unsigned int speedstep_processor = 0; static int speedstep_coppermine = 0; +static int speedstep_default_speed = 0; #define SPEEDSTEP_PROCESSOR_PIII_C 0x00000001 /* Coppermine core */ #define SPEEDSTEP_PROCESSOR_PIII_T 0x00000002 /* Tualatin core */ @@ -638,11 +639,15 @@ static int speedstep_cpu_init(struct cpu (speed / 1000)); /* cpuinfo and default policy values */ - policy->policy = (speed == speedstep_low_freq) ? - CPUFREQ_POLICY_POWERSAVE : CPUFREQ_POLICY_PERFORMANCE; + if(speedstep_default_speed==0) + policy->policy = (speed == speedstep_low_freq) ? + CPUFREQ_POLICY_POWERSAVE : CPUFREQ_POLICY_PERFORMANCE; + else + policy->policy = speedstep_default_speed; + policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; policy->cur = speed; - + return cpufreq_frequency_table_cpuinfo(policy, &speedstep_freqs[0]); } @@ -663,7 +668,32 @@ static int __init speedstep_setup(char * speedstep_coppermine = simple_strtoul(str, &str, 0); return 1; } + +/** + * speedstep_set_default + * + * Ripped blatantly from the coppermine handling, this is for + * forcing cpufreq to set a specific policy/speed on init. + * + * Coded up for use with swsusp (it gets weird if you suspend at + * one speed and resume at another) but it might be generally useful. + * + * IANAKG so this may be very wrong. + */ +static int __init speedstep_set_default(char *str) +{ + speedstep_default_speed=simple_strtoul(str,&str,0); + if (speedstep_default_speed != CPUFREQ_POLICY_POWERSAVE && + speedstep_default_speed != CPUFREQ_POLICY_PERFORMANCE) { + printk(KERN_INFO "cpufreq: Unknown default: %s\n",str); + speedstep_default_speed=0; + } else + printk(KERN_INFO "cpufreq: Default forced: %s\n", (speedstep_default_speed == CPUFREQ_POLICY_PERFORMANCE) ? "performance" : "powersave"); + return 1; +} + __setup("speedstep_coppermine=", speedstep_setup); +__setup("speedstep_default=", speedstep_set_default); #endif @@ -672,7 +702,7 @@ static struct cpufreq_driver speedstep_d .target = speedstep_target, .init = speedstep_cpu_init, .exit = NULL, - .policy = NULL, + .policy = (speedstep_set_default? speedstep_set_default : NULL), .name = "speedstep", }; @@ -719,7 +749,7 @@ static void __exit speedstep_exit(void) MODULE_PARM (speedstep_coppermine, "i"); - +MODULE_PARM (speedstep_default_speed, "i"); MODULE_AUTHOR ("Dave Jones , Dominik Brodowski "); MODULE_DESCRIPTION ("Speedstep driver for Intel mobile processors."); MODULE_LICENSE ("GPL"); diff -Naurp linux-2.4.20-wolk4.1s/arch/i386/kernel/vm86.c linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/vm86.c --- linux-2.4.20-wolk4.1s/arch/i386/kernel/vm86.c 2003-05-15 21:52:20.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/i386/kernel/vm86.c 2003-06-02 17:23:44.000000000 +0200 @@ -369,6 +369,9 @@ static inline unsigned long get_vflags(s if (VEFLAGS & VIF_MASK) flags |= IF_MASK; + else + flags &= ~IF_MASK; + flags |= IOPL_MASK; return flags | (VEFLAGS & current->thread.v86mask); } diff -Naurp linux-2.4.20-wolk4.1s/arch/i386/mm/init.c linux-2.4.20-wolk4.2-fullkernel/arch/i386/mm/init.c --- linux-2.4.20-wolk4.1s/arch/i386/mm/init.c 2003-05-15 21:52:20.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/i386/mm/init.c 2003-06-02 17:22:35.000000000 +0200 @@ -616,7 +616,7 @@ void free_initmem(void) { unsigned long limit; - limit = ((unsigned long)&_etext + PAGE_SIZE - 1) >> PAGE_SHIFT; + limit = (unsigned long)&_etext >> PAGE_SHIFT; gdt_table[2].a = (gdt_table[2].a & 0xFFFF0000UL) | (limit & 0x0FFFFUL); gdt_table[2].b = (gdt_table[2].b & 0xFFF0FFFFUL) | (limit & 0xF0000UL); diff -Naurp linux-2.4.20-wolk4.1s/arch/i386/vmlinux.lds.S linux-2.4.20-wolk4.2-fullkernel/arch/i386/vmlinux.lds.S --- linux-2.4.20-wolk4.1s/arch/i386/vmlinux.lds.S 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/i386/vmlinux.lds.S 2003-06-02 14:47:40.000000000 +0200 @@ -18,10 +18,6 @@ SECTIONS SHORT(__KERNEL_CS) } - __start___kallsyms = .; /* All kernel symbols */ - __kallsyms : { *(__kallsyms) } - __stop___kallsyms = .; - .data : { /* Data */ *(.data) CONSTRUCTORS @@ -31,9 +27,7 @@ SECTIONS .data.cacheline_aligned : { *(.data.cacheline_aligned) } . = ALIGN(8192); - .data.init_task : { - *(.data.init_task) - } + .data.init_task : { *(.data.init_task) } . = ALIGN(4096); .data.page_aligned : { @@ -77,6 +71,7 @@ SECTIONS } __init_end = . + __KERNEL_TEXT_OFFSET; + /* * PaX: this must be kept in synch with the KERNEL_CS base * in the GDTs in arch/i386/kernel/head.S @@ -94,10 +89,10 @@ SECTIONS *(.text) *(.fixup) *(.gnu.warning) - . = ALIGN(4096); } = 0x9090 _etext = .; /* End of text section */ + . = ALIGN(4096); #ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC . += __KERNEL_TEXT_OFFSET; @@ -116,8 +111,8 @@ SECTIONS __ksymtab : { *(__ksymtab) } __stop___ksymtab = .; - __start___kallsyms = .; /* All kernel symbols */ - __kallsyms : { *(__kallsyms) } + __start___kallsyms = .; /* All kernel symbols */ + __kallsyms : { *(__kallsyms) } __stop___kallsyms = .; #ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC diff -Naurp linux-2.4.20-wolk4.1s/arch/parisc/kernel/sys_parisc32.c linux-2.4.20-wolk4.2-fullkernel/arch/parisc/kernel/sys_parisc32.c --- linux-2.4.20-wolk4.1s/arch/parisc/kernel/sys_parisc32.c 2003-05-15 21:52:20.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/parisc/kernel/sys_parisc32.c 2003-06-02 14:41:51.000000000 +0200 @@ -178,6 +178,11 @@ do_execve32(char * filename, u32 * argv, struct file *file; int retval; int i; +#ifdef CONFIG_GRKERNSEC + struct file *old_exec_file; + struct acl_subject_label *old_acl; + struct rlimit old_rlim[RLIM_NLIMITS]; +#endif file = open_exec(filename); @@ -185,15 +190,6 @@ do_execve32(char * filename, u32 * argv, if (IS_ERR(file)) return retval; -#ifdef CONFIG_GRKERNSEC - if (current->exec_file) { - fput(current->exec_file); - current->exec_file = NULL; - } - get_file(file); - current->exec_file = file; -#endif - gr_learn_resource(current, RLIMIT_NPROC, atomic_read(¤t->user->processes)); if (gr_handle_nproc()) { @@ -209,6 +205,7 @@ do_execve32(char * filename, u32 * argv, } bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); + #ifdef CONFIG_GRKERNSEC_PAX_RANDUSTACK { unsigned short delta; @@ -216,6 +213,7 @@ do_execve32(char * filename, u32 * argv, bprm.p -= (delta & ~(sizeof(void *)-1)) & ~PAGE_MASK; } #endif + memset(bprm.page, 0, MAX_ARG_PAGES*sizeof(bprm.page[0])); DBG(("do_execve32(%s, %p, %p, %p)\n", filename, argv, envp, regs)); @@ -256,8 +254,6 @@ do_execve32(char * filename, u32 * argv, bprm.exec = bprm.p; - gr_set_proc_label(file->f_dentry, file->f_vfsmnt); - gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); retval = copy_strings32(bprm.envc, envp, &bprm); @@ -268,24 +264,38 @@ do_execve32(char * filename, u32 * argv, if (retval < 0) goto out; +#ifdef CONFIG_GRKERNSEC + old_acl = current->acl; + memcpy(old_rlim, current->rlim, sizeof(old_rlim)); + old_exec_file = current->exec_file; + get_file(file); + current->exec_file = file; +#endif + + gr_set_proc_label(file->f_dentry, file->f_vfsmnt); + retval = search_binary_handler(&bprm,regs); - if (retval >= 0) + if (retval >= 0) { +#ifdef CONFIG_GRKERNSEC + if (old_exec_file) + fput(old_exec_file); +#endif /* execve success */ return retval; + } +#ifdef CONFIG_GRKERNSEC + current->acl = old_acl; + memcpy(current->rlim, old_rlim, sizeof(old_rlim)); + fput(current->exec_file); + current->exec_file = old_exec_file; +#endif out: /* Something went wrong, return the inode and free the argument pages*/ allow_write_access(bprm.file); if (bprm.file) fput(bprm.file); -#ifdef CONFIG_GRKERNSEC - if (current->exec_file) { - fput(current->exec_file); - current->exec_file = NULL; - } -#endif - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { struct page * page = bprm.page[i]; if (page) diff -Naurp linux-2.4.20-wolk4.1s/arch/parisc/mm/fault.c linux-2.4.20-wolk4.2-fullkernel/arch/parisc/mm/fault.c --- linux-2.4.20-wolk4.1s/arch/parisc/mm/fault.c 2003-05-15 21:52:20.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/parisc/mm/fault.c 2003-06-02 14:41:51.000000000 +0200 @@ -329,7 +329,8 @@ good_area: #ifdef CONFIG_GRKERNSEC_PAX_PAGEEXEC if ((current->flags & PF_PAX_PAGEEXEC) && (acc_type & VM_EXEC) && - address == instruction_pointer(regs)) { + (address & ~3UL) == instruction_pointer(regs)) + { up_read(&mm->mmap_sem); switch(pax_handle_fetch_fault(regs)) { diff -Naurp linux-2.4.20-wolk4.1s/arch/sparc64/kernel/ioctl32.c linux-2.4.20-wolk4.2-fullkernel/arch/sparc64/kernel/ioctl32.c --- linux-2.4.20-wolk4.1s/arch/sparc64/kernel/ioctl32.c 2003-05-15 21:52:21.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/sparc64/kernel/ioctl32.c 2003-06-03 20:02:49.000000000 +0200 @@ -97,6 +97,7 @@ #include #include +#include #include #include @@ -4367,6 +4368,15 @@ chio_gstatus(unsigned int fd, unsigned i return err; } +/* Bluetooth ioctls */ +#define HCIUARTSETPROTO _IOW('U', 200, int) +#define HCIUARTGETPROTO _IOR('U', 201, int) + +#define BNEPCONNADD _IOW('B', 200, int) +#define BNEPCONNDEL _IOW('B', 201, int) +#define BNEPGETCONNLIST _IOR('B', 210, int) +#define BNEPGETCONNINFO _IOR('B', 211, int) + struct ioctl_trans { unsigned int cmd; unsigned int handler; @@ -5075,6 +5085,17 @@ COMPATIBLE_IOCTL(HCISETLINKMODE) COMPATIBLE_IOCTL(HCISETACLMTU) COMPATIBLE_IOCTL(HCISETSCOMTU) COMPATIBLE_IOCTL(HCIINQUIRY) +COMPATIBLE_IOCTL(HCIUARTSETPROTO) +COMPATIBLE_IOCTL(HCIUARTGETPROTO) +COMPATIBLE_IOCTL(RFCOMMCREATEDEV) +COMPATIBLE_IOCTL(RFCOMMRELEASEDEV) +COMPATIBLE_IOCTL(RFCOMMGETDEVLIST) +COMPATIBLE_IOCTL(RFCOMMGETDEVINFO) +COMPATIBLE_IOCTL(RFCOMMSTEALDLC) +COMPATIBLE_IOCTL(BNEPCONNADD) +COMPATIBLE_IOCTL(BNEPCONNDEL) +COMPATIBLE_IOCTL(BNEPGETCONNLIST) +COMPATIBLE_IOCTL(BNEPGETCONNINFO) /* Misc. */ COMPATIBLE_IOCTL(0x41545900) /* ATYIO_CLKR */ COMPATIBLE_IOCTL(0x41545901) /* ATYIO_CLKW */ @@ -5122,6 +5143,7 @@ COMPATIBLE_IOCTL(CHIOGELEM) COMPATIBLE_IOCTL(CHIOINITELEM) COMPATIBLE_IOCTL(CHIOSVOLTAG) COMPATIBLE_IOCTL(CHIOGVPARAMS) + /* device-mapper */ #if defined(CONFIG_BLK_DEV_DM) || defined(CONFIG_BLK_DEV_DM_MODULE) COMPATIBLE_IOCTL(DM_VERSION) diff -Naurp linux-2.4.20-wolk4.1s/arch/sparc64/kernel/sys_sparc32.c linux-2.4.20-wolk4.2-fullkernel/arch/sparc64/kernel/sys_sparc32.c --- linux-2.4.20-wolk4.1s/arch/sparc64/kernel/sys_sparc32.c 2003-05-15 21:52:21.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/arch/sparc64/kernel/sys_sparc32.c 2003-06-02 14:41:51.000000000 +0200 @@ -3146,6 +3146,11 @@ do_execve32(char * filename, u32 * argv, struct file * file; int retval; int i; +#ifdef CONFIG_GRKERNSEC + struct file *old_exec_file; + struct acl_subject_label *old_acl; + struct rlimit old_rlim[RLIM_NLIMITS]; +#endif bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); @@ -3165,15 +3170,6 @@ do_execve32(char * filename, u32 * argv, if (IS_ERR(file)) return retval; -#ifdef CONFIG_GRKERNSEC - if (current->exec_file) { - fput(current->exec_file); - current->exec_file = NULL; - } - get_file(file); - current->exec_file = file; -#endif - gr_learn_resource(current, RLIMIT_NPROC, atomic_read(¤t->user->processes)); if (gr_handle_nproc()) { @@ -3224,8 +3220,6 @@ do_execve32(char * filename, u32 * argv, bprm.exec = bprm.p; - gr_set_proc_label(file->f_dentry, file->f_vfsmnt); - gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); retval = copy_strings32(bprm.envc, envp, &bprm); @@ -3236,24 +3230,38 @@ do_execve32(char * filename, u32 * argv, if (retval < 0) goto out; +#ifdef CONFIG_GRKERNSEC + old_acl = current->acl; + memcpy(old_rlim, current->rlim, sizeof(old_rlim)); + old_exec_file = current->exec_file; + get_file(file); + current->exec_file = file; +#endif + + gr_set_proc_label(file->f_dentry, file->f_vfsmnt); + retval = search_binary_handler(&bprm, regs); - if (retval >= 0) + if (retval >= 0) { +#ifdef CONFIG_GRKERNSEC + if (old_exec_file) + fput(old_exec_file); +#endif /* execve success */ return retval; + } +#ifdef CONFIG_GRKERNSEC + current->acl = old_acl; + memcpy(current->rlim, old_rlim, sizeof(old_rlim)); + fput(current->exec_file); + current->exec_file = old_exec_file; +#endif out: /* Something went wrong, return the inode and free the argument pages*/ allow_write_access(bprm.file); if (bprm.file) fput(bprm.file); -#ifdef CONFIG_GRKERNSEC - if (current->exec_file) { - fput(current->exec_file); - current->exec_file = NULL; - } -#endif - for (i=0 ; ielevator, (blkelv_ioctl_arg_t *) arg); case BLKELVSET: diff -Naurp linux-2.4.20-wolk4.1s/drivers/block/elevator.c linux-2.4.20-wolk4.2-fullkernel/drivers/block/elevator.c --- linux-2.4.20-wolk4.1s/drivers/block/elevator.c 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/block/elevator.c 2003-06-03 11:15:24.000000000 +0200 @@ -87,8 +87,8 @@ static int rq_mergeable(struct request * return 0; if (req->nr_sectors + count > max_sectors) return 0; -// if (bh_elv_seq(bh) != bh_elv_seq(req->bh)) -// return 0; + if (bh_elv_seq(bh) != bh_elv_seq(req->bh)) + return 0; return 1; } @@ -98,7 +98,7 @@ int elevator_linus_merge(request_queue_t struct buffer_head *bh, int rw, int max_sectors) { - struct list_head *entry; + struct list_head *entry, *real_head; unsigned int count = bh->b_size >> 9; unsigned int ret = ELEVATOR_NO_MERGE; const int max_bomb_segments = q->elevator.max_bomb_segments; @@ -106,7 +106,11 @@ int elevator_linus_merge(request_queue_t int backmerge_only = 0; int passed_a_read = 0; - entry = &q->queue_head; + if (!bh_elv_seq(bh)) + entry = &q->queue_head; + else + entry = &q->atomic_head; + real_head = entry; /* * check last merge hint @@ -130,7 +134,10 @@ int elevator_linus_merge(request_queue_t while (!backmerge_only && (entry = entry->prev) != head) { __rq = blkdev_entry_to_request(entry); - if (__rq->elevator_sequence-- <= 0) { + /* + * we can't insert beyond a zero sequence point + */ + if (__rq->elevator_sequence-- <= 0 && !bh_elv_seq(bh)) { /* * OK, we've exceeded someone's latency limit. * But we still continue to look for merges, @@ -143,7 +150,7 @@ int elevator_linus_merge(request_queue_t continue; if (__rq->rq_dev != bh->b_rdev) continue; - if (!*req && bh_rq_in_between(bh, __rq, &q->queue_head) && !backmerge_only) + if (!*req && bh_rq_in_between(bh, __rq, real_head) && !backmerge_only) *req = __rq; if (__rq->cmd != WRITE) passed_a_read = 1; @@ -151,6 +158,11 @@ int elevator_linus_merge(request_queue_t continue; if (__rq->nr_sectors + count > max_sectors) continue; + /* + * possibly move this inside the merge path and make it a break + */ + if (bh_elv_seq(bh) != bh_elv_seq(__rq->bh)) + continue; if (__rq->sector + __rq->nr_sectors == bh->b_rsector) { /* * Really here we could re-increase the elevator_latency of __rq, @@ -178,7 +190,7 @@ out: int scan_cost = ret ? 1 : ELV_LINUS_SEEK_COST; struct list_head *entry = &(*req)->queue; - while ((entry = entry->next) != &q->queue_head) { + while ((entry = entry->next) != real_head) { __rq = blkdev_entry_to_request(entry); __rq->elevator_sequence -= scan_cost; } @@ -254,13 +266,18 @@ int elevator_noop_merge(request_queue_t struct buffer_head *bh, int rw, int max_sectors) { - struct list_head *entry; + struct list_head *entry, *real_head; unsigned int count = bh->b_size >> 9; - if (list_empty(&q->queue_head)) + if (!bh_elv_seq(bh)) + entry = &q->queue_head; + else + entry = &q->atomic_head; + real_head = entry; + + if (list_empty(real_head)) return ELEVATOR_NO_MERGE; - entry = &q->queue_head; while ((entry = entry->prev) != head) { struct request *__rq = blkdev_entry_to_request(entry); @@ -272,6 +289,11 @@ int elevator_noop_merge(request_queue_t continue; if (__rq->waiting) continue; + /* + * possibly move this inside the merge path and make it a break + */ + if (bh_elv_seq(bh) != bh_elv_seq(__rq->bh)) + continue; if (__rq->sector + __rq->nr_sectors == bh->b_rsector) { *req = __rq; return ELEVATOR_BACK_MERGE; @@ -281,7 +303,7 @@ int elevator_noop_merge(request_queue_t } } - *req = blkdev_entry_to_request(q->queue_head.prev); + *req = blkdev_entry_to_request(real_head->prev); return ELEVATOR_NO_MERGE; } diff -Naurp linux-2.4.20-wolk4.1s/drivers/block/ll_rw_blk.c linux-2.4.20-wolk4.2-fullkernel/drivers/block/ll_rw_blk.c --- linux-2.4.20-wolk4.1s/drivers/block/ll_rw_blk.c 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/block/ll_rw_blk.c 2003-06-04 01:24:08.000000000 +0200 @@ -51,6 +51,8 @@ static kmem_cache_t *request_cachep; */ DECLARE_TASK_QUEUE(tq_disk); +LIST_HEAD(blk_atomic_head); + /* * Protect the request list against multiple users.. * @@ -125,9 +127,63 @@ int * max_sectors[MAX_BLKDEV]; */ char * blkdev_varyio[MAX_BLKDEV]; +/* + * only allow merging of buffer_heads with identical sequence, for transparent + * support for writing atomic blocks larger than what a single bh can hold + */ +static unsigned int blk_atomic_seq; +static spinlock_cacheline_t blk_atomic_lock_cacheline = {SPIN_LOCK_UNLOCKED}; +static spinlock_cacheline_t blk_atomic_queue_lock_cacheline = {SPIN_LOCK_UNLOCKED}; + +#ifdef CONFIG_SMP +struct blk_atomic_cpu { + unsigned int seq; + unsigned int left; +} ____cacheline_aligned_in_smp; + +struct blk_atomic_cpu __cacheline_aligned_in_smp blk_atomic_cpu[NR_CPUS]; + +#define BLK_ATOMIC_SEQ_GRAB 1024 +#endif + unsigned long blk_max_low_pfn, blk_max_pfn; int blk_nohighio = 0; +unsigned int blk_get_atomic_seq(void) +{ + unsigned int ret; + +#ifdef CONFIG_SMP + { + struct blk_atomic_cpu *bcpu = &blk_atomic_cpu[smp_processor_id()]; + +restart: + if (unlikely(!bcpu->left)) { + spin_lock_irq(&blk_atomic_lock); + bcpu->seq = blk_atomic_seq; + blk_atomic_seq += BLK_ATOMIC_SEQ_GRAB; + spin_unlock_irq(&blk_atomic_lock); + bcpu->left = BLK_ATOMIC_SEQ_GRAB; + } + bcpu->seq++; + bcpu->left--; + if (unlikely(!bcpu->seq)) + goto restart; + + ret = bcpu->seq; + } +#else + spin_lock_irq(&blk_atomic_lock); + ret = ++blk_atomic_seq; + if (unlikely(!ret)) { + ret = 1; + ++blk_atomic_seq; + } + spin_unlock_irq(&blk_atomic_lock); +#endif + return ret; +} + static inline int get_max_sectors(kdev_t dev) { if (!max_sectors[MAJOR(dev)]) @@ -390,6 +446,91 @@ void generic_unplug_device(void *data) spin_unlock_irqrestore(q->queue_lock, flags); } +static void blk_atomic_add(request_queue_t *q) +{ + spin_lock_irq(&blk_atomic_queue_lock); + /* it's empty only when it's out of the blk_atomic_head queue */ + if (list_empty(&q->atomic_entry)) + list_add_tail(&q->atomic_entry, &blk_atomic_head); + spin_unlock_irq(&blk_atomic_queue_lock); +} + +static struct list_head *blk_find_insert_point(request_queue_t *q, + struct request *rq) +{ + struct list_head *head = &q->queue_head, *insert = q->queue_head.prev; + struct buffer_head *bh; + int elv_seq; + struct request *dummy; + + if (list_empty(head)) + goto done; + else if (q->head_active && !q->plugged) + head = head->next; + + dummy = NULL; + bh = rq->bh; + + elv_seq = bh_elv_seq(bh); + bh_elv_seq(bh) = 0; + + q->elevator.elevator_merge_fn(q, &dummy, head, bh, + -1 /* non cmd -> no merge */, + 0 /* too small max_sectors -> no merge */); + + bh_elv_seq(bh) = elv_seq; + + if (dummy) + insert = &dummy->queue; + +done: + return insert; +} + +void blk_refile_atomic_queue(int sequence) +{ + request_queue_t *q; + struct request * rq; + unsigned long flags; + struct list_head * q_entry, * rq_entry; + int __sequence; + + spin_lock_irqsave(&blk_atomic_queue_lock, flags); + + q_entry = blk_atomic_head.next; + while (q_entry != &blk_atomic_head) { + q = list_entry(q_entry, request_queue_t, atomic_entry); + q_entry = q_entry->next; + + spin_lock(q->queue_lock); + rq_entry = q->atomic_head.next; + while (rq_entry != &q->atomic_head) { + rq = list_entry(rq_entry, struct request, queue); + rq_entry = rq_entry->next; + + BUG_ON(!rq->q); + BUG_ON(!rq->bh); + __sequence = bh_elv_seq(rq->bh); + BUG_ON(!__sequence); + if (__sequence == sequence) { + struct list_head *ipoint; + + list_del(&rq->queue); + if (list_empty(&q->queue_head)) + q->plug_device_fn(q, rq->bh->b_rdev); + + ipoint = blk_find_insert_point(q, rq); + list_add(&rq->queue, ipoint); + } + } + if (list_empty(&q->atomic_head)) + list_del_init(&q->atomic_entry); + spin_unlock(q->queue_lock); + } + + spin_unlock_irqrestore(&blk_atomic_queue_lock, flags); +} + /** blk_grow_request_list * @q: The &request_queue_t * @nr_requests: how many requests are desired @@ -447,8 +588,9 @@ static void blk_init_free_list(request_q si_meminfo(&si); megs = si.totalram >> (20 - PAGE_SHIFT); + #ifndef CONFIG_BLK_DEV_ELEVATOR_LOWLAT - nr_requests = (megs * 2) & ~15; /* One per half-megabyte */ + nr_requests = (megs * 2) & ~15; /* One per half-megabyte */ if (nr_requests < 32) nr_requests = 32; if (nr_requests > 1024) @@ -462,6 +604,57 @@ static void blk_init_free_list(request_q init_waitqueue_head(&q->wait_for_requests[1]); } +void blk_print_stats(kdev_t dev) +{ + request_queue_t *q; + unsigned long avg_wait; + unsigned long min_wait; + unsigned long high_wait; + unsigned long *d; + + q = blk_get_queue(dev); + if (!q) + return; + + min_wait = q->min_wait; + if (min_wait == ~0UL) + min_wait = 0; + if (q->num_wait) + avg_wait = q->total_wait / q->num_wait; + else + avg_wait = 0; + printk("device %s: num_req %lu, total jiffies waited %lu\n", + kdevname(dev), q->num_req, q->total_wait); + printk("\t%lu forced to wait\n", q->num_wait); + printk("\t%lu min wait, %lu max wait\n", min_wait, q->max_wait); + printk("\t%lu average wait\n", avg_wait); + d = q->deviation; + printk("\t%lu < 100, %lu < 200, %lu < 300, %lu < 400, %lu < 500\n", + d[0], d[1], d[2], d[3], d[4]); + high_wait = d[0] + d[1] + d[2] + d[3] + d[4]; + high_wait = q->num_wait - high_wait; + printk("\t%lu waits longer than 500 jiffies\n", high_wait); +} + +static void reset_stats(request_queue_t *q) +{ + q->max_wait = 0; + q->min_wait = ~0UL; + q->total_wait = 0; + q->num_req = 0; + q->num_wait = 0; + memset(q->deviation, 0, sizeof(q->deviation)); +} +void blk_reset_stats(kdev_t dev) +{ + request_queue_t *q; + q = blk_get_queue(dev); + if (!q) + return; + printk("reset latency stats on device %s\n", kdevname(dev)); + reset_stats(q); +} + static int __make_request(request_queue_t * q, int rw, struct buffer_head * bh); /** @@ -500,6 +693,8 @@ static int __make_request(request_queue_ void blk_init_queue(request_queue_t * q, request_fn_proc * rfn) { INIT_LIST_HEAD(&q->queue_head); + INIT_LIST_HEAD(&q->atomic_head); + INIT_LIST_HEAD(&q->atomic_entry); elevator_init(&q->elevator, ELEVATOR_LINUS); q->queue_lock = &io_request_lock; blk_init_free_list(q); @@ -514,6 +709,8 @@ void blk_init_queue(request_queue_t * q, q->plugged = 0; q->last_merge = NULL; + reset_stats(q); + /* * These booleans describe the queue properties. We set the * default (and most common) values here. Other drivers can @@ -610,28 +807,34 @@ static struct request *get_request(reque static struct request *__get_request_wait(request_queue_t *q, int rw) { register struct request *rq; + unsigned long wait_start = jiffies; + unsigned long time_waited; DECLARE_WAITQUEUE(wait, current); - add_wait_queue_exclusive(&q->wait_for_requests[rw], &wait); + add_wait_queue(&q->wait_for_requests[rw], &wait); do { set_current_state(TASK_UNINTERRUPTIBLE); - if (q->rq[rw].count == 0) { - /* - * All we care about is not to stall if any request - * is been released after we set TASK_UNINTERRUPTIBLE. - * This is the most efficient place to unplug the queue - * in case we hit the race and we can get the request - * without waiting. - */ - generic_unplug_device(q); + generic_unplug_device(q); + if (q->rq[rw].count == 0) schedule(); - } spin_lock_irq(q->queue_lock); rq = get_request(q, rw); spin_unlock_irq(q->queue_lock); } while (rq == NULL); remove_wait_queue(&q->wait_for_requests[rw], &wait); current->state = TASK_RUNNING; + + time_waited = jiffies - wait_start; + if (time_waited > q->max_wait) + q->max_wait = time_waited; + if (time_waited && time_waited < q->min_wait) + q->min_wait = time_waited; + q->total_wait += time_waited; + q->num_wait++; + if (time_waited < 500) { + q->deviation[time_waited/100]++; + } + return rq; } @@ -841,11 +1044,6 @@ static inline void add_request(request_q { drive_stat_acct(req->rq_dev, req->cmd, req->nr_sectors, 1); - if (!q->plugged && q->head_active && insert_here == &q->queue_head) { - spin_unlock_irq(q->queue_lock); - BUG(); - } - /* * elevator indicated where it wants this request to be * inserted at elevator_merge time @@ -875,8 +1073,7 @@ void blkdev_release_request(struct reque list_add(&req->queue, &q->rq[rw].free); if (++q->rq[rw].count >= q->batch_requests) { smp_mb(); - if (waitqueue_active(&q->wait_for_requests[rw])) - wake_up(&q->wait_for_requests[rw]); + wake_up(&q->wait_for_requests[rw]); } } } @@ -899,6 +1096,8 @@ static void attempt_merge(request_queue_ || req->nr_sectors + next->nr_sectors > max_sectors || next->waiting) return; + if (bh_elv_seq(req->bh) != bh_elv_seq(next->bh)) + return; /* * If we are not allowed to merge these requests, then * return. If we are allowed to merge, then the count @@ -922,11 +1121,12 @@ static void attempt_merge(request_queue_ } static inline void attempt_back_merge(request_queue_t * q, + struct list_head * head, struct request *req, int max_sectors, int max_segments) { - if (&req->queue == q->queue_head.prev) + if (&req->queue == head->prev) return; attempt_merge(q, req, max_sectors, max_segments); } @@ -952,9 +1152,10 @@ static int __make_request(request_queue_ int max_segments = MAX_SEGMENTS; struct request * req, *freereq = NULL; int rw_ahead, max_sectors, el_ret; - struct list_head *head, *insert_here; + struct list_head *head, *real_head, *insert_here; int latency; elevator_t *elevator = &q->elevator; + int atomic = bh_elv_seq(bh), atomic_add = 0; count = bh->b_size >> 9; sector = bh->b_rsector; @@ -996,7 +1197,7 @@ static int __make_request(request_queue_ max_sectors = get_max_sectors(bh->b_rdev); req = NULL; - head = &q->queue_head; + real_head = head = !atomic ? &q->queue_head : &q->atomic_head; /* * Now we acquire the request spinlock, we have to be mega careful * not to schedule or do something nonatomic @@ -1005,11 +1206,14 @@ static int __make_request(request_queue_ again: insert_here = head->prev; - if (list_empty(head)) { - q->plug_device_fn(q, bh->b_rdev); /* is atomic */ + if (!atomic) { + if (list_empty(head)) { + q->plug_device_fn(q, bh->b_rdev); /* is atomic */ + goto get_rq; + } else if (q->head_active && !q->plugged) + head = head->next; + } else if (list_empty(head)) goto get_rq; - } else if (q->head_active && !q->plugged) - head = head->next; el_ret = elevator->elevator_merge_fn(q, &req, head, bh, rw,max_sectors); switch (el_ret) { @@ -1025,7 +1229,7 @@ again: blk_started_io(count); drive_stat_acct(req->rq_dev, req->cmd, count, 0); req_new_io(req, 1, count); - attempt_back_merge(q, req, max_sectors, max_segments); + attempt_back_merge(q, real_head, req, max_sectors, max_segments); goto out; case ELEVATOR_FRONT_MERGE: @@ -1088,9 +1292,10 @@ get_rq: req = get_request(q, rw); if (req == NULL) { spin_unlock_irq(q->queue_lock); + if (atomic) + blk_refile_atomic_queue(atomic); freereq = __get_request_wait(q, rw); - req = NULL; - head = &q->queue_head; + head = real_head; spin_lock_irq(q->queue_lock); get_request_wait_wakeup(q, rw); goto again; @@ -1114,12 +1319,16 @@ get_rq: req->rq_dev = bh->b_rdev; req->start_time = jiffies; req_new_io(req, 0, count); + q->num_req++; blk_started_io(count); add_request(q, req, insert_here); + atomic_add = atomic; out: if (freereq) blkdev_release_request(freereq); spin_unlock_irq(q->queue_lock); + if (atomic_add) + blk_atomic_add(q); return 0; end_io: bh->b_end_io(bh, test_bit(BH_Uptodate, &bh->b_state)); @@ -1168,6 +1377,8 @@ void generic_make_request (int rw, struc if (!bh->b_end_io) BUG(); + if (!buffer_atomic(bh)) + bh->b_elv_sequence = 0; /* Test device size, when known. */ if (blk_size[major]) @@ -1459,6 +1670,10 @@ int __init blk_dev_init(void) memset(max_readahead, 0, sizeof(max_readahead)); memset(max_sectors, 0, sizeof(max_sectors)); +#ifdef CONFIG_SMP + memset(blk_atomic_cpu, 0, sizeof(blk_atomic_cpu)); +#endif + blk_max_low_pfn = max_low_pfn - 1; blk_max_pfn = max_pfn - 1; @@ -1584,3 +1799,5 @@ EXPORT_SYMBOL(blk_max_low_pfn); EXPORT_SYMBOL(blk_max_pfn); EXPORT_SYMBOL(blk_seg_merge_ok); EXPORT_SYMBOL(blk_nohighio); +EXPORT_SYMBOL(blk_get_atomic_seq); +EXPORT_SYMBOL(blk_refile_atomic_queue); diff -Naurp linux-2.4.20-wolk4.1s/drivers/bluetooth/Config.in linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/Config.in --- linux-2.4.20-wolk4.1s/drivers/bluetooth/Config.in 2002-12-18 01:03:50.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/Config.in 2003-06-03 20:02:49.000000000 +0200 @@ -1,14 +1,21 @@ +# +# Bluetooth HCI device drivers configuration +# + mainmenu_option next_comment comment 'Bluetooth device drivers' dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then + bool ' SCO (voice) support' CONFIG_BLUEZ_USB_SCO bool ' USB zero packet support' CONFIG_BLUEZ_USB_ZERO_PACKET fi dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then bool ' UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4 + bool ' BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP + dep_bool ' Transmit CRC with every BCSP packet' CONFIG_BLUEZ_HCIUART_BCSP_TXCRC $CONFIG_BLUEZ_HCIUART_BCSP fi dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ @@ -17,6 +24,9 @@ dep_tristate 'HCI BT3C (PC Card) driver' dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ +dep_tristate 'HCI UART (PC Card) driver' CONFIG_BLUEZ_HCIBTUART $CONFIG_PCMCIA $CONFIG_BLUEZ + dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ endmenu + diff -Naurp linux-2.4.20-wolk4.1s/drivers/bluetooth/Makefile linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/Makefile --- linux-2.4.20-wolk4.1s/drivers/bluetooth/Makefile 2002-12-18 01:03:50.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/Makefile 2003-06-03 20:02:49.000000000 +0200 @@ -1,5 +1,5 @@ # -# Makefile for Bluetooth HCI device drivers. +# Makefile for the Linux Bluetooth HCI device drivers # O_TARGET := bluetooth.o @@ -9,13 +9,15 @@ list-multi := hci_uart.o obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o -obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o -uart-y := hci_ldisc.o -uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o +obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o +uart-y := hci_ldisc.o +uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o +uart-$(CONFIG_BLUEZ_HCIUART_BCSP) += hci_bcsp.o obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o +obj-$(CONFIG_BLUEZ_HCIBTUART) += btuart_cs.o include $(TOPDIR)/Rules.make diff -Naurp linux-2.4.20-wolk4.1s/drivers/bluetooth/btuart_cs.c linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/btuart_cs.c --- linux-2.4.20-wolk4.1s/drivers/bluetooth/btuart_cs.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/btuart_cs.c 2003-06-03 20:02:49.000000000 +0200 @@ -0,0 +1,906 @@ +/* + * + * Driver for Bluetooth PCMCIA cards with HCI UART interface + * + * Copyright (C) 2001-2002 Marcel Holtmann + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The initial developer of the original code is David A. Hinds + * . Portions created by David A. Hinds + * are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + * + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + + +/* ======================== Module parameters ======================== */ + + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xffff; +static int irq_list[4] = { -1 }; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +MODULE_AUTHOR("Marcel Holtmann "); +MODULE_DESCRIPTION("BlueZ driver for Bluetooth PCMCIA cards with HCI UART interface"); +MODULE_LICENSE("GPL"); + + + +/* ======================== Local structures ======================== */ + + +typedef struct btuart_info_t { + dev_link_t link; + dev_node_t node; + + struct hci_dev hdev; + + spinlock_t lock; /* For serializing operations */ + + struct sk_buff_head txq; + unsigned long tx_state; + + unsigned long rx_state; + unsigned long rx_count; + struct sk_buff *rx_skb; +} btuart_info_t; + + +void btuart_config(dev_link_t *link); +void btuart_release(u_long arg); +int btuart_event(event_t event, int priority, event_callback_args_t *args); + +static dev_info_t dev_info = "btuart_cs"; + +dev_link_t *btuart_attach(void); +void btuart_detach(dev_link_t *); + +static dev_link_t *dev_list = NULL; + + +/* Maximum baud rate */ +#define SPEED_MAX 115200 + +/* Default baud rate: 57600, 115200, 230400 or 460800 */ +#define DEFAULT_BAUD_RATE 115200 + + +/* Transmit states */ +#define XMIT_SENDING 1 +#define XMIT_WAKEUP 2 +#define XMIT_WAITING 8 + +/* Receiver states */ +#define RECV_WAIT_PACKET_TYPE 0 +#define RECV_WAIT_EVENT_HEADER 1 +#define RECV_WAIT_ACL_HEADER 2 +#define RECV_WAIT_SCO_HEADER 3 +#define RECV_WAIT_DATA 4 + + + +/* ======================== Interrupt handling ======================== */ + + +static int btuart_write(unsigned int iobase, int fifo_size, __u8 *buf, int len) +{ + int actual = 0; + + /* Tx FIFO should be empty */ + if (!(inb(iobase + UART_LSR) & UART_LSR_THRE)) + return 0; + + /* Fill FIFO with current frame */ + while ((fifo_size-- > 0) && (actual < len)) { + /* Transmit next byte */ + outb(buf[actual], iobase + UART_TX); + actual++; + } + + return actual; +} + + +static void btuart_write_wakeup(btuart_info_t *info) +{ + if (!info) { + printk(KERN_WARNING "btuart_cs: Call of write_wakeup for unknown device.\n"); + return; + } + + if (test_and_set_bit(XMIT_SENDING, &(info->tx_state))) { + set_bit(XMIT_WAKEUP, &(info->tx_state)); + return; + } + + do { + register unsigned int iobase = info->link.io.BasePort1; + register struct sk_buff *skb; + register int len; + + clear_bit(XMIT_WAKEUP, &(info->tx_state)); + + if (!(info->link.state & DEV_PRESENT)) + return; + + if (!(skb = skb_dequeue(&(info->txq)))) + break; + + /* Send frame */ + len = btuart_write(iobase, 16, skb->data, skb->len); + set_bit(XMIT_WAKEUP, &(info->tx_state)); + + if (len == skb->len) { + kfree_skb(skb); + } else { + skb_pull(skb, len); + skb_queue_head(&(info->txq), skb); + } + + info->hdev.stat.byte_tx += len; + + } while (test_bit(XMIT_WAKEUP, &(info->tx_state))); + + clear_bit(XMIT_SENDING, &(info->tx_state)); +} + + +static void btuart_receive(btuart_info_t *info) +{ + unsigned int iobase; + int boguscount = 0; + + if (!info) { + printk(KERN_WARNING "btuart_cs: Call of receive for unknown device.\n"); + return; + } + + iobase = info->link.io.BasePort1; + + do { + info->hdev.stat.byte_rx++; + + /* Allocate packet */ + if (info->rx_skb == NULL) { + info->rx_state = RECV_WAIT_PACKET_TYPE; + info->rx_count = 0; + if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) { + printk(KERN_WARNING "btuart_cs: Can't allocate mem for new packet.\n"); + return; + } + } + + if (info->rx_state == RECV_WAIT_PACKET_TYPE) { + + info->rx_skb->dev = (void *)&(info->hdev); + info->rx_skb->pkt_type = inb(iobase + UART_RX); + + switch (info->rx_skb->pkt_type) { + + case HCI_EVENT_PKT: + info->rx_state = RECV_WAIT_EVENT_HEADER; + info->rx_count = HCI_EVENT_HDR_SIZE; + break; + + case HCI_ACLDATA_PKT: + info->rx_state = RECV_WAIT_ACL_HEADER; + info->rx_count = HCI_ACL_HDR_SIZE; + break; + + case HCI_SCODATA_PKT: + info->rx_state = RECV_WAIT_SCO_HEADER; + info->rx_count = HCI_SCO_HDR_SIZE; + break; + + default: + /* Unknown packet */ + printk(KERN_WARNING "btuart_cs: Unknown HCI packet with type 0x%02x received.\n", info->rx_skb->pkt_type); + info->hdev.stat.err_rx++; + clear_bit(HCI_RUNNING, &(info->hdev.flags)); + + kfree_skb(info->rx_skb); + info->rx_skb = NULL; + break; + + } + + } else { + + *skb_put(info->rx_skb, 1) = inb(iobase + UART_RX); + info->rx_count--; + + if (info->rx_count == 0) { + + int dlen; + hci_event_hdr *eh; + hci_acl_hdr *ah; + hci_sco_hdr *sh; + + + switch (info->rx_state) { + + case RECV_WAIT_EVENT_HEADER: + eh = (hci_event_hdr *)(info->rx_skb->data); + info->rx_state = RECV_WAIT_DATA; + info->rx_count = eh->plen; + break; + + case RECV_WAIT_ACL_HEADER: + ah = (hci_acl_hdr *)(info->rx_skb->data); + dlen = __le16_to_cpu(ah->dlen); + info->rx_state = RECV_WAIT_DATA; + info->rx_count = dlen; + break; + + case RECV_WAIT_SCO_HEADER: + sh = (hci_sco_hdr *)(info->rx_skb->data); + info->rx_state = RECV_WAIT_DATA; + info->rx_count = sh->dlen; + break; + + case RECV_WAIT_DATA: + hci_recv_frame(info->rx_skb); + info->rx_skb = NULL; + break; + + } + + } + + } + + /* Make sure we don't stay here to long */ + if (boguscount++ > 16) + break; + + } while (inb(iobase + UART_LSR) & UART_LSR_DR); +} + + +void btuart_interrupt(int irq, void *dev_inst, struct pt_regs *regs) +{ + btuart_info_t *info = dev_inst; + unsigned int iobase; + int boguscount = 0; + int iir, lsr; + + if (!info) { + printk(KERN_WARNING "btuart_cs: Call of irq %d for unknown device.\n", irq); + return; + } + + iobase = info->link.io.BasePort1; + + spin_lock(&(info->lock)); + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + while (iir) { + + /* Clear interrupt */ + lsr = inb(iobase + UART_LSR); + + switch (iir) { + case UART_IIR_RLSI: + printk(KERN_NOTICE "btuart_cs: RLSI\n"); + break; + case UART_IIR_RDI: + /* Receive interrupt */ + btuart_receive(info); + break; + case UART_IIR_THRI: + if (lsr & UART_LSR_THRE) { + /* Transmitter ready for data */ + btuart_write_wakeup(info); + } + break; + default: + printk(KERN_NOTICE "btuart_cs: Unhandled IIR=%#x\n", iir); + break; + } + + /* Make sure we don't stay here to long */ + if (boguscount++ > 100) + break; + + iir = inb(iobase + UART_IIR) & UART_IIR_ID; + + } + + spin_unlock(&(info->lock)); +} + + +static void btuart_change_speed(btuart_info_t *info, unsigned int speed) +{ + unsigned long flags; + unsigned int iobase; + int fcr; /* FIFO control reg */ + int lcr; /* Line control reg */ + int divisor; + + if (!info) { + printk(KERN_WARNING "btuart_cs: Call of change speed for unknown device.\n"); + return; + } + + iobase = info->link.io.BasePort1; + + spin_lock_irqsave(&(info->lock), flags); + + /* Turn off interrupts */ + outb(0, iobase + UART_IER); + + divisor = SPEED_MAX / speed; + + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT; + + /* + * Use trigger level 1 to avoid 3 ms. timeout delay at 9600 bps, and + * almost 1,7 ms at 19200 bps. At speeds above that we can just forget + * about this timeout since it will always be fast enough. + */ + + if (speed < 38400) + fcr |= UART_FCR_TRIGGER_1; + else + fcr |= UART_FCR_TRIGGER_14; + + /* Bluetooth cards use 8N1 */ + lcr = UART_LCR_WLEN8; + + outb(UART_LCR_DLAB | lcr, iobase + UART_LCR); /* Set DLAB */ + outb(divisor & 0xff, iobase + UART_DLL); /* Set speed */ + outb(divisor >> 8, iobase + UART_DLM); + outb(lcr, iobase + UART_LCR); /* Set 8N1 */ + outb(fcr, iobase + UART_FCR); /* Enable FIFO's */ + + /* Turn on interrups */ + outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); + + spin_unlock_irqrestore(&(info->lock), flags); +} + + + +/* ======================== HCI interface ======================== */ + + +static int btuart_hci_flush(struct hci_dev *hdev) +{ + btuart_info_t *info = (btuart_info_t *)(hdev->driver_data); + + /* Drop TX queue */ + skb_queue_purge(&(info->txq)); + + return 0; +} + + +static int btuart_hci_open(struct hci_dev *hdev) +{ + set_bit(HCI_RUNNING, &(hdev->flags)); + + return 0; +} + + +static int btuart_hci_close(struct hci_dev *hdev) +{ + if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) + return 0; + + btuart_hci_flush(hdev); + + return 0; +} + + +static int btuart_hci_send_frame(struct sk_buff *skb) +{ + btuart_info_t *info; + struct hci_dev *hdev = (struct hci_dev *)(skb->dev); + + if (!hdev) { + printk(KERN_WARNING "btuart_cs: Frame for unknown HCI device (hdev=NULL)."); + return -ENODEV; + } + + info = (btuart_info_t *)(hdev->driver_data); + + switch (skb->pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; + case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + break; + }; + + /* Prepend skb with frame type */ + memcpy(skb_push(skb, 1), &(skb->pkt_type), 1); + skb_queue_tail(&(info->txq), skb); + + btuart_write_wakeup(info); + + return 0; +} + + +static void btuart_hci_destruct(struct hci_dev *hdev) +{ +} + + +static int btuart_hci_ioctl(struct hci_dev *hdev, unsigned int cmd, unsigned long arg) +{ + return -ENOIOCTLCMD; +} + + + +/* ======================== Card services HCI interaction ======================== */ + + +int btuart_open(btuart_info_t *info) +{ + unsigned long flags; + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev; + + spin_lock_init(&(info->lock)); + + skb_queue_head_init(&(info->txq)); + + info->rx_state = RECV_WAIT_PACKET_TYPE; + info->rx_count = 0; + info->rx_skb = NULL; + + spin_lock_irqsave(&(info->lock), flags); + + /* Reset UART */ + outb(0, iobase + UART_MCR); + + /* Turn off interrupts */ + outb(0, iobase + UART_IER); + + /* Initialize UART */ + outb(UART_LCR_WLEN8, iobase + UART_LCR); /* Reset DLAB */ + outb((UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2), iobase + UART_MCR); + + /* Turn on interrupts */ + // outb(UART_IER_RLSI | UART_IER_RDI | UART_IER_THRI, iobase + UART_IER); + + spin_unlock_irqrestore(&(info->lock), flags); + + btuart_change_speed(info, DEFAULT_BAUD_RATE); + + /* Timeout before it is safe to send the first HCI packet */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ); + + + /* Initialize and register HCI device */ + + hdev = &(info->hdev); + + hdev->type = HCI_PCCARD; + hdev->driver_data = info; + + hdev->open = btuart_hci_open; + hdev->close = btuart_hci_close; + hdev->flush = btuart_hci_flush; + hdev->send = btuart_hci_send_frame; + hdev->destruct = btuart_hci_destruct; + hdev->ioctl = btuart_hci_ioctl; + + if (hci_register_dev(hdev) < 0) { + printk(KERN_WARNING "btuart_cs: Can't register HCI device %s.\n", hdev->name); + return -ENODEV; + } + + return 0; +} + + +int btuart_close(btuart_info_t *info) +{ + unsigned long flags; + unsigned int iobase = info->link.io.BasePort1; + struct hci_dev *hdev = &(info->hdev); + + btuart_hci_close(hdev); + + spin_lock_irqsave(&(info->lock), flags); + + /* Reset UART */ + outb(0, iobase + UART_MCR); + + /* Turn off interrupts */ + outb(0, iobase + UART_IER); + + spin_unlock_irqrestore(&(info->lock), flags); + + if (hci_unregister_dev(hdev) < 0) + printk(KERN_WARNING "btuart_cs: Can't unregister HCI device %s.\n", hdev->name); + + return 0; +} + + + +/* ======================== Card services ======================== */ + + +static void cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + + CardServices(ReportError, handle, &err); +} + + +dev_link_t *btuart_attach(void) +{ + btuart_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + /* Create new info device */ + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof(*info)); + + link = &info->link; + link->priv = info; + + link->release.function = &btuart_release; + link->release.data = (u_long)link; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts1 = 8; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + + link->irq.Handler = btuart_interrupt; + link->irq.Instance = info; + + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &btuart_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + btuart_detach(link); + return NULL; + } + + return link; +} + + +void btuart_detach(dev_link_t *link) +{ + btuart_info_t *info = link->priv; + dev_link_t **linkp; + int ret; + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + + if (*linkp == NULL) + return; + + del_timer(&link->release); + if (link->state & DEV_CONFIG) + btuart_release((u_long)link); + + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + + /* Unlink device structure, free bits */ + *linkp = link->next; + + kfree(info); +} + + +static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse) +{ + int i; + + i = CardServices(fn, handle, tuple); + if (i != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + + i = CardServices(GetTupleData, handle, tuple); + if (i != CS_SUCCESS) + return i; + + return CardServices(ParseTuple, handle, tuple, parse); +} + + +#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) +#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) + +void btuart_config(dev_link_t *link) +{ + static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; + client_handle_t handle = link->handle; + btuart_info_t *info = link->priv; + tuple_t tuple; + u_short buf[256]; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + config_info_t config; + int i, j, try, last_ret, last_fn; + + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + + /* Get configuration register information */ + tuple.DesiredTuple = CISTPL_CONFIG; + last_ret = first_tuple(handle, &tuple, &parse); + if (last_ret != CS_SUCCESS) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + i = CardServices(GetConfigurationInfo, handle, &config); + link->conf.Vcc = config.Vcc; + + /* First pass: look for a config entry that looks normal. */ + tuple.TupleData = (cisdata_t *) buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + /* Two tries: without IO aliases, then with aliases */ + for (try = 0; try < 2; try++) { + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if (i != CS_SUCCESS) + goto next_entry; + if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; + if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && (cf->io.win[0].base != 0)) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.IOAddrLines = (try == 0) ? 16 : cf->io.flags & CISTPL_IO_LINES_MASK; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) + goto found_port; + } +next_entry: + i = next_tuple(handle, &tuple, &parse); + } + } + + /* Second pass: try to find an entry that isn't picky about + its base address, then try to grab any standard serial port + address, and finally try to get any free port. */ + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if ((i == CS_SUCCESS) && (cf->io.nwin > 0) + && ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { + link->conf.ConfigIndex = cf->index; + for (j = 0; j < 5; j++) { + link->io.BasePort1 = base[j]; + link->io.IOAddrLines = base[j] ? 16 : 3; + i = CardServices(RequestIO, link->handle, &link->io); + if (i == CS_SUCCESS) + goto found_port; + } + } + i = next_tuple(handle, &tuple, &parse); + } + +found_port: + if (i != CS_SUCCESS) { + printk(KERN_NOTICE "btuart_cs: No usable port range found. Giving up.\n"); + cs_error(link->handle, RequestIO, i); + goto failed; + } + + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); + link->irq.AssignedIRQ = 0; + } + + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + goto failed; + } + + MOD_INC_USE_COUNT; + + if (btuart_open(info) != 0) + goto failed; + + strcpy(info->node.dev_name, info->hdev.name); + link->dev = &info->node; + link->state &= ~DEV_CONFIG_PENDING; + + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); + +failed: + btuart_release((u_long) link); +} + + +void btuart_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + btuart_info_t *info = link->priv; + + if (link->state & DEV_PRESENT) + btuart_close(info); + + MOD_DEC_USE_COUNT; + + link->dev = NULL; + + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + + link->state &= ~DEV_CONFIG; +} + + +int btuart_event(event_t event, int priority, event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + btuart_info_t *info = link->priv; + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + btuart_close(info); + mod_timer(&link->release, jiffies + HZ / 20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + btuart_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (DEV_OK(link)) + CardServices(RequestConfiguration, link->handle, &link->conf); + break; + } + + return 0; +} + + + +/* ======================== Module initialization ======================== */ + + +int __init init_btuart_cs(void) +{ + servinfo_t serv; + int err; + + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "btuart_cs: Card Services release does not match!\n"); + return -1; + } + + err = register_pccard_driver(&dev_info, &btuart_attach, &btuart_detach); + + return err; +} + + +void __exit exit_btuart_cs(void) +{ + unregister_pccard_driver(&dev_info); + + while (dev_list != NULL) + btuart_detach(dev_list); +} + + +module_init(init_btuart_cs); +module_exit(exit_btuart_cs); + +EXPORT_NO_SYMBOLS; diff -Naurp linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_bcsp.c linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_bcsp.c --- linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_bcsp.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_bcsp.c 2003-06-03 20:02:49.000000000 +0200 @@ -0,0 +1,710 @@ +/* + BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ). + Copyright 2002 by Fabrizio Gennari + + Based on + hci_h4.c by Maxim Krasnyansky + ABCSP by Carl Orsborn + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * $Id: hci_bcsp.c,v 1.2 2002/09/26 05:05:14 maxk Exp $ + */ + +#define VERSION "0.1" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "hci_uart.h" +#include "hci_bcsp.h" + +#ifndef HCI_UART_DEBUG +#undef BT_DBG +#define BT_DBG( A... ) +#undef BT_DMP +#define BT_DMP( A... ) +#endif + +/* ---- BCSP CRC calculation ---- */ + +/* Table for calculating CRC for polynomial 0x1021, LSB processed first, +initial value 0xffff, bits shifted in reverse order. */ + +static const u16 crc_table[] = { + 0x0000, 0x1081, 0x2102, 0x3183, + 0x4204, 0x5285, 0x6306, 0x7387, + 0x8408, 0x9489, 0xa50a, 0xb58b, + 0xc60c, 0xd68d, 0xe70e, 0xf78f +}; + +/* Initialise the crc calculator */ +#define BCSP_CRC_INIT(x) x = 0xffff + +/* + Update crc with next data byte + + Implementation note + The data byte is treated as two nibbles. The crc is generated + in reverse, i.e., bits are fed into the register from the top. +*/ +static void bcsp_crc_update(u16 *crc, u8 d) +{ + u16 reg = *crc; + + reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f]; + reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f]; + + *crc = reg; +} + +/* + Get reverse of generated crc + + Implementation note + The crc generator (bcsp_crc_init() and bcsp_crc_update()) + creates a reversed crc, so it needs to be swapped back before + being passed on. +*/ +static u16 bcsp_crc_reverse(u16 crc) +{ + u16 b, rev; + + for (b = 0, rev = 0; b < 16; b++) { + rev = rev << 1; + rev |= (crc & 1); + crc = crc >> 1; + } + return (rev); +} + +/* ---- BCSP core ---- */ + +static void bcsp_slip_msgdelim(struct sk_buff *skb) +{ + const char pkt_delim = 0xc0; + memcpy(skb_put(skb, 1), &pkt_delim, 1); +} + +static void bcsp_slip_one_byte(struct sk_buff *skb, u8 c) +{ + const char esc_c0[2] = { 0xdb, 0xdc }; + const char esc_db[2] = { 0xdb, 0xdd }; + + switch (c) { + case 0xc0: + memcpy(skb_put(skb, 2), &esc_c0, 2); + break; + case 0xdb: + memcpy(skb_put(skb, 2), &esc_db, 2); + break; + default: + memcpy(skb_put(skb, 1), &c, 1); + } +} + +static int bcsp_enqueue(struct hci_uart *hu, struct sk_buff *skb) +{ + struct bcsp_struct *bcsp = hu->priv; + + if (skb->len > 0xFFF) { + BT_ERR("Packet too long"); + kfree_skb(skb); + return 0; + } + + switch (skb->pkt_type) { + case HCI_ACLDATA_PKT: + case HCI_COMMAND_PKT: + skb_queue_tail(&bcsp->rel, skb); + break; + + case HCI_SCODATA_PKT: + skb_queue_tail(&bcsp->unrel, skb); + break; + + default: + BT_ERR("Unknown packet type"); + kfree_skb(skb); + break; + } + return 0; +} + +static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data, + int len, int pkt_type) +{ + struct sk_buff *nskb; + u8 hdr[4], chan; + int rel, i; + +#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC + u16 BCSP_CRC_INIT(bcsp_txmsg_crc); +#endif + + switch (pkt_type) { + case HCI_ACLDATA_PKT: + chan = 6; /* BCSP ACL channel */ + rel = 1; /* reliable channel */ + break; + case HCI_COMMAND_PKT: + chan = 5; /* BCSP cmd/evt channel */ + rel = 1; /* reliable channel */ + break; + case HCI_SCODATA_PKT: + chan = 7; /* BCSP SCO channel */ + rel = 0; /* unreliable channel */ + break; + case BCSP_LE_PKT: + chan = 1; /* BCSP LE channel */ + rel = 0; /* unreliable channel */ + break; + case BCSP_ACK_PKT: + chan = 0; /* BCSP internal channel */ + rel = 0; /* unreliable channel */ + break; + default: + BT_ERR("Unknown packet type"); + return NULL; + } + + /* Max len of packet: (original len +4(bcsp hdr) +2(crc))*2 + (because bytes 0xc0 and 0xdb are escaped, worst case is + when the packet is all made of 0xc0 and 0xdb :) ) + + 2 (0xc0 delimiters at start and end). */ + + nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC); + if (!nskb) + return NULL; + + nskb->pkt_type = pkt_type; + + bcsp_slip_msgdelim(nskb); + + hdr[0] = bcsp->rxseq_txack << 3; + bcsp->txack_req = 0; + BT_DBG("We request packet no %u to card", bcsp->rxseq_txack); + + if (rel) { + hdr[0] |= 0x80 + bcsp->msgq_txseq; + BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq); + bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07; + } +#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC + hdr[0] |= 0x40; +#endif + + hdr[1] = (len << 4) & 0xFF; + hdr[1] |= chan; + hdr[2] = len >> 4; + hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]); + + /* Put BCSP header */ + for (i = 0; i < 4; i++) { + bcsp_slip_one_byte(nskb, hdr[i]); +#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC + bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]); +#endif + } + + /* Put payload */ + for (i = 0; i < len; i++) { + bcsp_slip_one_byte(nskb, data[i]); +#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC + bcsp_crc_update(&bcsp_txmsg_crc, data[i]); +#endif + } + +#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC + /* Put CRC */ + bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc); + bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff)); + bcsp_slip_one_byte(nskb, (u8) (bcsp_txmsg_crc & 0x00ff)); +#endif + + bcsp_slip_msgdelim(nskb); + return nskb; +} + +/* This is a rewrite of pkt_avail in ABCSP */ +static struct sk_buff *bcsp_dequeue(struct hci_uart *hu) +{ + struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv; + unsigned long flags; + struct sk_buff *skb; + + /* First of all, check for unreliable messages in the queue, + since they have priority */ + + if ((skb = skb_dequeue(&bcsp->unrel)) != NULL) { + struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type); + if (nskb) { + kfree_skb(skb); + return nskb; + } else { + skb_queue_head(&bcsp->unrel, skb); + BT_ERR("Could not dequeue pkt because alloc_skb failed"); + } + } + + /* Now, try to send a reliable pkt. We can only send a + reliable packet if the number of packets sent but not yet ack'ed + is < than the winsize */ + + spin_lock_irqsave(&bcsp->unack.lock, flags); + + if (bcsp->unack.qlen < BCSP_TXWINSIZE && (skb = skb_dequeue(&bcsp->rel)) != NULL) { + struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, skb->data, skb->len, skb->pkt_type); + if (nskb) { + __skb_queue_tail(&bcsp->unack, skb); + mod_timer(&bcsp->tbcsp, jiffies + HZ / 4); + spin_unlock_irqrestore(&bcsp->unack.lock, flags); + return nskb; + } else { + skb_queue_head(&bcsp->rel, skb); + BT_ERR("Could not dequeue pkt because alloc_skb failed"); + } + } + + spin_unlock_irqrestore(&bcsp->unack.lock, flags); + + + /* We could not send a reliable packet, either because there are + none or because there are too many unack'ed pkts. Did we receive + any packets we have not acknowledged yet ? */ + + if (bcsp->txack_req) { + /* if so, craft an empty ACK pkt and send it on BCSP unreliable + channel 0 */ + struct sk_buff *nskb = bcsp_prepare_pkt(bcsp, NULL, 0, BCSP_ACK_PKT); + return nskb; + } + + /* We have nothing to send */ + return NULL; +} + +static int bcsp_flush(struct hci_uart *hu) +{ + BT_DBG("hu %p", hu); + return 0; +} + +/* Remove ack'ed packets */ +static void bcsp_pkt_cull(struct bcsp_struct *bcsp) +{ + unsigned long flags; + struct sk_buff *skb; + int i, pkts_to_be_removed; + u8 seqno; + + spin_lock_irqsave(&bcsp->unack.lock, flags); + + pkts_to_be_removed = bcsp->unack.qlen; + seqno = bcsp->msgq_txseq; + + while (pkts_to_be_removed) { + if (bcsp->rxack == seqno) + break; + pkts_to_be_removed--; + seqno = (seqno - 1) & 0x07; + } + + if (bcsp->rxack != seqno) + BT_ERR("Peer acked invalid packet"); + + BT_DBG("Removing %u pkts out of %u, up to seqno %u", + pkts_to_be_removed, bcsp->unack.qlen, (seqno - 1) & 0x07); + + for (i = 0, skb = ((struct sk_buff *) &bcsp->unack)->next; i < pkts_to_be_removed + && skb != (struct sk_buff *) &bcsp->unack; i++) { + struct sk_buff *nskb; + + nskb = skb->next; + __skb_unlink(skb, &bcsp->unack); + kfree_skb(skb); + skb = nskb; + } + if (bcsp->unack.qlen == 0) + del_timer(&bcsp->tbcsp); + spin_unlock_irqrestore(&bcsp->unack.lock, flags); + + if (i != pkts_to_be_removed) + BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed); +} + +/* Handle BCSP link-establishment packets. When we + detect a "sync" packet, symptom that the BT module has reset, + we do nothing :) (yet) */ +static void bcsp_handle_le_pkt(struct hci_uart *hu) +{ + struct bcsp_struct *bcsp = hu->priv; + u8 conf_pkt[4] = { 0xad, 0xef, 0xac, 0xed }; + u8 conf_rsp_pkt[4] = { 0xde, 0xad, 0xd0, 0xd0 }; + u8 sync_pkt[4] = { 0xda, 0xdc, 0xed, 0xed }; + + /* spot "conf" pkts and reply with a "conf rsp" pkt */ + if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 && + !memcmp(&bcsp->rx_skb->data[4], conf_pkt, 4)) { + struct sk_buff *nskb = alloc_skb(4, GFP_ATOMIC); + + BT_DBG("Found a LE conf pkt"); + if (!nskb) + return; + memcpy(skb_put(nskb, 4), conf_rsp_pkt, 4); + nskb->pkt_type = BCSP_LE_PKT; + + skb_queue_head(&bcsp->unrel, nskb); + hci_uart_tx_wakeup(hu); + } + /* Spot "sync" pkts. If we find one...disaster! */ + else if (bcsp->rx_skb->data[1] >> 4 == 4 && bcsp->rx_skb->data[2] == 0 && + !memcmp(&bcsp->rx_skb->data[4], sync_pkt, 4)) { + BT_ERR("Found a LE sync pkt, card has reset"); + } +} + +static inline void bcsp_unslip_one_byte(struct bcsp_struct *bcsp, unsigned char byte) +{ + const u8 c0 = 0xc0, db = 0xdb; + + switch (bcsp->rx_esc_state) { + case BCSP_ESCSTATE_NOESC: + switch (byte) { + case 0xdb: + bcsp->rx_esc_state = BCSP_ESCSTATE_ESC; + break; + default: + memcpy(skb_put(bcsp->rx_skb, 1), &byte, 1); + if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && + bcsp->rx_state != BCSP_W4_CRC) + bcsp_crc_update(&bcsp->message_crc, byte); + bcsp->rx_count--; + } + break; + + case BCSP_ESCSTATE_ESC: + switch (byte) { + case 0xdc: + memcpy(skb_put(bcsp->rx_skb, 1), &c0, 1); + if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && + bcsp->rx_state != BCSP_W4_CRC) + bcsp_crc_update(&bcsp-> message_crc, 0xc0); + bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; + bcsp->rx_count--; + break; + + case 0xdd: + memcpy(skb_put(bcsp->rx_skb, 1), &db, 1); + if ((bcsp->rx_skb-> data[0] & 0x40) != 0 && + bcsp->rx_state != BCSP_W4_CRC) + bcsp_crc_update(&bcsp-> message_crc, 0xdb); + bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; + bcsp->rx_count--; + break; + + default: + BT_ERR ("Invalid byte %02x after esc byte", byte); + kfree_skb(bcsp->rx_skb); + bcsp->rx_skb = NULL; + bcsp->rx_state = BCSP_W4_PKT_DELIMITER; + bcsp->rx_count = 0; + } + } +} + +static inline void bcsp_complete_rx_pkt(struct hci_uart *hu) +{ + struct bcsp_struct *bcsp = hu->priv; + int pass_up; + + if (bcsp->rx_skb->data[0] & 0x80) { /* reliable pkt */ + BT_DBG("Received seqno %u from card", bcsp->rxseq_txack); + bcsp->rxseq_txack++; + bcsp->rxseq_txack %= 0x8; + bcsp->txack_req = 1; + + /* If needed, transmit an ack pkt */ + hci_uart_tx_wakeup(hu); + } + + bcsp->rxack = (bcsp->rx_skb->data[0] >> 3) & 0x07; + BT_DBG("Request for pkt %u from card", bcsp->rxack); + + bcsp_pkt_cull(bcsp); + if ((bcsp->rx_skb->data[1] & 0x0f) == 6 && + bcsp->rx_skb->data[0] & 0x80) { + bcsp->rx_skb->pkt_type = HCI_ACLDATA_PKT; + pass_up = 1; + } else if ((bcsp->rx_skb->data[1] & 0x0f) == 5 && + bcsp->rx_skb->data[0] & 0x80) { + bcsp->rx_skb->pkt_type = HCI_EVENT_PKT; + pass_up = 1; + } else if ((bcsp->rx_skb->data[1] & 0x0f) == 7) { + bcsp->rx_skb->pkt_type = HCI_SCODATA_PKT; + pass_up = 1; + } else if ((bcsp->rx_skb->data[1] & 0x0f) == 1 && + !(bcsp->rx_skb->data[0] & 0x80)) { + bcsp_handle_le_pkt(hu); + pass_up = 0; + } else + pass_up = 0; + + if (!pass_up) { + if ((bcsp->rx_skb->data[1] & 0x0f) != 0 && + (bcsp->rx_skb->data[1] & 0x0f) != 1) { + BT_ERR ("Packet for unknown channel (%u %s)", + bcsp->rx_skb->data[1] & 0x0f, + bcsp->rx_skb->data[0] & 0x80 ? + "reliable" : "unreliable"); + } + kfree_skb(bcsp->rx_skb); + } else { + /* Pull out BCSP hdr */ + skb_pull(bcsp->rx_skb, 4); + + hci_recv_frame(bcsp->rx_skb); + } + bcsp->rx_state = BCSP_W4_PKT_DELIMITER; + bcsp->rx_skb = NULL; +} + +/* Recv data */ +static int bcsp_recv(struct hci_uart *hu, void *data, int count) +{ + struct bcsp_struct *bcsp = hu->priv; + register unsigned char *ptr; + + BT_DBG("hu %p count %d rx_state %ld rx_count %ld", + hu, count, bcsp->rx_state, bcsp->rx_count); + + ptr = data; + while (count) { + if (bcsp->rx_count) { + if (*ptr == 0xc0) { + BT_ERR("Short BCSP packet"); + kfree_skb(bcsp->rx_skb); + bcsp->rx_state = BCSP_W4_PKT_START; + bcsp->rx_count = 0; + } else + bcsp_unslip_one_byte(bcsp, *ptr); + + ptr++; count--; + continue; + } + + switch (bcsp->rx_state) { + case BCSP_W4_BCSP_HDR: + if ((0xff & (u8) ~ (bcsp->rx_skb->data[0] + bcsp->rx_skb->data[1] + + bcsp->rx_skb->data[2])) != bcsp->rx_skb->data[3]) { + BT_ERR("Error in BCSP hdr checksum"); + kfree_skb(bcsp->rx_skb); + bcsp->rx_state = BCSP_W4_PKT_DELIMITER; + bcsp->rx_count = 0; + continue; + } + if (bcsp->rx_skb->data[0] & 0x80 /* reliable pkt */ + && (bcsp->rx_skb->data[0] & 0x07) != bcsp->rxseq_txack) { + BT_ERR ("Out-of-order packet arrived, got %u expected %u", + bcsp->rx_skb->data[0] & 0x07, bcsp->rxseq_txack); + + kfree_skb(bcsp->rx_skb); + bcsp->rx_state = BCSP_W4_PKT_DELIMITER; + bcsp->rx_count = 0; + continue; + } + bcsp->rx_state = BCSP_W4_DATA; + bcsp->rx_count = (bcsp->rx_skb->data[1] >> 4) + + (bcsp->rx_skb->data[2] << 4); /* May be 0 */ + continue; + + case BCSP_W4_DATA: + if (bcsp->rx_skb->data[0] & 0x40) { /* pkt with crc */ + bcsp->rx_state = BCSP_W4_CRC; + bcsp->rx_count = 2; + } else + bcsp_complete_rx_pkt(hu); + continue; + + case BCSP_W4_CRC: + if (bcsp_crc_reverse(bcsp->message_crc) != + (bcsp->rx_skb->data[bcsp->rx_skb->len - 2] << 8) + + bcsp->rx_skb->data[bcsp->rx_skb->len - 1]) { + + BT_ERR ("Checksum failed: computed %04x received %04x", + bcsp_crc_reverse(bcsp->message_crc), + (bcsp->rx_skb-> data[bcsp->rx_skb->len - 2] << 8) + + bcsp->rx_skb->data[bcsp->rx_skb->len - 1]); + + kfree_skb(bcsp->rx_skb); + bcsp->rx_state = BCSP_W4_PKT_DELIMITER; + bcsp->rx_count = 0; + continue; + } + skb_trim(bcsp->rx_skb, bcsp->rx_skb->len - 2); + bcsp_complete_rx_pkt(hu); + continue; + + case BCSP_W4_PKT_DELIMITER: + switch (*ptr) { + case 0xc0: + bcsp->rx_state = BCSP_W4_PKT_START; + break; + default: + /*BT_ERR("Ignoring byte %02x", *ptr);*/ + break; + } + ptr++; count--; + break; + + case BCSP_W4_PKT_START: + switch (*ptr) { + case 0xc0: + ptr++; count--; + break; + + default: + bcsp->rx_state = BCSP_W4_BCSP_HDR; + bcsp->rx_count = 4; + bcsp->rx_esc_state = BCSP_ESCSTATE_NOESC; + BCSP_CRC_INIT(bcsp->message_crc); + + /* Do not increment ptr or decrement count + * Allocate packet. Max len of a BCSP pkt= + * 0xFFF (payload) +4 (header) +2 (crc) */ + + bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC); + if (!bcsp->rx_skb) { + BT_ERR("Can't allocate mem for new packet"); + bcsp->rx_state = BCSP_W4_PKT_DELIMITER; + bcsp->rx_count = 0; + return 0; + } + bcsp->rx_skb->dev = (void *) &hu->hdev; + break; + } + break; + } + } + return count; +} + + /* Arrange to retransmit all messages in the relq. */ +static void bcsp_timed_event(unsigned long arg) +{ + struct hci_uart *hu = (struct hci_uart *) arg; + struct bcsp_struct *bcsp = (struct bcsp_struct *) hu->priv; + struct sk_buff *skb; + unsigned long flags; + + BT_ERR("Timeout, retransmitting %u pkts", bcsp->unack.qlen); + spin_lock_irqsave(&bcsp->unack.lock, flags); + + while ((skb = __skb_dequeue_tail(&bcsp->unack)) != NULL) { + bcsp->msgq_txseq = (bcsp->msgq_txseq - 1) & 0x07; + skb_queue_head(&bcsp->rel, skb); + } + + spin_unlock_irqrestore(&bcsp->unack.lock, flags); + + hci_uart_tx_wakeup(hu); +} + +static int bcsp_open(struct hci_uart *hu) +{ + struct bcsp_struct *bcsp; + + BT_DBG("hu %p", hu); + + bcsp = kmalloc(sizeof(*bcsp), GFP_ATOMIC); + if (!bcsp) + return -ENOMEM; + memset(bcsp, 0, sizeof(*bcsp)); + + hu->priv = bcsp; + skb_queue_head_init(&bcsp->unack); + skb_queue_head_init(&bcsp->rel); + skb_queue_head_init(&bcsp->unrel); + + init_timer(&bcsp->tbcsp); + bcsp->tbcsp.function = bcsp_timed_event; + bcsp->tbcsp.data = (u_long) hu; + + bcsp->rx_state = BCSP_W4_PKT_DELIMITER; + + return 0; +} + +static int bcsp_close(struct hci_uart *hu) +{ + struct bcsp_struct *bcsp = hu->priv; + hu->priv = NULL; + + BT_DBG("hu %p", hu); + + skb_queue_purge(&bcsp->unack); + skb_queue_purge(&bcsp->rel); + skb_queue_purge(&bcsp->unrel); + del_timer(&bcsp->tbcsp); + + kfree(bcsp); + return 0; +} + +static struct hci_uart_proto bcsp = { + id: HCI_UART_BCSP, + open: bcsp_open, + close: bcsp_close, + enqueue: bcsp_enqueue, + dequeue: bcsp_dequeue, + recv: bcsp_recv, + flush: bcsp_flush +}; + +int bcsp_init(void) +{ + return hci_uart_register_proto(&bcsp); +} + +int bcsp_deinit(void) +{ + return hci_uart_unregister_proto(&bcsp); +} diff -Naurp linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_bcsp.h linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_bcsp.h --- linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_bcsp.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_bcsp.h 2003-06-03 20:02:49.000000000 +0200 @@ -0,0 +1,70 @@ +/* + BlueCore Serial Protocol (BCSP) for Linux Bluetooth stack (BlueZ). + Copyright 2002 by Fabrizio Gennari + + Based on + hci_h4.c by Maxim Krasnyansky + ABCSP by Carl Orsborn + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * $Id: hci_bcsp.h,v 1.2 2002/09/26 05:05:14 maxk Exp $ + */ + +#ifndef __HCI_BCSP_H__ +#define __HCI_BCSP_H__ + +#define BCSP_TXWINSIZE 4 + +#define BCSP_ACK_PKT 0x05 +#define BCSP_LE_PKT 0x06 + +struct bcsp_struct { + struct sk_buff_head unack; /* Unack'ed packets queue */ + struct sk_buff_head rel; /* Reliable packets queue */ + struct sk_buff_head unrel; /* Unreliable packets queue */ + + unsigned long rx_count; + struct sk_buff *rx_skb; + u8 rxseq_txack; /* rxseq == txack. */ + u8 rxack; /* Last packet sent by us that the peer ack'ed */ + struct timer_list tbcsp; + + enum { + BCSP_W4_PKT_DELIMITER, + BCSP_W4_PKT_START, + BCSP_W4_BCSP_HDR, + BCSP_W4_DATA, + BCSP_W4_CRC + } rx_state; + + enum { + BCSP_ESCSTATE_NOESC, + BCSP_ESCSTATE_ESC + } rx_esc_state; + + u16 message_crc; + u8 txack_req; /* Do we need to send ack's to the peer? */ + + /* Reliable packet sequence number - used to assign seq to each rel pkt. */ + u8 msgq_txseq; +}; + +#endif /* __HCI_BCSP_H__ */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_h4.c linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_h4.c --- linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_h4.c 2002-09-27 23:25:42.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_h4.c 2003-06-03 20:02:49.000000000 +0200 @@ -25,15 +25,14 @@ /* * BlueZ HCI UART(H4) protocol. * - * $Id: hci_h4.c,v 1.2 2002/04/17 17:37:20 maxk Exp $ + * $Id: hci_h4.c,v 1.3 2002/09/09 01:17:32 maxk Exp $ */ -#define VERSION "1.1" +#define VERSION "1.2" #include #include #include -#include #include #include #include @@ -64,63 +63,61 @@ #endif /* Initialize protocol */ -static int h4_open(struct n_hci *n_hci) +static int h4_open(struct hci_uart *hu) { struct h4_struct *h4; - BT_DBG("n_hci %p", n_hci); + BT_DBG("hu %p", hu); h4 = kmalloc(sizeof(*h4), GFP_ATOMIC); if (!h4) return -ENOMEM; memset(h4, 0, sizeof(*h4)); - n_hci->priv = h4; + skb_queue_head_init(&h4->txq); + + hu->priv = h4; return 0; } /* Flush protocol data */ -static int h4_flush(struct n_hci *n_hci) +static int h4_flush(struct hci_uart *hu) { - BT_DBG("n_hci %p", n_hci); + struct h4_struct *h4 = hu->priv; + + BT_DBG("hu %p", hu); + skb_queue_purge(&h4->txq); return 0; } /* Close protocol */ -static int h4_close(struct n_hci *n_hci) +static int h4_close(struct hci_uart *hu) { - struct h4_struct *h4 = n_hci->priv; - n_hci->priv = NULL; + struct h4_struct *h4 = hu->priv; + hu->priv = NULL; - BT_DBG("n_hci %p", n_hci); + BT_DBG("hu %p", hu); + skb_queue_purge(&h4->txq); if (h4->rx_skb) kfree_skb(h4->rx_skb); + hu->priv = NULL; kfree(h4); return 0; } -/* Send data */ -static int h4_send(struct n_hci *n_hci, void *data, int len) +/* Enqueue frame for transmittion (padding, crc, etc) */ +static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) { - struct tty_struct *tty = n_hci->tty; - - BT_DBG("n_hci %p len %d", n_hci, len); + struct h4_struct *h4 = hu->priv; - /* Send frame to TTY driver */ - tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - return tty->driver.write(tty, 0, data, len); -} - -/* Init frame before queueing (padding, crc, etc) */ -static struct sk_buff* h4_preq(struct n_hci *n_hci, struct sk_buff *skb) -{ - BT_DBG("n_hci %p skb %p", n_hci, skb); + BT_DBG("hu %p skb %p", hu, skb); /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &skb->pkt_type, 1); - return skb; + skb_queue_tail(&h4->txq, skb); + return 0; } static inline int h4_check_data_len(struct h4_struct *h4, int len) @@ -132,7 +129,7 @@ static inline int h4_check_data_len(stru BT_DMP(h4->rx_skb->data, h4->rx_skb->len); hci_recv_frame(h4->rx_skb); } else if (len > room) { - BT_ERR("Data length is to large"); + BT_ERR("Data length is too large"); kfree_skb(h4->rx_skb); } else { h4->rx_state = H4_W4_DATA; @@ -147,16 +144,17 @@ static inline int h4_check_data_len(stru } /* Recv data */ -static int h4_recv(struct n_hci *n_hci, void *data, int count) +static int h4_recv(struct hci_uart *hu, void *data, int count) { - struct h4_struct *h4 = n_hci->priv; + struct h4_struct *h4 = hu->priv; register char *ptr; hci_event_hdr *eh; hci_acl_hdr *ah; hci_sco_hdr *sh; register int len, type, dlen; - BT_DBG("n_hci %p count %d rx_state %ld rx_count %ld", n_hci, count, h4->rx_state, h4->rx_count); + BT_DBG("hu %p count %d rx_state %ld rx_count %ld", + hu, count, h4->rx_state, h4->rx_count); ptr = data; while (count) { @@ -204,7 +202,7 @@ static int h4_recv(struct n_hci *n_hci, h4_check_data_len(h4, sh->dlen); continue; - }; + } } /* H4_W4_PACKET_TYPE */ @@ -232,7 +230,7 @@ static int h4_recv(struct n_hci *n_hci, default: BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr); - n_hci->hdev.stat.err_rx++; + hu->hdev.stat.err_rx++; ptr++; count--; continue; }; @@ -246,20 +244,26 @@ static int h4_recv(struct n_hci *n_hci, h4->rx_count = 0; return 0; } - h4->rx_skb->dev = (void *) &n_hci->hdev; + h4->rx_skb->dev = (void *) &hu->hdev; h4->rx_skb->pkt_type = type; } return count; } +static struct sk_buff *h4_dequeue(struct hci_uart *hu) +{ + struct h4_struct *h4 = hu->priv; + return skb_dequeue(&h4->txq); +} + static struct hci_uart_proto h4p = { - id: HCI_UART_H4, - open: h4_open, - close: h4_close, - send: h4_send, - recv: h4_recv, - preq: h4_preq, - flush: h4_flush, + id: HCI_UART_H4, + open: h4_open, + close: h4_close, + recv: h4_recv, + enqueue: h4_enqueue, + dequeue: h4_dequeue, + flush: h4_flush, }; int h4_init(void) diff -Naurp linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_h4.h linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_h4.h --- linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_h4.h 2002-09-27 23:25:42.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_h4.h 2003-06-03 20:02:49.000000000 +0200 @@ -23,7 +23,7 @@ */ /* - * $Id: hci_h4.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + * $Id: hci_h4.h,v 1.2 2002/09/09 01:17:32 maxk Exp $ */ #ifdef __KERNEL__ @@ -31,6 +31,7 @@ struct h4_struct { unsigned long rx_state; unsigned long rx_count; struct sk_buff *rx_skb; + struct sk_buff_head txq; }; /* H4 receiver States */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_ldisc.c linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_ldisc.c --- linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_ldisc.c 2002-12-18 01:03:50.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_ldisc.c 2003-06-03 20:02:49.000000000 +0200 @@ -25,14 +25,15 @@ /* * BlueZ HCI UART driver. * - * $Id: hci_ldisc.c,v 1.2 2002/04/17 17:37:20 maxk Exp $ + * $Id: hci_ldisc.c,v 1.5 2002/10/02 18:37:20 maxk Exp $ */ -#define VERSION "2.0" +#define VERSION "2.1" #include #include #include +#include #include #include #include @@ -87,16 +88,86 @@ int hci_uart_unregister_proto(struct hci return 0; } -static struct hci_uart_proto *n_hci_get_proto(unsigned int id) +static struct hci_uart_proto *hci_uart_get_proto(unsigned int id) { if (id >= HCI_UART_MAX_PROTO) return NULL; return hup[id]; } +static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type) +{ + struct hci_dev *hdev = &hu->hdev; + + /* Update HCI stat counters */ + switch (pkt_type) { + case HCI_COMMAND_PKT: + hdev->stat.cmd_tx++; + break; + + case HCI_ACLDATA_PKT: + hdev->stat.acl_tx++; + break; + + case HCI_SCODATA_PKT: + hdev->stat.cmd_tx++; + break; + } +} + +static inline struct sk_buff *hci_uart_dequeue(struct hci_uart *hu) +{ + struct sk_buff *skb = hu->tx_skb; + if (!skb) + skb = hu->proto->dequeue(hu); + else + hu->tx_skb = NULL; + return skb; +} + +int hci_uart_tx_wakeup(struct hci_uart *hu) +{ + struct tty_struct *tty = hu->tty; + struct hci_dev *hdev = &hu->hdev; + struct sk_buff *skb; + + if (test_and_set_bit(HCI_UART_SENDING, &hu->tx_state)) { + set_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); + return 0; + } + + BT_DBG(""); + +restart: + clear_bit(HCI_UART_TX_WAKEUP, &hu->tx_state); + + while ((skb = hci_uart_dequeue(hu))) { + int len; + + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); + len = tty->driver.write(tty, 0, skb->data, skb->len); + hdev->stat.byte_tx += len; + + skb_pull(skb, len); + if (skb->len) { + hu->tx_skb = skb; + break; + } + + hci_uart_tx_complete(hu, skb->pkt_type); + kfree_skb(skb); + } + + if (test_bit(HCI_UART_TX_WAKEUP, &hu->tx_state)) + goto restart; + + clear_bit(HCI_UART_SENDING, &hu->tx_state); + return 0; +} + /* ------- Interface to HCI layer ------ */ /* Initialize device */ -static int n_hci_open(struct hci_dev *hdev) +static int hci_uart_open(struct hci_dev *hdev) { BT_DBG("%s %p", hdev->name, hdev); @@ -107,15 +178,16 @@ static int n_hci_open(struct hci_dev *hd } /* Reset device */ -static int n_hci_flush(struct hci_dev *hdev) +static int hci_uart_flush(struct hci_dev *hdev) { - struct n_hci *n_hci = (struct n_hci *) hdev->driver_data; - struct tty_struct *tty = n_hci->tty; + struct hci_uart *hu = (struct hci_uart *) hdev->driver_data; + struct tty_struct *tty = hu->tty; BT_DBG("hdev %p tty %p", hdev, tty); - /* Drop TX queue */ - skb_queue_purge(&n_hci->txq); + if (hu->tx_skb) { + kfree_skb(hu->tx_skb); hu->tx_skb = NULL; + } /* Flush any pending characters in the driver and discipline. */ if (tty->ldisc.flush_buffer) @@ -124,80 +196,30 @@ static int n_hci_flush(struct hci_dev *h if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); - if (n_hci->proto->flush) - n_hci->proto->flush(n_hci); + if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) + hu->proto->flush(hu); return 0; } /* Close device */ -static int n_hci_close(struct hci_dev *hdev) +static int hci_uart_close(struct hci_dev *hdev) { BT_DBG("hdev %p", hdev); if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) return 0; - n_hci_flush(hdev); - return 0; -} - -static int n_hci_tx_wakeup(struct n_hci *n_hci) -{ - struct hci_dev *hdev = &n_hci->hdev; - - if (test_and_set_bit(N_HCI_SENDING, &n_hci->tx_state)) { - set_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state); - return 0; - } - - BT_DBG(""); - do { - register struct sk_buff *skb; - register int len; - - clear_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state); - - if (!(skb = skb_dequeue(&n_hci->txq))) - break; - - len = n_hci->proto->send(n_hci, skb->data, skb->len); - n_hci->hdev.stat.byte_tx += len; - - if (len == skb->len) { - /* Complete frame was sent */ - - switch (skb->pkt_type) { - case HCI_COMMAND_PKT: - hdev->stat.cmd_tx++; - break; - - case HCI_ACLDATA_PKT: - hdev->stat.acl_tx++; - break; - - case HCI_SCODATA_PKT: - hdev->stat.cmd_tx++; - break; - }; - - kfree_skb(skb); - } else { - /* Subtract sent part and requeue */ - skb_pull(skb, len); - skb_queue_head(&n_hci->txq, skb); - } - } while (test_bit(N_HCI_TX_WAKEUP, &n_hci->tx_state)); - clear_bit(N_HCI_SENDING, &n_hci->tx_state); + hci_uart_flush(hdev); return 0; } /* Send frames from HCI layer */ -static int n_hci_send_frame(struct sk_buff *skb) +static int hci_uart_send_frame(struct sk_buff *skb) { struct hci_dev* hdev = (struct hci_dev *) skb->dev; struct tty_struct *tty; - struct n_hci *n_hci; + struct hci_uart *hu; if (!hdev) { BT_ERR("Frame for uknown device (hdev=NULL)"); @@ -207,66 +229,60 @@ static int n_hci_send_frame(struct sk_bu if (!test_bit(HCI_RUNNING, &hdev->flags)) return -EBUSY; - n_hci = (struct n_hci *) hdev->driver_data; - tty = n_hci->tty; + hu = (struct hci_uart *) hdev->driver_data; + tty = hu->tty; BT_DBG("%s: type %d len %d", hdev->name, skb->pkt_type, skb->len); - if (n_hci->proto->preq) { - skb = n_hci->proto->preq(n_hci, skb); - if (!skb) - return 0; - } - - skb_queue_tail(&n_hci->txq, skb); - n_hci_tx_wakeup(n_hci); + hu->proto->enqueue(hu, skb); + + hci_uart_tx_wakeup(hu); return 0; } -static void n_hci_destruct(struct hci_dev *hdev) +static void hci_uart_destruct(struct hci_dev *hdev) { - struct n_hci *n_hci; + struct hci_uart *hu; if (!hdev) return; BT_DBG("%s", hdev->name); - n_hci = (struct n_hci *) hdev->driver_data; - kfree(n_hci); + hu = (struct hci_uart *) hdev->driver_data; + kfree(hu); MOD_DEC_USE_COUNT; } /* ------ LDISC part ------ */ -/* n_hci_tty_open +/* hci_uart_tty_open * - * Called when line discipline changed to N_HCI. + * Called when line discipline changed to HCI_UART. * * Arguments: * tty pointer to tty info structure * Return Value: * 0 if success, otherwise error code */ -static int n_hci_tty_open(struct tty_struct *tty) +static int hci_uart_tty_open(struct tty_struct *tty) { - struct n_hci *n_hci = (void *)tty->disc_data; + struct hci_uart *hu = (void *) tty->disc_data; BT_DBG("tty %p", tty); - if (n_hci) + if (hu) return -EEXIST; - if (!(n_hci = kmalloc(sizeof(struct n_hci), GFP_KERNEL))) { + if (!(hu = kmalloc(sizeof(struct hci_uart), GFP_KERNEL))) { BT_ERR("Can't allocate controll structure"); return -ENFILE; } - memset(n_hci, 0, sizeof(struct n_hci)); + memset(hu, 0, sizeof(struct hci_uart)); - tty->disc_data = n_hci; - n_hci->tty = tty; + tty->disc_data = hu; + hu->tty = tty; - spin_lock_init(&n_hci->rx_lock); - skb_queue_head_init(&n_hci->txq); + spin_lock_init(&hu->rx_lock); /* Flush any pending characters in the driver and line discipline */ if (tty->ldisc.flush_buffer) @@ -279,34 +295,34 @@ static int n_hci_tty_open(struct tty_str return 0; } -/* n_hci_tty_close() +/* hci_uart_tty_close() * * Called when the line discipline is changed to something * else, the tty is closed, or the tty detects a hangup. */ -static void n_hci_tty_close(struct tty_struct *tty) +static void hci_uart_tty_close(struct tty_struct *tty) { - struct n_hci *n_hci = (void *)tty->disc_data; + struct hci_uart *hu = (void *)tty->disc_data; BT_DBG("tty %p", tty); /* Detach from the tty */ tty->disc_data = NULL; - if (n_hci) { - struct hci_dev *hdev = &n_hci->hdev; - n_hci_close(hdev); + if (hu) { + struct hci_dev *hdev = &hu->hdev; + hci_uart_close(hdev); - if (test_and_clear_bit(N_HCI_PROTO_SET, &n_hci->flags)) { - n_hci->proto->close(n_hci); + if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { + hu->proto->close(hu); hci_unregister_dev(hdev); } - + MOD_DEC_USE_COUNT; } } -/* n_hci_tty_wakeup() +/* hci_uart_tty_wakeup() * * Callback for transmit wakeup. Called when low level * device driver can accept more send data. @@ -314,24 +330,25 @@ static void n_hci_tty_close(struct tty_s * Arguments: tty pointer to associated tty instance data * Return Value: None */ -static void n_hci_tty_wakeup( struct tty_struct *tty ) +static void hci_uart_tty_wakeup(struct tty_struct *tty) { - struct n_hci *n_hci = (void *)tty->disc_data; + struct hci_uart *hu = (void *)tty->disc_data; BT_DBG(""); - if (!n_hci) + if (!hu) return; - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - if (tty != n_hci->tty) + if (tty != hu->tty) return; - n_hci_tx_wakeup(n_hci); + if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) + hci_uart_tx_wakeup(hu); } -/* n_hci_tty_room() +/* hci_uart_tty_room() * * Callback function from tty driver. Return the amount of * space left in the receiver's buffer to decide if remote @@ -340,12 +357,12 @@ static void n_hci_tty_wakeup( struct tty * Arguments: tty pointer to associated tty instance data * Return Value: number of bytes left in receive buffer */ -static int n_hci_tty_room (struct tty_struct *tty) +static int hci_uart_tty_room (struct tty_struct *tty) { return 65536; } -/* n_hci_tty_receive() +/* hci_uart_tty_receive() * * Called by tty low level driver when receive data is * available. @@ -357,42 +374,42 @@ static int n_hci_tty_room (struct tty_st * * Return Value: None */ -static void n_hci_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count) +static void hci_uart_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count) { - struct n_hci *n_hci = (void *)tty->disc_data; + struct hci_uart *hu = (void *)tty->disc_data; - if (!n_hci || tty != n_hci->tty) + if (!hu || tty != hu->tty) return; - if (!test_bit(N_HCI_PROTO_SET, &n_hci->flags)) + if (!test_bit(HCI_UART_PROTO_SET, &hu->flags)) return; - spin_lock(&n_hci->rx_lock); - n_hci->proto->recv(n_hci, (void *) data, count); - n_hci->hdev.stat.byte_rx += count; - spin_unlock(&n_hci->rx_lock); + spin_lock(&hu->rx_lock); + hu->proto->recv(hu, (void *) data, count); + hu->hdev.stat.byte_rx += count; + spin_unlock(&hu->rx_lock); if (test_and_clear_bit(TTY_THROTTLED,&tty->flags) && tty->driver.unthrottle) tty->driver.unthrottle(tty); } -static int n_hci_register_dev(struct n_hci *n_hci) +static int hci_uart_register_dev(struct hci_uart *hu) { struct hci_dev *hdev; BT_DBG(""); /* Initialize and register HCI device */ - hdev = &n_hci->hdev; + hdev = &hu->hdev; hdev->type = HCI_UART; - hdev->driver_data = n_hci; + hdev->driver_data = hu; - hdev->open = n_hci_open; - hdev->close = n_hci_close; - hdev->flush = n_hci_flush; - hdev->send = n_hci_send_frame; - hdev->destruct = n_hci_destruct; + hdev->open = hci_uart_open; + hdev->close = hci_uart_close; + hdev->flush = hci_uart_flush; + hdev->send = hci_uart_send_frame; + hdev->destruct = hci_uart_destruct; if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device %s", hdev->name); @@ -402,30 +419,30 @@ static int n_hci_register_dev(struct n_h return 0; } -static int n_hci_set_proto(struct n_hci *n_hci, int id) +static int hci_uart_set_proto(struct hci_uart *hu, int id) { struct hci_uart_proto *p; int err; - p = n_hci_get_proto(id); + p = hci_uart_get_proto(id); if (!p) return -EPROTONOSUPPORT; - err = p->open(n_hci); + err = p->open(hu); if (err) return err; - n_hci->proto = p; + hu->proto = p; - err = n_hci_register_dev(n_hci); + err = hci_uart_register_dev(hu); if (err) { - p->close(n_hci); + p->close(hu); return err; } return 0; } -/* n_hci_tty_ioctl() +/* hci_uart_tty_ioctl() * * Process IOCTL system call for the tty device. * @@ -438,24 +455,24 @@ static int n_hci_set_proto(struct n_hci * * Return Value: Command dependent */ -static int n_hci_tty_ioctl(struct tty_struct *tty, struct file * file, +static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - struct n_hci *n_hci = (void *)tty->disc_data; + struct hci_uart *hu = (void *)tty->disc_data; int err = 0; BT_DBG(""); /* Verify the status of the device */ - if (!n_hci) + if (!hu) return -EBADF; switch (cmd) { case HCIUARTSETPROTO: - if (!test_and_set_bit(N_HCI_PROTO_SET, &n_hci->flags)) { - err = n_hci_set_proto(n_hci, arg); + if (!test_and_set_bit(HCI_UART_PROTO_SET, &hu->flags)) { + err = hci_uart_set_proto(hu, arg); if (err) { - clear_bit(N_HCI_PROTO_SET, &n_hci->flags); + clear_bit(HCI_UART_PROTO_SET, &hu->flags); return err; } tty->low_latency = 1; @@ -463,8 +480,8 @@ static int n_hci_tty_ioctl(struct tty_st return -EBUSY; case HCIUARTGETPROTO: - if (test_bit(N_HCI_PROTO_SET, &n_hci->flags)) - return n_hci->proto->id; + if (test_bit(HCI_UART_PROTO_SET, &hu->flags)) + return hu->proto->id; return -EUNATCH; default: @@ -478,15 +495,15 @@ static int n_hci_tty_ioctl(struct tty_st /* * We don't provide read/write/poll interface for user space. */ -static ssize_t n_hci_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) +static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) { return 0; } -static ssize_t n_hci_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) +static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) { return 0; } -static unsigned int n_hci_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) +static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp, poll_table *wait) { return 0; } @@ -495,10 +512,14 @@ static unsigned int n_hci_tty_poll(struc int h4_init(void); int h4_deinit(void); #endif +#ifdef CONFIG_BLUEZ_HCIUART_BCSP +int bcsp_init(void); +int bcsp_deinit(void); +#endif -int __init n_hci_init(void) +int __init hci_uart_init(void) { - static struct tty_ldisc n_hci_ldisc; + static struct tty_ldisc hci_uart_ldisc; int err; BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc", @@ -507,20 +528,20 @@ int __init n_hci_init(void) /* Register the tty discipline */ - memset(&n_hci_ldisc, 0, sizeof (n_hci_ldisc)); - n_hci_ldisc.magic = TTY_LDISC_MAGIC; - n_hci_ldisc.name = "n_hci"; - n_hci_ldisc.open = n_hci_tty_open; - n_hci_ldisc.close = n_hci_tty_close; - n_hci_ldisc.read = n_hci_tty_read; - n_hci_ldisc.write = n_hci_tty_write; - n_hci_ldisc.ioctl = n_hci_tty_ioctl; - n_hci_ldisc.poll = n_hci_tty_poll; - n_hci_ldisc.receive_room= n_hci_tty_room; - n_hci_ldisc.receive_buf = n_hci_tty_receive; - n_hci_ldisc.write_wakeup= n_hci_tty_wakeup; + memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc)); + hci_uart_ldisc.magic = TTY_LDISC_MAGIC; + hci_uart_ldisc.name = "n_hci"; + hci_uart_ldisc.open = hci_uart_tty_open; + hci_uart_ldisc.close = hci_uart_tty_close; + hci_uart_ldisc.read = hci_uart_tty_read; + hci_uart_ldisc.write = hci_uart_tty_write; + hci_uart_ldisc.ioctl = hci_uart_tty_ioctl; + hci_uart_ldisc.poll = hci_uart_tty_poll; + hci_uart_ldisc.receive_room= hci_uart_tty_room; + hci_uart_ldisc.receive_buf = hci_uart_tty_receive; + hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup; - if ((err = tty_register_ldisc(N_HCI, &n_hci_ldisc))) { + if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) { BT_ERR("Can't register HCI line discipline (%d)", err); return err; } @@ -528,25 +549,31 @@ int __init n_hci_init(void) #ifdef CONFIG_BLUEZ_HCIUART_H4 h4_init(); #endif +#ifdef CONFIG_BLUEZ_HCIUART_BCSP + bcsp_init(); +#endif return 0; } -void n_hci_cleanup(void) +void hci_uart_cleanup(void) { int err; #ifdef CONFIG_BLUEZ_HCIUART_H4 h4_deinit(); #endif +#ifdef CONFIG_BLUEZ_HCIUART_BCSP + bcsp_deinit(); +#endif /* Release tty registration of line discipline */ if ((err = tty_register_ldisc(N_HCI, NULL))) BT_ERR("Can't unregister HCI line discipline (%d)", err); } -module_init(n_hci_init); -module_exit(n_hci_cleanup); +module_init(hci_uart_init); +module_exit(hci_uart_cleanup); MODULE_AUTHOR("Maxim Krasnyansky "); MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION); diff -Naurp linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_uart.h linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_uart.h --- linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_uart.h 2002-09-27 23:25:42.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_uart.h 2003-06-03 20:02:49.000000000 +0200 @@ -23,10 +23,10 @@ */ /* - * $Id: hci_uart.h,v 1.1.1.1 2002/03/08 21:03:15 maxk Exp $ + * $Id: hci_uart.h,v 1.2 2002/09/09 01:17:32 maxk Exp $ */ -#ifndef N_HCI +#ifndef N_HCI #define N_HCI 15 #endif @@ -42,19 +42,19 @@ #define HCI_UART_NCSP 2 #ifdef __KERNEL__ -struct n_hci; +struct hci_uart; struct hci_uart_proto { unsigned int id; - int (*open)(struct n_hci *n_hci); - int (*recv)(struct n_hci *n_hci, void *data, int len); - int (*send)(struct n_hci *n_hci, void *data, int len); - int (*close)(struct n_hci *n_hci); - int (*flush)(struct n_hci *n_hci); - struct sk_buff* (*preq)(struct n_hci *n_hci, struct sk_buff *skb); + int (*open)(struct hci_uart *hu); + int (*close)(struct hci_uart *hu); + int (*flush)(struct hci_uart *hu); + int (*recv)(struct hci_uart *hu, void *data, int len); + int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb); + struct sk_buff *(*dequeue)(struct hci_uart *hu); }; -struct n_hci { +struct hci_uart { struct tty_struct *tty; struct hci_dev hdev; unsigned long flags; @@ -62,19 +62,20 @@ struct n_hci { struct hci_uart_proto *proto; void *priv; - struct sk_buff_head txq; - unsigned long tx_state; - spinlock_t rx_lock; + struct sk_buff *tx_skb; + unsigned long tx_state; + spinlock_t rx_lock; }; -/* N_HCI flag bits */ -#define N_HCI_PROTO_SET 0x00 +/* HCI_UART flag bits */ +#define HCI_UART_PROTO_SET 0 /* TX states */ -#define N_HCI_SENDING 1 -#define N_HCI_TX_WAKEUP 2 +#define HCI_UART_SENDING 1 +#define HCI_UART_TX_WAKEUP 2 int hci_uart_register_proto(struct hci_uart_proto *p); int hci_uart_unregister_proto(struct hci_uart_proto *p); +int hci_uart_tx_wakeup(struct hci_uart *hu); #endif /* __KERNEL__ */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_usb.c linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_usb.c --- linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_usb.c 2002-12-18 01:03:50.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_usb.c 2003-06-03 20:02:49.000000000 +0200 @@ -1,9 +1,10 @@ /* - BlueZ - Bluetooth protocol stack for Linux + HCI USB driver for Linux Bluetooth protocol stack (BlueZ) Copyright (C) 2000-2001 Qualcomm Incorporated - Written 2000,2001 by Maxim Krasnyansky + Copyright (C) 2003 Maxim Krasnyansky + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation; @@ -23,20 +24,17 @@ */ /* - * BlueZ HCI USB driver. * Based on original USB Bluetooth driver for Linux kernel * Copyright (c) 2000 Greg Kroah-Hartman * Copyright (c) 2000 Mark Douglas Corner * * $Id: hci_usb.c,v 1.8 2002/07/18 17:23:09 maxk Exp $ */ -#define VERSION "2.1" +#define VERSION "2.4" #include #include -#define __KERNEL_SYSCALLS__ - #include #include #include @@ -49,15 +47,13 @@ #include #include #include -#include #include #include #include -#include "hci_usb.h" -#define HCI_MAX_PENDING (HCI_MAX_BULK_RX + HCI_MAX_BULK_TX + 1) +#include "hci_usb.h" #ifndef HCI_USB_DEBUG #undef BT_DBG @@ -80,6 +76,9 @@ static struct usb_device_id bluetooth_id /* Ericsson with non-standard id */ { USB_DEVICE(0x0bdb, 0x1002) }, + /* Bluetooth Ultraport Module from IBM */ + { USB_DEVICE(0x04bf, 0x030a) }, + { } /* Terminating entry */ }; @@ -92,109 +91,193 @@ static struct usb_device_id ignore_ids[] { } /* Terminating entry */ }; -static void hci_usb_interrupt(struct urb *urb); +struct _urb *_urb_alloc(int isoc, int gfp) +{ + struct _urb *_urb = kmalloc(sizeof(struct _urb) + + sizeof(struct iso_packet_descriptor) * isoc, gfp); + if (_urb) { + memset(_urb, 0, sizeof(*_urb)); + spin_lock_init(&_urb->urb.lock); + } + return _urb; +} + +struct _urb *_urb_dequeue(struct _urb_queue *q) +{ + struct _urb *_urb = NULL; + unsigned long flags; + spin_lock_irqsave(&q->lock, flags); + { + struct list_head *head = &q->head; + struct list_head *next = head->next; + if (next != head) { + _urb = list_entry(next, struct _urb, list); + list_del(next); _urb->queue = NULL; + } + } + spin_unlock_irqrestore(&q->lock, flags); + return _urb; +} + static void hci_usb_rx_complete(struct urb *urb); static void hci_usb_tx_complete(struct urb *urb); -static struct urb *hci_usb_get_completed(struct hci_usb *husb) +#define __pending_tx(husb, type) (&husb->pending_tx[type-1]) +#define __pending_q(husb, type) (&husb->pending_q[type-1]) +#define __completed_q(husb, type) (&husb->completed_q[type-1]) +#define __transmit_q(husb, type) (&husb->transmit_q[type-1]) +#define __reassembly(husb, type) (husb->reassembly[type-1]) + +static inline struct _urb *__get_completed(struct hci_usb *husb, int type) { - struct sk_buff *skb; - struct urb *urb = NULL; + return _urb_dequeue(__completed_q(husb, type)); +} - skb = skb_dequeue(&husb->completed_q); - if (skb) { - urb = ((struct hci_usb_scb *) skb->cb)->urb; - kfree_skb(skb); - } +static void __fill_isoc_desc(struct urb *urb, int len, int mtu) +{ + int offset = 0, i; - BT_DBG("%s urb %p", husb->hdev.name, urb); - return urb; + BT_DBG("len %d mtu %d", len, mtu); + + for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) { + urb->iso_frame_desc[i].offset = offset; + urb->iso_frame_desc[i].length = mtu; + BT_DBG("desc %d offset %d len %d", i, offset, mtu); + } + if (len && i < HCI_MAX_ISOC_FRAMES) { + urb->iso_frame_desc[i].offset = offset; + urb->iso_frame_desc[i].length = len; + BT_DBG("desc %d offset %d len %d", i, offset, len); + i++; + } + urb->number_of_packets = i; } -static int hci_usb_enable_intr(struct hci_usb *husb) +static int hci_usb_intr_rx_submit(struct hci_usb *husb) { + struct _urb *_urb; struct urb *urb; - int pipe, size; + int err, pipe, interval, size; void *buf; BT_DBG("%s", husb->hdev.name); - if (!(urb = usb_alloc_urb(0))) + size = husb->intr_in_ep->wMaxPacketSize; + + buf = kmalloc(size, GFP_ATOMIC); + if (!buf) return -ENOMEM; - if (!(buf = kmalloc(HCI_MAX_EVENT_SIZE, GFP_KERNEL))) { - usb_free_urb(urb); + _urb = _urb_alloc(0, GFP_ATOMIC); + if (!_urb) { + kfree(buf); return -ENOMEM; } + _urb->type = HCI_EVENT_PKT; + _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - husb->intr_urb = urb; + urb = &_urb->urb; + pipe = usb_rcvintpipe(husb->udev, husb->intr_in_ep->bEndpointAddress); + interval = husb->intr_in_ep->bInterval; + FILL_INT_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval); - pipe = usb_rcvintpipe(husb->udev, husb->intr_ep); - size = usb_maxpacket(husb->udev, pipe, usb_pipeout(pipe)); - FILL_INT_URB(urb, husb->udev, pipe, buf, size, - hci_usb_interrupt, husb, husb->intr_interval); - - return usb_submit_urb(urb); + err = usb_submit_urb(urb); + if (err) { + BT_ERR("%s intr rx submit failed urb %p err %d", + husb->hdev.name, urb, err); + _urb_unlink(_urb); + _urb_free(_urb); + kfree(buf); + } + return err; } -static int hci_usb_disable_intr(struct hci_usb *husb) +static int hci_usb_bulk_rx_submit(struct hci_usb *husb) { - struct urb *urb = husb->intr_urb; - struct sk_buff *skb; - - BT_DBG("%s", husb->hdev.name); + struct _urb *_urb; + struct urb *urb; + int err, pipe, size = HCI_MAX_FRAME_SIZE; + void *buf; - usb_unlink_urb(urb); usb_free_urb(urb); - husb->intr_urb = NULL; + buf = kmalloc(size, GFP_ATOMIC); + if (!buf) + return -ENOMEM; - skb = husb->intr_skb; - if (skb) { - husb->intr_skb = NULL; - kfree_skb(skb); + _urb = _urb_alloc(0, GFP_ATOMIC); + if (!_urb) { + kfree(buf); + return -ENOMEM; } + _urb->type = HCI_ACLDATA_PKT; + _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - return 0; + urb = &_urb->urb; + pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->bEndpointAddress); + FILL_BULK_URB(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb); + urb->transfer_flags = USB_QUEUE_BULK; + + BT_DBG("%s urb %p", husb->hdev.name, urb); + + err = usb_submit_urb(urb); + if (err) { + BT_ERR("%s bulk rx submit failed urb %p err %d", + husb->hdev.name, urb, err); + _urb_unlink(_urb); + _urb_free(_urb); + kfree(buf); + } + return err; } -static int hci_usb_rx_submit(struct hci_usb *husb, struct urb *urb) +#ifdef CONFIG_BLUEZ_USB_SCO +static int hci_usb_isoc_rx_submit(struct hci_usb *husb) { - struct hci_usb_scb *scb; - struct sk_buff *skb; - int pipe, size, err; + struct _urb *_urb; + struct urb *urb; + int err, mtu, size; + void *buf; - if (!urb && !(urb = usb_alloc_urb(0))) - return -ENOMEM; + mtu = husb->isoc_in_ep->wMaxPacketSize; + size = mtu * HCI_MAX_ISOC_FRAMES; - size = HCI_MAX_FRAME_SIZE; + buf = kmalloc(size, GFP_ATOMIC); + if (!buf) + return -ENOMEM; - if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) { - usb_free_urb(urb); + _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); + if (!_urb) { + kfree(buf); return -ENOMEM; } - - BT_DBG("%s urb %p", husb->hdev.name, urb); + _urb->type = HCI_SCODATA_PKT; + _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - skb->dev = (void *) &husb->hdev; - skb->pkt_type = HCI_ACLDATA_PKT; + urb = &_urb->urb; - scb = (struct hci_usb_scb *) skb->cb; - scb->urb = urb; + urb->context = husb; + urb->dev = husb->udev; + urb->pipe = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->bEndpointAddress); + urb->complete = hci_usb_rx_complete; - pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep); + urb->transfer_buffer_length = size; + urb->transfer_buffer = buf; + urb->transfer_flags = USB_ISO_ASAP; - FILL_BULK_URB(urb, husb->udev, pipe, skb->data, size, hci_usb_rx_complete, skb); - urb->transfer_flags = USB_QUEUE_BULK; + __fill_isoc_desc(urb, size, mtu); + + BT_DBG("%s urb %p", husb->hdev.name, urb); - skb_queue_tail(&husb->pending_q, skb); err = usb_submit_urb(urb); if (err) { - BT_ERR("%s bulk rx submit failed urb %p err %d", + BT_ERR("%s isoc rx submit failed urb %p err %d", husb->hdev.name, urb, err); - skb_unlink(skb); - usb_free_urb(urb); + _urb_unlink(_urb); + _urb_free(_urb); + kfree(buf); } return err; } +#endif /* Initialize device */ static int hci_usb_open(struct hci_dev *hdev) @@ -212,10 +295,14 @@ static int hci_usb_open(struct hci_dev * write_lock_irqsave(&husb->completion_lock, flags); - err = hci_usb_enable_intr(husb); + err = hci_usb_intr_rx_submit(husb); if (!err) { - for (i = 0; i < HCI_MAX_BULK_TX; i++) - hci_usb_rx_submit(husb, NULL); + for (i = 0; i < HCI_MAX_BULK_RX; i++) + hci_usb_bulk_rx_submit(husb); + +#ifdef CONFIG_BLUEZ_USB_SCO + hci_usb_isoc_rx_submit(husb); +#endif } else { clear_bit(HCI_RUNNING, &hdev->flags); MOD_DEC_USE_COUNT; @@ -229,29 +316,52 @@ static int hci_usb_open(struct hci_dev * static int hci_usb_flush(struct hci_dev *hdev) { struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + int i; BT_DBG("%s", hdev->name); - skb_queue_purge(&husb->cmd_q); - skb_queue_purge(&husb->acl_q); + for (i=0; i < 4; i++) + skb_queue_purge(&husb->transmit_q[i]); return 0; } -static inline void hci_usb_unlink_urbs(struct hci_usb *husb) +static void hci_usb_unlink_urbs(struct hci_usb *husb) { - struct sk_buff *skb; - struct urb *urb; + int i; BT_DBG("%s", husb->hdev.name); - while ((skb = skb_dequeue(&husb->pending_q))) { - urb = ((struct hci_usb_scb *) skb->cb)->urb; - usb_unlink_urb(urb); - kfree_skb(skb); - } + for (i=0; i < 4; i++) { + struct _urb *_urb; + struct urb *urb; + + /* Kill pending requests */ + while ((_urb = _urb_dequeue(&husb->pending_q[i]))) { + urb = &_urb->urb; + BT_DBG("%s unlinking _urb %p type %d urb %p", + husb->hdev.name, _urb, _urb->type, urb); + usb_unlink_urb(urb); + _urb_queue_tail(__completed_q(husb, _urb->type), _urb); + } - while ((urb = hci_usb_get_completed(husb))) - usb_free_urb(urb); + /* Release completed requests */ + while ((_urb = _urb_dequeue(&husb->completed_q[i]))) { + urb = &_urb->urb; + BT_DBG("%s freeing _urb %p type %d urb %p", + husb->hdev.name, _urb, _urb->type, urb); + if (urb->setup_packet) + kfree(urb->setup_packet); + if (urb->transfer_buffer) + kfree(urb->transfer_buffer); + _urb_free(_urb); + } + + /* Release reassembly buffers */ + if (husb->reassembly[i]) { + kfree_skb(husb->reassembly[i]); + husb->reassembly[i] = NULL; + } + } } /* Close device */ @@ -267,7 +377,6 @@ static int hci_usb_close(struct hci_dev write_lock_irqsave(&husb->completion_lock, flags); - hci_usb_disable_intr(husb); hci_usb_unlink_urbs(husb); hci_usb_flush(hdev); @@ -277,22 +386,45 @@ static int hci_usb_close(struct hci_dev return 0; } +static int __tx_submit(struct hci_usb *husb, struct _urb *_urb) +{ + struct urb *urb = &_urb->urb; + int err; + + BT_DBG("%s urb %p type %d", husb->hdev.name, urb, _urb->type); + + _urb_queue_tail(__pending_q(husb, _urb->type), _urb); + err = usb_submit_urb(urb); + if (err) { + BT_ERR("%s tx submit failed urb %p type %d err %d", + husb->hdev.name, urb, _urb->type, err); + _urb_unlink(_urb); + _urb_queue_tail(__completed_q(husb, _urb->type), _urb); + } else + atomic_inc(__pending_tx(husb, _urb->type)); + + return err; +} + static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb) { - struct hci_usb_scb *scb = (void *) skb->cb; - struct urb *urb = hci_usb_get_completed(husb); + struct _urb *_urb = __get_completed(husb, skb->pkt_type); struct usb_ctrlrequest *dr; - int pipe, err; - - if (!urb && !(urb = usb_alloc_urb(0))) - return -ENOMEM; + struct urb *urb; - if (!(dr = kmalloc(sizeof(*dr), GFP_ATOMIC))) { - usb_free_urb(urb); - return -ENOMEM; - } - - pipe = usb_sndctrlpipe(husb->udev, 0); + if (!_urb) { + _urb = _urb_alloc(0, GFP_ATOMIC); + if (!_urb) + return -ENOMEM; + _urb->type = skb->pkt_type; + + dr = kmalloc(sizeof(*dr), GFP_ATOMIC); + if (!dr) { + _urb_free(_urb); + return -ENOMEM; + } + } else + dr = (void *) _urb->urb.setup_packet; dr->bRequestType = HCI_CTRL_REQ; dr->bRequest = 0; @@ -300,81 +432,111 @@ static inline int hci_usb_send_ctrl(stru dr->wValue = 0; dr->wLength = __cpu_to_le16(skb->len); - FILL_CONTROL_URB(urb, husb->udev, pipe, (void *) dr, - skb->data, skb->len, hci_usb_tx_complete, skb); - - BT_DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len); - - scb->urb = urb; + urb = &_urb->urb; + FILL_CONTROL_URB(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0), + (void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb); - skb_queue_tail(&husb->pending_q, skb); - err = usb_submit_urb(urb); - if (err) { - BT_ERR("%s ctrl tx submit failed urb %p err %d", - husb->hdev.name, urb, err); - skb_unlink(skb); - usb_free_urb(urb); kfree(dr); - } - return err; + BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len); + + _urb->priv = skb; + return __tx_submit(husb, _urb); } static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb) { - struct hci_usb_scb *scb = (void *) skb->cb; - struct urb *urb = hci_usb_get_completed(husb); - int pipe, err; + struct _urb *_urb = __get_completed(husb, skb->pkt_type); + struct urb *urb; + int pipe; - if (!urb && !(urb = usb_alloc_urb(0))) - return -ENOMEM; + if (!_urb) { + _urb = _urb_alloc(0, GFP_ATOMIC); + if (!_urb) + return -ENOMEM; + _urb->type = skb->pkt_type; + } - pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep); - - FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, - hci_usb_tx_complete, skb); + urb = &_urb->urb; + pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->bEndpointAddress); + FILL_BULK_URB(urb, husb->udev, pipe, skb->data, skb->len, + hci_usb_tx_complete, husb); urb->transfer_flags = USB_QUEUE_BULK | USB_ZERO_PACKET; - BT_DBG("%s urb %p len %d", husb->hdev.name, urb, skb->len); + BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len); - scb->urb = urb; + _urb->priv = skb; + return __tx_submit(husb, _urb); +} - skb_queue_tail(&husb->pending_q, skb); - err = usb_submit_urb(urb); - if (err) { - BT_ERR("%s bulk tx submit failed urb %p err %d", - husb->hdev.name, urb, err); - skb_unlink(skb); - usb_free_urb(urb); +#ifdef CONFIG_BLUEZ_USB_SCO +static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb) +{ + struct _urb *_urb = __get_completed(husb, skb->pkt_type); + struct urb *urb; + + if (!_urb) { + _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); + if (!_urb) + return -ENOMEM; + _urb->type = skb->pkt_type; } - return err; + + BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len); + + urb = &_urb->urb; + + urb->context = husb; + urb->dev = husb->udev; + urb->pipe = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->bEndpointAddress); + urb->complete = hci_usb_tx_complete; + urb->transfer_flags = USB_ISO_ASAP; + + urb->transfer_buffer = skb->data; + urb->transfer_buffer_length = skb->len; + + __fill_isoc_desc(urb, skb->len, husb->isoc_out_ep->wMaxPacketSize); + + _urb->priv = skb; + return __tx_submit(husb, _urb); } +#endif static void hci_usb_tx_process(struct hci_usb *husb) { + struct sk_buff_head *q; struct sk_buff *skb; BT_DBG("%s", husb->hdev.name); do { clear_bit(HCI_USB_TX_WAKEUP, &husb->state); + + /* Process command queue */ + q = __transmit_q(husb, HCI_COMMAND_PKT); + if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) && + (skb = skb_dequeue(q))) { + if (hci_usb_send_ctrl(husb, skb) < 0) + skb_queue_head(q, skb); + } + +#ifdef CONFIG_BLUEZ_USB_SCO + /* Process SCO queue */ + q = __transmit_q(husb, HCI_SCODATA_PKT); + if (!atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) && + (skb = skb_dequeue(q))) { + if (hci_usb_send_isoc(husb, skb) < 0) + skb_queue_head(q, skb); + } +#endif /* Process ACL queue */ - while (skb_queue_len(&husb->pending_q) < HCI_MAX_PENDING && - (skb = skb_dequeue(&husb->acl_q))) { + q = __transmit_q(husb, HCI_ACLDATA_PKT); + while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX && + (skb = skb_dequeue(q))) { if (hci_usb_send_bulk(husb, skb) < 0) { - skb_queue_head(&husb->acl_q, skb); + skb_queue_head(q, skb); break; } } - - /* Process command queue */ - if (!test_bit(HCI_USB_CTRL_TX, &husb->state) && - (skb = skb_dequeue(&husb->cmd_q)) != NULL) { - set_bit(HCI_USB_CTRL_TX, &husb->state); - if (hci_usb_send_ctrl(husb, skb) < 0) { - skb_queue_head(&husb->cmd_q, skb); - clear_bit(HCI_USB_CTRL_TX, &husb->state); - } - } } while(test_bit(HCI_USB_TX_WAKEUP, &husb->state)); } @@ -389,7 +551,7 @@ static inline void hci_usb_tx_wakeup(str } /* Send frames from HCI layer */ -int hci_usb_send_frame(struct sk_buff *skb) +static int hci_usb_send_frame(struct sk_buff *skb) { struct hci_dev *hdev = (struct hci_dev *) skb->dev; struct hci_usb *husb; @@ -402,204 +564,207 @@ int hci_usb_send_frame(struct sk_buff *s if (!test_bit(HCI_RUNNING, &hdev->flags)) return -EBUSY; - husb = (struct hci_usb *) hdev->driver_data; - BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); - read_lock(&husb->completion_lock); + husb = (struct hci_usb *) hdev->driver_data; switch (skb->pkt_type) { case HCI_COMMAND_PKT: - skb_queue_tail(&husb->cmd_q, skb); hdev->stat.cmd_tx++; break; case HCI_ACLDATA_PKT: - skb_queue_tail(&husb->acl_q, skb); hdev->stat.acl_tx++; break; +#ifdef CONFIG_BLUEZ_USB_SCO case HCI_SCODATA_PKT: + hdev->stat.sco_tx++; + break; +#endif + default: kfree_skb(skb); - break; + return 0; } + + read_lock(&husb->completion_lock); + + skb_queue_tail(__transmit_q(husb, skb->pkt_type), skb); hci_usb_tx_wakeup(husb); read_unlock(&husb->completion_lock); return 0; } -static void hci_usb_interrupt(struct urb *urb) +static inline int __recv_frame(struct hci_usb *husb, int type, void *data, int count) { - struct hci_usb *husb = (void *) urb->context; - struct hci_usb_scb *scb; - struct sk_buff *skb; - hci_event_hdr *eh; - __u8 *data = urb->transfer_buffer; - int count = urb->actual_length; - int len = HCI_EVENT_HDR_SIZE; - - BT_DBG("%s urb %p count %d", husb->hdev.name, urb, count); - - if (!test_bit(HCI_RUNNING, &husb->hdev.flags)) - return; - - if (urb->status || !count) { - BT_DBG("%s intr status %d, count %d", - husb->hdev.name, urb->status, count); - return; - } + BT_DBG("%s type %d data %p count %d", husb->hdev.name, type, data, count); - read_lock(&husb->completion_lock); - husb->hdev.stat.byte_rx += count; - if (!(skb = husb->intr_skb)) { - /* Start of the frame */ - if (count < HCI_EVENT_HDR_SIZE) - goto bad_len; + while (count) { + struct sk_buff *skb = __reassembly(husb, type); + struct { int expect; } *scb; + int len = 0; + + if (!skb) { + /* Start of the frame */ - eh = (hci_event_hdr *) data; - len = eh->plen + HCI_EVENT_HDR_SIZE; + switch (type) { + case HCI_EVENT_PKT: + if (count >= HCI_EVENT_HDR_SIZE) { + hci_event_hdr *h = data; + len = HCI_EVENT_HDR_SIZE + h->plen; + } else + return -EILSEQ; + break; - if (count > len) - goto bad_len; + case HCI_ACLDATA_PKT: + if (count >= HCI_ACL_HDR_SIZE) { + hci_acl_hdr *h = data; + len = HCI_ACL_HDR_SIZE + __le16_to_cpu(h->dlen); + } else + return -EILSEQ; + break; +#ifdef CONFIG_BLUEZ_USB_SCO + case HCI_SCODATA_PKT: + if (count >= HCI_SCO_HDR_SIZE) { + hci_sco_hdr *h = data; + len = HCI_SCO_HDR_SIZE + h->dlen; + } else + return -EILSEQ; + break; +#endif + } + BT_DBG("new packet len %d", len); + + skb = bluez_skb_alloc(len, GFP_ATOMIC); + if (!skb) { + BT_ERR("%s no memory for the packet", husb->hdev.name); + return -ENOMEM; + } + skb->dev = (void *) &husb->hdev; + skb->pkt_type = type; + + __reassembly(husb, type) = skb; - skb = bluez_skb_alloc(len, GFP_ATOMIC); - if (!skb) { - BT_ERR("%s no memory for event packet", husb->hdev.name); - goto done; + scb = (void *) skb->cb; + scb->expect = len; + } else { + /* Continuation */ + scb = (void *) skb->cb; + len = scb->expect; } - scb = (void *) skb->cb; - skb->dev = (void *) &husb->hdev; - skb->pkt_type = HCI_EVENT_PKT; + len = min(len, count); + + memcpy(skb_put(skb, len), data, len); - husb->intr_skb = skb; - scb->intr_len = len; - } else { - /* Continuation */ - scb = (void *) skb->cb; - len = scb->intr_len; - if (count > len) { - husb->intr_skb = NULL; - kfree_skb(skb); - goto bad_len; + scb->expect -= len; + if (!scb->expect) { + /* Complete frame */ + __reassembly(husb, type) = NULL; + hci_recv_frame(skb); } - } - memcpy(skb_put(skb, count), data, count); - scb->intr_len -= count; - - if (!scb->intr_len) { - /* Complete frame */ - husb->intr_skb = NULL; - hci_recv_frame(skb); + count -= len; data += len; } - -done: - read_unlock(&husb->completion_lock); - return; - -bad_len: - BT_ERR("%s bad frame len %d expected %d", husb->hdev.name, count, len); - husb->hdev.stat.err_rx++; - read_unlock(&husb->completion_lock); + return 0; } -static void hci_usb_tx_complete(struct urb *urb) +static void hci_usb_rx_complete(struct urb *urb) { - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; + struct _urb *_urb = container_of(urb, struct _urb, urb); + struct hci_usb *husb = (void *) urb->context; + struct hci_dev *hdev = &husb->hdev; + int err, count = urb->actual_length; - BT_DBG("%s urb %p status %d flags %x", husb->hdev.name, urb, - urb->status, urb->transfer_flags); - - if (urb->pipe == usb_sndctrlpipe(husb->udev, 0)) { - kfree(urb->setup_packet); - clear_bit(HCI_USB_CTRL_TX, &husb->state); - } + BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb, + _urb->type, urb->status, count, urb->transfer_flags); if (!test_bit(HCI_RUNNING, &hdev->flags)) return; read_lock(&husb->completion_lock); - - if (!urb->status) - husb->hdev.stat.byte_tx += skb->len; - else - husb->hdev.stat.err_tx++; - skb_unlink(skb); - skb_queue_tail(&husb->completed_q, skb); - hci_usb_tx_wakeup(husb); - + if (urb->status || !count) + goto resubmit; + + if (_urb->type == HCI_SCODATA_PKT) { +#ifdef CONFIG_BLUEZ_USB_SCO + int i; + for (i=0; i < urb->number_of_packets; i++) { + BT_DBG("desc %d status %d offset %d len %d", i, + urb->iso_frame_desc[i].status, + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + + if (!urb->iso_frame_desc[i].status) + __recv_frame(husb, _urb->type, + urb->transfer_buffer + urb->iso_frame_desc[i].offset, + urb->iso_frame_desc[i].actual_length); + } +#else + ; +#endif + } else { + err = __recv_frame(husb, _urb->type, urb->transfer_buffer, count); + if (err < 0) { + BT_ERR("%s corrupted packet: type %d count %d", + husb->hdev.name, _urb->type, count); + hdev->stat.err_rx++; + } + } + +resubmit: + if (_urb->type != HCI_EVENT_PKT) { + urb->dev = husb->udev; + err = usb_submit_urb(urb); + BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb, + _urb->type, err); + } read_unlock(&husb->completion_lock); - return; } -static void hci_usb_rx_complete(struct urb *urb) +static void hci_usb_tx_complete(struct urb *urb) { - struct sk_buff *skb = (struct sk_buff *) urb->context; - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - int status, count = urb->actual_length; - hci_acl_hdr *ah; - int dlen, size; + struct _urb *_urb = container_of(urb, struct _urb, urb); + struct hci_usb *husb = (void *) urb->context; + struct hci_dev *hdev = &husb->hdev; - BT_DBG("%s urb %p status %d count %d flags %x", husb->hdev.name, urb, - urb->status, count, urb->transfer_flags); + BT_DBG("%s urb %p status %d flags %x", hdev->name, urb, + urb->status, urb->transfer_flags); - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return; + atomic_dec(__pending_tx(husb, _urb->type)); - read_lock(&husb->completion_lock); + urb->transfer_buffer = NULL; + kfree_skb((struct sk_buff *) _urb->priv); - if (urb->status || !count) - goto resubmit; - - husb->hdev.stat.byte_rx += count; + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return; - ah = (hci_acl_hdr *) skb->data; - dlen = __le16_to_cpu(ah->dlen); - size = HCI_ACL_HDR_SIZE + dlen; - - /* Verify frame len and completeness */ - if (count != size) { - BT_ERR("%s corrupted ACL packet: count %d, dlen %d", - husb->hdev.name, count, dlen); - bluez_dump("hci_usb", skb->data, count); - husb->hdev.stat.err_rx++; - goto resubmit; - } + if (!urb->status) + hdev->stat.byte_tx += urb->transfer_buffer_length; + else + hdev->stat.err_tx++; - skb_unlink(skb); - skb_put(skb, count); - hci_recv_frame(skb); + read_lock(&husb->completion_lock); - hci_usb_rx_submit(husb, urb); + _urb_unlink(_urb); + _urb_queue_tail(__completed_q(husb, _urb->type), _urb); - read_unlock(&husb->completion_lock); - return; - -resubmit: - urb->dev = husb->udev; - status = usb_submit_urb(urb); - BT_DBG("%s URB resubmit status %d", husb->hdev.name, status); + hci_usb_tx_wakeup(husb); + read_unlock(&husb->completion_lock); } static void hci_usb_destruct(struct hci_dev *hdev) { - struct hci_usb *husb; - - if (!hdev) return; + struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; BT_DBG("%s", hdev->name); - husb = (struct hci_usb *) hdev->driver_data; kfree(husb); } @@ -662,6 +827,7 @@ static void *hci_usb_probe(struct usb_de bulk_out_ep[i] = ep; break; +#ifdef CONFIG_BLUEZ_USB_SCO case USB_ENDPOINT_XFER_ISOC: if (ep->wMaxPacketSize < size) break; @@ -676,6 +842,7 @@ static void *hci_usb_probe(struct usb_de else isoc_out_ep[i] = ep; break; +#endif } } } @@ -686,10 +853,12 @@ static void *hci_usb_probe(struct usb_de goto done; } +#ifdef CONFIG_BLUEZ_USB_SCO if (!isoc_in_ep[1] || !isoc_out_ep[1]) { BT_DBG("Isoc endpoints not found"); isoc_iface = NULL; } +#endif if (!(husb = kmalloc(sizeof(struct hci_usb), GFP_KERNEL))) { BT_ERR("Can't allocate: control structure"); @@ -699,35 +868,36 @@ static void *hci_usb_probe(struct usb_de memset(husb, 0, sizeof(struct hci_usb)); husb->udev = udev; - husb->bulk_out_ep = bulk_out_ep[0]->bEndpointAddress; - husb->bulk_in_ep = bulk_in_ep[0]->bEndpointAddress; - - husb->intr_ep = intr_in_ep[0]->bEndpointAddress; - husb->intr_interval = intr_in_ep[0]->bInterval; + husb->bulk_out_ep = bulk_out_ep[0]; + husb->bulk_in_ep = bulk_in_ep[0]; + husb->intr_in_ep = intr_in_ep[0]; +#ifdef CONFIG_BLUEZ_USB_SCO if (isoc_iface) { + BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts); if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) { BT_ERR("Can't set isoc interface settings"); isoc_iface = NULL; } usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb); husb->isoc_iface = isoc_iface; - - husb->isoc_in_ep = isoc_in_ep[1]->bEndpointAddress; - husb->isoc_out_ep = isoc_in_ep[1]->bEndpointAddress; + husb->isoc_in_ep = isoc_in_ep[isoc_ifnum]; + husb->isoc_out_ep = isoc_out_ep[isoc_ifnum]; } - - husb->completion_lock = RW_LOCK_UNLOCKED; +#endif - skb_queue_head_init(&husb->acl_q); - skb_queue_head_init(&husb->cmd_q); - skb_queue_head_init(&husb->pending_q); - skb_queue_head_init(&husb->completed_q); + husb->completion_lock = RW_LOCK_UNLOCKED; + + for (i = 0; i < 4; i++) { + skb_queue_head_init(&husb->transmit_q[i]); + _urb_queue_init(&husb->pending_q[i]); + _urb_queue_init(&husb->completed_q[i]); + } /* Initialize and register HCI device */ hdev = &husb->hdev; - hdev->type = HCI_USB; + hdev->type = HCI_USB; hdev->driver_data = husb; hdev->open = hci_usb_open; diff -Naurp linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_usb.h linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_usb.h --- linux-2.4.20-wolk4.1s/drivers/bluetooth/hci_usb.h 2002-12-18 01:03:50.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/bluetooth/hci_usb.h 2003-06-03 20:02:49.000000000 +0200 @@ -1,9 +1,10 @@ /* - BlueZ - Bluetooth protocol stack for Linux + HCI USB driver for Linux Bluetooth protocol stack (BlueZ) Copyright (C) 2000-2001 Qualcomm Incorporated - Written 2000,2001 by Maxim Krasnyansky + Copyright (C) 2003 Maxim Krasnyansky + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation; @@ -40,40 +41,96 @@ #define HCI_MAX_BULK_TX 4 #define HCI_MAX_BULK_RX 1 +#define HCI_MAX_ISOC_FRAMES 10 + +struct _urb_queue { + struct list_head head; + spinlock_t lock; +}; + +struct _urb { + struct list_head list; + struct _urb_queue *queue; + int type; + void *priv; + struct urb urb; +}; + +struct _urb *_urb_alloc(int isoc, int gfp); + +static inline void _urb_free(struct _urb *_urb) +{ + kfree(_urb); +} + +static inline void _urb_queue_init(struct _urb_queue *q) +{ + INIT_LIST_HEAD(&q->head); + spin_lock_init(&q->lock); +} + +static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb) +{ + unsigned long flags; + spin_lock_irqsave(&q->lock, flags); + list_add(&_urb->list, &q->head); _urb->queue = q; + spin_unlock_irqrestore(&q->lock, flags); +} + +static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb) +{ + unsigned long flags; + spin_lock_irqsave(&q->lock, flags); + list_add_tail(&_urb->list, &q->head); _urb->queue = q; + spin_unlock_irqrestore(&q->lock, flags); +} + +static inline void _urb_unlink(struct _urb *_urb) +{ + struct _urb_queue *q = _urb->queue; + unsigned long flags; + if (q) { + spin_lock_irqsave(&q->lock, flags); + list_del(&_urb->list); _urb->queue = NULL; + spin_unlock_irqrestore(&q->lock, flags); + } +} + +struct _urb *_urb_dequeue(struct _urb_queue *q); + +#ifndef container_of +#define container_of(ptr, type, member) ({ \ + const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type,member) );}) +#endif + struct hci_usb { struct hci_dev hdev; unsigned long state; struct usb_device *udev; - struct usb_interface *isoc_iface; - __u8 bulk_out_ep; - __u8 bulk_in_ep; - __u8 isoc_out_ep; - __u8 isoc_in_ep; - - __u8 intr_ep; - __u8 intr_interval; - struct urb *intr_urb; - struct sk_buff * intr_skb; + struct usb_endpoint_descriptor *bulk_in_ep; + struct usb_endpoint_descriptor *bulk_out_ep; + struct usb_endpoint_descriptor *intr_in_ep; + + struct usb_interface *isoc_iface; + struct usb_endpoint_descriptor *isoc_out_ep; + struct usb_endpoint_descriptor *isoc_in_ep; + + struct sk_buff_head transmit_q[4]; + struct sk_buff *reassembly[4]; // Reassembly buffers rwlock_t completion_lock; - - struct sk_buff_head cmd_q; // TX Commands - struct sk_buff_head acl_q; // TX ACLs - struct sk_buff_head pending_q; // Pending requests - struct sk_buff_head completed_q; // Completed requests -}; -struct hci_usb_scb { - struct urb *urb; - int intr_len; + atomic_t pending_tx[4]; // Number of pending requests + struct _urb_queue pending_q[4]; // Pending requests + struct _urb_queue completed_q[4]; // Completed requests }; /* States */ #define HCI_USB_TX_PROCESS 1 #define HCI_USB_TX_WAKEUP 2 -#define HCI_USB_CTRL_TX 3 #endif /* __KERNEL__ */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/char/Config.in linux-2.4.20-wolk4.2-fullkernel/drivers/char/Config.in --- linux-2.4.20-wolk4.1s/drivers/char/Config.in 2003-05-15 21:52:23.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/char/Config.in 2003-06-02 17:21:07.000000000 +0200 @@ -306,7 +306,9 @@ if [ "$CONFIG_AGP" != "n" ]; then bool ' Generic SiS support' CONFIG_AGP_SIS bool ' ALI chipset support' CONFIG_AGP_ALI bool ' Serverworks LE/HE support' CONFIG_AGP_SWORKS - bool ' Nvidia Nforce2 support' CONFIG_AGP_NV + if [ "$CONFIG_X86" = "y" ]; then + bool ' NVIDIA chipset support' CONFIG_AGP_NVIDIA + fi if [ "$CONFIG_IA64" = "y" ]; then bool ' HP ZX1 AGP support' CONFIG_AGP_HP_ZX1 fi diff -Naurp linux-2.4.20-wolk4.1s/drivers/char/agp/agp.h linux-2.4.20-wolk4.2-fullkernel/drivers/char/agp/agp.h --- linux-2.4.20-wolk4.1s/drivers/char/agp/agp.h 2003-05-15 21:52:23.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/char/agp/agp.h 2003-06-02 17:21:07.000000000 +0200 @@ -271,9 +271,6 @@ struct agp_bridge_data { #ifndef PCI_DEVICE_ID_AL_M1671_0 #define PCI_DEVICE_ID_AL_M1671_0 0x1671 #endif -#ifndef PCI_DEVICE_ID_NV_NFORCE2_0 -#define PCI_DEVICE_ID_NV_NFORCE2_0 0x01e0 -#endif /* intel register */ #define INTEL_APBASE 0x10 @@ -415,16 +412,16 @@ struct agp_bridge_data { #define SVWRKS_POSTFLUSH 0x14 #define SVWRKS_DIRFLUSH 0x0c -/* NVidia registers */ -#define NVIDIA_0_APBASE 0x10 -#define NVIDIA_0_APSIZE 0x80 -#define NVIDIA_1_WBC 0xf0 -#define NVIDIA_2_GARTCTRL 0xd0 -#define NVIDIA_2_APBASE 0xd8 -#define NVIDIA_2_APLIMIT 0xdc -#define NVIDIA_2_ATTBASE(i) (0xe0 + (i) * 4) -#define NVIDIA_3_APBASE 0x50 -#define NVIDIA_3_APLIMIT 0x54 +/* NVIDIA registers */ +#define NVIDIA_0_APBASE 0x10 +#define NVIDIA_0_APSIZE 0x80 +#define NVIDIA_1_WBC 0xf0 +#define NVIDIA_2_GARTCTRL 0xd0 +#define NVIDIA_2_APBASE 0xd8 +#define NVIDIA_2_APLIMIT 0xdc +#define NVIDIA_2_ATTBASE(i) (0xe0 + (i) * 4) +#define NVIDIA_3_APBASE 0x50 +#define NVIDIA_3_APLIMIT 0x54 /* HP ZX1 SBA registers */ #define HP_ZX1_CTRL 0x200 diff -Naurp linux-2.4.20-wolk4.1s/drivers/char/agp/agpgart_be.c linux-2.4.20-wolk4.2-fullkernel/drivers/char/agp/agpgart_be.c --- linux-2.4.20-wolk4.1s/drivers/char/agp/agpgart_be.c 2003-05-15 21:52:23.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/char/agp/agpgart_be.c 2003-06-02 17:21:07.000000000 +0200 @@ -43,6 +43,9 @@ #include #include #include +#ifdef CONFIG_AGP_NVIDIA + #include +#endif #include #include "agp.h" @@ -3418,7 +3421,7 @@ static struct _serverworks_private { } serverworks_private; static int serverworks_create_page_map(serverworks_page_map *page_map) -{ +{ int i; int err = 0; @@ -4003,22 +4006,7 @@ static int __init serverworks_setup (str #endif /* CONFIG_AGP_SWORKS */ -#ifdef CONFIG_AGP_NV - -static aper_size_info_8 nvidia_generic_sizes[5] = -{ - {512, 131072, 7, 0}, - {256, 65536, 6, 8}, - {128, 32768, 5, 12}, - {64, 16384, 4, 14}, - /* The 32M mode still requires a 64k gatt */ - {32, 16384, 4, 15} -}; - -static gatt_mask nvidia_generic_masks[] = -{ - {0x00000001, 0} -}; +#ifdef CONFIG_AGP_NVIDIA static struct _nvidia_private { struct pci_dev *dev_1; @@ -4027,7 +4015,6 @@ static struct _nvidia_private { volatile u32 *aperture; int num_active_entries; off_t pg_offset; - u32 wbc_mask; } nvidia_private; static int nvidia_fetch_size(void) @@ -4052,9 +4039,55 @@ static int nvidia_fetch_size(void) return 0; } +#define SYSCFG 0xC0010010 +#define IORR_BASE0 0xC0010016 +#define IORR_MASK0 0xC0010017 +#define AMD_K7_NUM_IORR 2 + +static int nvidia_init_iorr(u32 base, u32 size) +{ + u32 base_hi, base_lo; + u32 mask_hi, mask_lo; + u32 sys_hi, sys_lo; + u32 iorr_addr, free_iorr_addr; + + /* Find the iorr that is already used for the base */ + /* If not found, determine the uppermost available iorr */ + free_iorr_addr = AMD_K7_NUM_IORR; + for(iorr_addr = 0; iorr_addr < AMD_K7_NUM_IORR; iorr_addr++) { + rdmsr(IORR_BASE0 + 2 * iorr_addr, base_lo, base_hi); + rdmsr(IORR_MASK0 + 2 * iorr_addr, mask_lo, mask_hi); + + if ((base_lo & 0xfffff000) == (base & 0xfffff000)) + break; + + if ((mask_lo & 0x00000800) == 0) + free_iorr_addr = iorr_addr; + } + + if (iorr_addr >= AMD_K7_NUM_IORR) { + iorr_addr = free_iorr_addr; + if (iorr_addr >= AMD_K7_NUM_IORR) + return -EINVAL; + } + + base_hi = 0x0; + base_lo = (base & ~0xfff) | 0x18; + mask_hi = 0xf; + mask_lo = ((~(size - 1)) & 0xfffff000) | 0x800; + wrmsr(IORR_BASE0 + 2 * iorr_addr, base_lo, base_hi); + wrmsr(IORR_MASK0 + 2 * iorr_addr, mask_lo, mask_hi); + + rdmsr(SYSCFG, sys_lo, sys_hi); + sys_lo |= 0x00100000; + wrmsr(SYSCFG, sys_lo, sys_hi); + + return 0; +} + static int nvidia_configure(void) { - int i, num_dirs; + int i, rc, num_dirs; u32 apbase, aplimit; aper_size_info_8 *current_size; u32 temp; @@ -4074,6 +4107,8 @@ static int nvidia_configure(void) pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APLIMIT, aplimit); pci_write_config_dword(nvidia_private.dev_3, NVIDIA_3_APBASE, apbase); pci_write_config_dword(nvidia_private.dev_3, NVIDIA_3_APLIMIT, aplimit); + if (0 != (rc = nvidia_init_iorr(apbase, current_size->size * 1024 * 1024))) + return rc; /* directory size is 64k */ num_dirs = current_size->size / 64; @@ -4094,11 +4129,13 @@ static int nvidia_configure(void) /* gtlb control */ pci_read_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, &temp); - pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, temp | 0x11); + pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, + temp | 0x11); /* gart control */ pci_read_config_dword(agp_bridge.dev, NVIDIA_0_APSIZE, &temp); - pci_write_config_dword(agp_bridge.dev, NVIDIA_0_APSIZE, temp | 0x100); + pci_write_config_dword(agp_bridge.dev, NVIDIA_0_APSIZE, + temp | 0x100); /* map aperture */ nvidia_private.aperture = @@ -4114,11 +4151,13 @@ static void nvidia_cleanup(void) /* gart control */ pci_read_config_dword(agp_bridge.dev, NVIDIA_0_APSIZE, &temp); - pci_write_config_dword(agp_bridge.dev, NVIDIA_0_APSIZE, temp & ~(0x100)); + pci_write_config_dword(agp_bridge.dev, NVIDIA_0_APSIZE, + temp & ~(0x100)); /* gtlb control */ pci_read_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, &temp); - pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, temp & ~(0x11)); + pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, + temp & ~(0x11)); /* unmap aperture */ iounmap((void *) nvidia_private.aperture); @@ -4127,29 +4166,43 @@ static void nvidia_cleanup(void) previous_size = A_SIZE_8(agp_bridge.previous_size); pci_write_config_byte(agp_bridge.dev, NVIDIA_0_APSIZE, previous_size->size_value); + + /* restore iorr for previous aperture size */ + nvidia_init_iorr(agp_bridge.gart_bus_addr, + previous_size->size * 1024 * 1024); } static void nvidia_tlbflush(agp_memory * mem) { - unsigned long end; - u32 wbc_reg, temp; int i; + unsigned long end; + u32 wbc_reg, wbc_mask, temp; /* flush chipset */ - if (nvidia_private.wbc_mask) { + switch(agp_bridge.type) { + case NVIDIA_NFORCE: + wbc_mask = 0x00010000; + break; + case NVIDIA_NFORCE2: + wbc_mask = 0x80000000; + break; + default: + wbc_mask = 0; + break; + } + + if (wbc_mask) { pci_read_config_dword(nvidia_private.dev_1, NVIDIA_1_WBC, &wbc_reg); - wbc_reg |= nvidia_private.wbc_mask; + wbc_reg |= wbc_mask; pci_write_config_dword(nvidia_private.dev_1, NVIDIA_1_WBC, wbc_reg); end = jiffies + 3*HZ; do { - pci_read_config_dword(nvidia_private.dev_1, - NVIDIA_1_WBC, &wbc_reg); + pci_read_config_dword(nvidia_private.dev_1, NVIDIA_1_WBC, &wbc_reg); if ((signed)(end - jiffies) <= 0) { - printk(KERN_ERR - "TLB flush took more than 3 seconds.\n"); + printk(KERN_ERR "TLB flush took more than 3 seconds.\n"); } - } while (wbc_reg & nvidia_private.wbc_mask); + } while (wbc_reg & wbc_mask); } /* flush TLB entries */ @@ -4162,13 +4215,12 @@ static void nvidia_tlbflush(agp_memory * static unsigned long nvidia_mask_memory(unsigned long addr, int type) { /* Memory type is ignored */ + return addr | agp_bridge.masks[0].mask; } -#if 0 -extern int agp_memory_reserved; - -static int nvidia_insert_memory(agp_memory * mem, off_t pg_start, int type) +static int nvidia_insert_memory(agp_memory * mem, + off_t pg_start, int type) { int i, j; @@ -4180,22 +4232,25 @@ static int nvidia_insert_memory(agp_memo return -EINVAL; for(j = pg_start; j < (pg_start + mem->page_count); j++) { - if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[nvidia_private.pg_offset + j])) + if (!PGE_EMPTY(agp_bridge.gatt_table[nvidia_private.pg_offset + j])) { return -EBUSY; + } } if (mem->is_flushed == FALSE) { - global_cache_flush(); + CACHE_FLUSH(); mem->is_flushed = TRUE; } - for (i = 0, j = pg_start; i < mem->page_count; i++, j++) - agp_bridge->gatt_table[nvidia_private.pg_offset + j] = mem->memory[i]; + for (i = 0, j = pg_start; i < mem->page_count; i++, j++) { + agp_bridge.gatt_table[nvidia_private.pg_offset + j] = mem->memory[i]; + } - agp_bridge->tlb_flush(mem); + agp_bridge.tlb_flush(mem); return 0; } -static int nvidia_remove_memory(agp_memory * mem, off_t pg_start, int type) +static int nvidia_remove_memory(agp_memory * mem, off_t pg_start, + int type) { int i; @@ -4203,14 +4258,28 @@ static int nvidia_remove_memory(agp_memo return -EINVAL; for (i = pg_start; i < (mem->page_count + pg_start); i++) { - agp_bridge->gatt_table[nvidia_private.pg_offset + i] = - (unsigned long) agp_bridge->scratch_page; + agp_bridge.gatt_table[nvidia_private.pg_offset + i] = + (unsigned long) agp_bridge.scratch_page; } - agp_bridge->tlb_flush(mem); + agp_bridge.tlb_flush(mem); return 0; } -#endif + +static aper_size_info_8 nvidia_generic_sizes[5] = +{ + {512, 131072, 7, 0}, + {256, 65536, 6, 8}, + {128, 32768, 5, 12}, + {64, 16384, 4, 14}, + /* The 32M mode still requires a 64k gatt */ + {32, 16384, 4, 15} +}; + +static gatt_mask nvidia_generic_masks[] = +{ + {0x00000001, 0} +}; static int __init nvidia_generic_setup (struct pci_dev *pdev) { @@ -4220,11 +4289,22 @@ static int __init nvidia_generic_setup ( pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2)); nvidia_private.dev_3 = pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0)); - nvidia_private.wbc_mask = 0x80000000; + + if((nvidia_private.dev_1 == NULL) || + (nvidia_private.dev_2 == NULL) || + (nvidia_private.dev_3 == NULL)) { + printk(KERN_INFO PFX "agpgart: Detected an NVIDIA " + "nForce/nForce2 chipset, but could not find " + "the secondary devices.\n"); + agp_bridge.type = NOT_SUPPORTED; + return -ENODEV; + } + agp_bridge.masks = nvidia_generic_masks; agp_bridge.aperture_sizes = (void *) nvidia_generic_sizes; agp_bridge.size_type = U8_APER_SIZE; agp_bridge.num_aperture_sizes = 5; + agp_bridge.dev_private_data = (void *) &nvidia_private; agp_bridge.needs_scratch_page = FALSE; agp_bridge.configure = nvidia_configure; agp_bridge.fetch_size = nvidia_fetch_size; @@ -4235,8 +4315,8 @@ static int __init nvidia_generic_setup ( agp_bridge.cache_flush = global_cache_flush; agp_bridge.create_gatt_table = agp_generic_create_gatt_table; agp_bridge.free_gatt_table = agp_generic_free_gatt_table; - agp_bridge.insert_memory = agp_generic_insert_memory; - agp_bridge.remove_memory = agp_generic_remove_memory; + agp_bridge.insert_memory = nvidia_insert_memory; + agp_bridge.remove_memory = nvidia_remove_memory; agp_bridge.alloc_by_type = agp_generic_alloc_by_type; agp_bridge.free_by_type = agp_generic_free_by_type; agp_bridge.agp_alloc_page = agp_generic_alloc_page; @@ -4244,14 +4324,11 @@ static int __init nvidia_generic_setup ( agp_bridge.suspend = agp_generic_suspend; agp_bridge.resume = agp_generic_resume; agp_bridge.cant_use_aperture = 0; - agp_bridge.dev_private_data = &nvidia_private; return 0; - - (void) pdev; /* unused */ } -#endif /* CONFIG_AGP_NV */ +#endif /* CONFIG_AGP_NVIDIA */ #ifdef CONFIG_AGP_HP_ZX1 @@ -4970,14 +5047,26 @@ static struct { via_generic_setup }, #endif /* CONFIG_AGP_VIA */ -#ifdef CONFIG_AGP_NV - { PCI_DEVICE_ID_NV_NFORCE2_0, +#ifdef CONFIG_AGP_NVIDIA + { PCI_DEVICE_ID_NVIDIA_NFORCE, + PCI_VENDOR_ID_NVIDIA, + NVIDIA_NFORCE, + "NVIDIA", + "nForce", + nvidia_generic_setup }, + { PCI_DEVICE_ID_NVIDIA_NFORCE2, PCI_VENDOR_ID_NVIDIA, - NV_NFORCE_2, - "Nvidia", - "Nforce2", + NVIDIA_NFORCE2, + "NVIDIA", + "nForce2", + nvidia_generic_setup }, + { 0, + PCI_VENDOR_ID_NVIDIA, + NVIDIA_GENERIC, + "NVIDIA", + "Generic", nvidia_generic_setup }, -#endif /* CONFIG_AGP_NV */ +#endif /* CONFIG_AGP_NVIDIA */ #ifdef CONFIG_AGP_HP_ZX1 { PCI_DEVICE_ID_HP_ZX1_LBA, diff -Naurp linux-2.4.20-wolk4.1s/drivers/char/console.c linux-2.4.20-wolk4.2-fullkernel/drivers/char/console.c --- linux-2.4.20-wolk4.1s/drivers/char/console.c 2003-05-15 21:52:23.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/char/console.c 2003-06-04 21:14:31.000000000 +0200 @@ -696,11 +696,13 @@ int vc_allocate(unsigned int currcons) / kmalloced = 1; vc_init(currcons, video_num_lines, video_num_columns, 1); +#ifdef CONFIG_PM if (!pm_con) { pm_con = pm_register(PM_SYS_DEV, PM_SYS_VGA, pm_con_request); } +#endif } return 0; } diff -Naurp linux-2.4.20-wolk4.1s/drivers/char/drm/mga_dma.c linux-2.4.20-wolk4.2-fullkernel/drivers/char/drm/mga_dma.c --- linux-2.4.20-wolk4.1s/drivers/char/drm/mga_dma.c 2003-05-15 21:52:24.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/char/drm/mga_dma.c 2003-06-02 17:21:02.000000000 +0200 @@ -61,6 +61,7 @@ int mga_do_wait_for_idle( drm_mga_privat MGA_WRITE8( MGA_CRTC_INDEX, 0 ); return 0; } + cond_resched(); udelay( 1 ); } @@ -80,6 +81,7 @@ int mga_do_dma_idle( drm_mga_private_t * for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { status = MGA_READ( MGA_STATUS ) & MGA_DMA_IDLE_MASK; if ( status == MGA_ENDPRDMASTS ) return 0; + cond_resched(); udelay( 1 ); } @@ -121,6 +123,7 @@ int mga_do_engine_reset( drm_mga_private * How about we clean up after ourselves? */ MGA_WRITE( MGA_RST, MGA_SOFTRESET ); + cond_resched(); /* We shouldn't get here anyway... */ udelay( 15 ); /* Wait at least 10 usecs */ MGA_WRITE( MGA_RST, 0 ); diff -Naurp linux-2.4.20-wolk4.1s/drivers/char/drm/r128_cce.c linux-2.4.20-wolk4.2-fullkernel/drivers/char/drm/r128_cce.c --- linux-2.4.20-wolk4.1s/drivers/char/drm/r128_cce.c 2003-05-15 21:52:24.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/char/drm/r128_cce.c 2003-06-02 17:21:02.000000000 +0200 @@ -128,6 +128,7 @@ static int r128_do_pixcache_flush( drm_r if ( !(R128_READ( R128_PC_NGUI_CTLSTAT ) & R128_PC_BUSY) ) { return 0; } + cond_resched(); udelay( 1 ); } @@ -144,6 +145,7 @@ static int r128_do_wait_for_fifo( drm_r1 for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { int slots = R128_READ( R128_GUI_STAT ) & R128_GUI_FIFOCNT_MASK; if ( slots >= entries ) return 0; + cond_resched(); udelay( 1 ); } @@ -165,6 +167,7 @@ int r128_do_wait_for_idle( drm_r128_priv r128_do_pixcache_flush( dev_priv ); return 0; } + cond_resched(); udelay( 1 ); } @@ -225,6 +228,7 @@ int r128_do_cce_idle( drm_r128_private_t return r128_do_pixcache_flush( dev_priv ); } } + cond_resched(); udelay( 1 ); } @@ -924,6 +928,7 @@ drm_buf_t *r128_freelist_get( drm_device return buf; } } + cond_resched(); udelay( 1 ); } @@ -957,6 +962,7 @@ int r128_wait_ring( drm_r128_private_t * r128_update_ring_snapshot( ring ); if ( ring->space >= n ) return 0; + cond_resched(); udelay( 1 ); } diff -Naurp linux-2.4.20-wolk4.1s/drivers/char/pc_keyb.c linux-2.4.20-wolk4.2-fullkernel/drivers/char/pc_keyb.c --- linux-2.4.20-wolk4.1s/drivers/char/pc_keyb.c 2003-05-15 21:52:26.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/char/pc_keyb.c 2003-06-02 17:23:43.000000000 +0200 @@ -807,6 +807,15 @@ static char * __init initialize_kbd(void int status; /* + * This is not really IA-64 specific. Probably ought to be done on all platforms + * that are (potentially) legacy-free. + */ + if (kbd_read_status() == 0xff && kbd_read_input() == 0xff) { + kbd_exists = 0; + return "No keyboard controller preset"; + } + + /* * Test the keyboard interface. * This seems to be the only way to get it going. * If the test is successful a x55 is placed in the input buffer. @@ -913,6 +922,8 @@ void __init pckbd_init_hw(void) char *msg = initialize_kbd(); if (msg) printk(KERN_WARNING "initialize_kbd: %s\n", msg); + if (!kbd_exists) + return; } #if defined CONFIG_PSMOUSE diff -Naurp linux-2.4.20-wolk4.1s/drivers/char/pcmcia/serial_cs.c linux-2.4.20-wolk4.2-fullkernel/drivers/char/pcmcia/serial_cs.c --- linux-2.4.20-wolk4.1s/drivers/char/pcmcia/serial_cs.c 2001-12-21 18:41:54.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/char/pcmcia/serial_cs.c 2003-06-03 20:02:49.000000000 +0200 @@ -2,7 +2,7 @@ A driver for PCMCIA serial devices - serial_cs.c 1.128 2001/10/18 12:18:35 + serial_cs.c 1.138 2002/10/25 06:24:52 The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file @@ -28,7 +28,7 @@ and other provisions required by the GPL. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the GPL. - + ======================================================================*/ #include @@ -69,14 +69,14 @@ INT_MODULE_PARM(irq_mask, 0xdeb8); static int irq_list[4] = { -1 }; MODULE_PARM(irq_list, "1-4i"); -/* Enable the speaker? */ -INT_MODULE_PARM(do_sound, 1); +INT_MODULE_PARM(do_sound, 1); /* Enable the speaker? */ +INT_MODULE_PARM(buggy_uart, 0); /* Skip strict UART tests? */ #ifdef PCMCIA_DEBUG INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG); #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) static char *version = -"serial_cs.c 1.128 2001/10/18 12:18:35 (David Hinds)"; +"serial_cs.c 1.138 2002/10/25 06:24:52 (David Hinds)"; #else #define DEBUG(n, args...) #endif @@ -95,6 +95,7 @@ static multi_id_t multi_id[] = { { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 }, { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 }, { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 }, + { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D2, 2 }, { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 }, { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS422, 2 }, { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS422, 4 }, @@ -148,7 +149,7 @@ static dev_link_t *serial_attach(void) client_reg_t client_reg; dev_link_t *link; int i, ret; - + DEBUG(0, "serial_attach()\n"); /* Create new serial device */ @@ -160,7 +161,7 @@ static dev_link_t *serial_attach(void) link->release.function = &serial_release; link->release.data = (u_long)link; link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.NumPorts1 = 8; + link->io.Attributes2 = IO_DATA_PATH_WIDTH_8; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; if (irq_list[0] == -1) @@ -169,13 +170,12 @@ static dev_link_t *serial_attach(void) for (i = 0; i < 4; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; if (do_sound) { link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; } link->conf.IntType = INT_MEMORY_AND_IO; - + /* Register with Card Services */ link->next = dev_list; dev_list = link; @@ -194,7 +194,7 @@ static dev_link_t *serial_attach(void) serial_detach(link); return NULL; } - + return link; } /* serial_attach */ @@ -214,7 +214,7 @@ static void serial_detach(dev_link_t *li int ret; DEBUG(0, "serial_detach(0x%p)\n", link); - + /* Locate device structure */ for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) if (*linkp == link) break; @@ -224,17 +224,17 @@ static void serial_detach(dev_link_t *li del_timer(&link->release); if (link->state & DEV_CONFIG) serial_release((u_long)link); - + if (link->handle) { ret = CardServices(DeregisterClient, link->handle); if (ret != CS_SUCCESS) cs_error(link->handle, DeregisterClient, ret); } - + /* Unlink device structure, free bits */ *linkp = link->next; kfree(info); - + } /* serial_detach */ /*====================================================================*/ @@ -243,18 +243,20 @@ static int setup_serial(serial_info_t *i { struct serial_struct serial; int line; - + memset(&serial, 0, sizeof(serial)); serial.port = port; serial.irq = irq; serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ; + if (buggy_uart) + serial.flags |= ASYNC_BUGGY_UART; line = register_serial(&serial); if (line < 0) { printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx," " irq %d failed\n", (u_long)serial.port, serial.irq); return -1; } - + info->line[info->ndev] = line; sprintf(info->node[info->ndev].dev_name, "ttyS%d", line); info->node[info->ndev].major = TTY_MAJOR; @@ -262,7 +264,7 @@ static int setup_serial(serial_info_t *i if (info->ndev > 0) info->node[info->ndev-1].next = &info->node[info->ndev]; info->ndev++; - + return 0; } @@ -313,7 +315,10 @@ static int simple_config(dev_link_t *lin return setup_serial(info, port, config.AssignedIRQ); } link->conf.Vcc = config.Vcc; - + + link->io.NumPorts1 = 8; + link->io.NumPorts2 = 0; + /* First pass: look for a config entry that looks normal. */ tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; @@ -340,7 +345,7 @@ static int simple_config(dev_link_t *lin i = next_tuple(handle, &tuple, &parse); } } - + /* Second pass: try to find an entry that isn't picky about its base address, then try to grab any standard serial port address, and finally try to get any free port. */ @@ -352,8 +357,7 @@ static int simple_config(dev_link_t *lin for (j = 0; j < 5; j++) { link->io.BasePort1 = base[j]; link->io.IOAddrLines = base[j] ? 16 : 3; - i = CardServices(RequestIO, link->handle, - &link->io); + i = CardServices(RequestIO, link->handle, &link->io); if (i == CS_SUCCESS) goto found_port; } } @@ -365,7 +369,7 @@ found_port: cs_error(link->handle, RequestIO, i); return -1; } - + i = CardServices(RequestIRQ, link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); @@ -390,8 +394,12 @@ static int multi_config(dev_link_t *link u_char buf[256]; cisparse_t parse; cistpl_cftable_entry_t *cf = &parse.cftable_entry; + config_info_t config; int i, base2 = 0; + CardServices(GetConfigurationInfo, handle, &config); + link->conf.Vcc = config.Vcc; + tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; @@ -433,12 +441,12 @@ static int multi_config(dev_link_t *link i = next_tuple(handle, &tuple, &parse); } } - + if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIO, i); - return -1; + /* At worst, try to configure as a single port */ + return simple_config(link); } - + i = CardServices(RequestIRQ, link->handle, &link->irq); if (i != CS_SUCCESS) { cs_error(link->handle, RequestIRQ, i); @@ -454,14 +462,27 @@ static int multi_config(dev_link_t *link cs_error(link->handle, RequestConfiguration, i); return -1; } - + + /* The Oxford Semiconductor OXCF950 cards are in fact single-port: + 8 registers are for the UART, the others are extra registers */ + if (info->manfid == MANFID_OXSEMI) { + if (cf->index == 1 || cf->index == 3) { + setup_serial(info, base2, link->irq.AssignedIRQ); + outb(12,link->io.BasePort1+1); + } else { + setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); + outb(12,base2+1); + } + return 0; + } + setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); /* The Nokia cards are not really multiport cards */ if (info->manfid == MANFID_NOKIA) return 0; for (i = 0; i < info->multi-1; i++) setup_serial(info, base2+(8*i), link->irq.AssignedIRQ); - + return 0; } @@ -487,7 +508,7 @@ void serial_config(dev_link_t *link) int i, last_ret, last_fn; DEBUG(0, "serial_config(0x%p)\n", link); - + tuple.TupleData = (cisdata_t *)buf; tuple.TupleOffset = 0; tuple.TupleDataMax = 255; tuple.Attributes = 0; @@ -500,7 +521,7 @@ void serial_config(dev_link_t *link) } link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; - + /* Configure card */ link->state |= DEV_CONFIG; @@ -508,8 +529,8 @@ void serial_config(dev_link_t *link) tuple.DesiredTuple = CISTPL_LONGLINK_MFC; tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS); - - /* Is this a multiport card? */ + + /* Scan list of known multiport card ID's */ tuple.DesiredTuple = CISTPL_MANFID; if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { info->manfid = le16_to_cpu(buf[0]); @@ -537,15 +558,15 @@ void serial_config(dev_link_t *link) info->multi = 2; } } - + if (info->multi > 1) multi_config(link); else simple_config(link); - + if (info->ndev == 0) goto failed; - + if (info->manfid == MANFID_IBM) { conf_reg_t reg = { 0, CS_READ, 0x800, 0 }; CS_CHECK(AccessConfigurationRegister, link->handle, ®); @@ -562,6 +583,7 @@ cs_failed: cs_error(link->handle, last_fn, last_ret); failed: serial_release((u_long)link); + link->state &= ~DEV_CONFIG_PENDING; } /* serial_config */ @@ -569,7 +591,7 @@ failed: After a card is removed, serial_release() will unregister the net device, and release the PCMCIA configuration. - + ======================================================================*/ void serial_release(u_long arg) @@ -577,7 +599,7 @@ void serial_release(u_long arg) dev_link_t *link = (dev_link_t *)arg; serial_info_t *info = link->priv; int i; - + DEBUG(0, "serial_release(0x%p)\n", link); for (i = 0; i < info->ndev; i++) { @@ -590,7 +612,7 @@ void serial_release(u_long arg) CardServices(ReleaseIO, link->handle, &link->io); CardServices(ReleaseIRQ, link->handle, &link->irq); } - + link->state &= ~DEV_CONFIG; } /* serial_release */ @@ -601,7 +623,7 @@ void serial_release(u_long arg) stuff to run after an event is received. A CARD_REMOVAL event also sets some flags to discourage the serial drivers from talking to the ports. - + ======================================================================*/ static int serial_event(event_t event, int priority, @@ -609,9 +631,9 @@ static int serial_event(event_t event, i { dev_link_t *link = args->client_data; serial_info_t *info = link->priv; - + DEBUG(1, "serial_event(0x%06x)\n", event); - + switch (event) { case CS_EVENT_CARD_REMOVAL: link->state &= ~DEV_PRESENT; @@ -650,7 +672,7 @@ static int __init init_serial_cs(void) if (serv.Revision != CS_RELEASE_CODE) { printk(KERN_NOTICE "serial_cs: Card Services release " "does not match!\n"); - return -1; + return -EINVAL; } register_pccard_driver(&dev_info, &serial_attach, &serial_detach); return 0; diff -Naurp linux-2.4.20-wolk4.1s/drivers/char/serial.c linux-2.4.20-wolk4.2-fullkernel/drivers/char/serial.c --- linux-2.4.20-wolk4.1s/drivers/char/serial.c 2003-05-15 21:52:26.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/char/serial.c 2003-06-03 20:02:49.000000000 +0200 @@ -892,10 +892,15 @@ static void rs_interrupt(int irq, void * if (status & UART_LSR_DR) receive_chars(info, &status, regs); check_modem_status(info); +#ifdef CONFIG_MELAN if ((status & UART_LSR_THRE) || /* for buggy ELAN processors */ ((iir & UART_IIR_ID) == UART_IIR_THRI)) transmit_chars(info, 0); +#else + if (status & UART_LSR_THRE) + transmit_chars(info, 0); +#endif next: info = info->next_port; diff -Naurp linux-2.4.20-wolk4.1s/drivers/char/tty_io.c linux-2.4.20-wolk4.2-fullkernel/drivers/char/tty_io.c --- linux-2.4.20-wolk4.1s/drivers/char/tty_io.c 2003-05-15 21:52:26.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/char/tty_io.c 2003-06-02 17:23:44.000000000 +0200 @@ -134,12 +134,6 @@ extern struct tty_driver ptm_driver[]; / extern struct tty_driver pts_driver[]; /* Unix98 pty slaves; for /dev/ptmx */ #endif -/* - * redirect is the pseudo-tty that console output - * is redirected to if asked by TIOCCONS. - */ -struct tty_struct * redirect; - static void initialize_tty_struct(struct tty_struct *tty); static ssize_t tty_read(struct file *, char *, size_t, loff_t *); @@ -444,6 +438,8 @@ static struct file_operations hung_up_tt release: tty_release, }; +static spinlock_t redirect_lock = SPIN_LOCK_UNLOCKED; +static struct file *redirect; /* * This can be called by the "eventd" kernel thread. That is process synchronous, * but doesn't hold any locks, so we need to make sure we have the appropriate @@ -453,6 +449,7 @@ void do_tty_hangup(void *data) { struct tty_struct *tty = (struct tty_struct *) data; struct file * cons_filp = NULL; + struct file *f = NULL; struct task_struct *p; struct list_head *l; int closecount = 0, n; @@ -462,6 +459,15 @@ void do_tty_hangup(void *data) /* inuse_filps is protected by the single kernel lock */ lock_kernel(); + + spin_lock(&redirect_lock); + if (redirect && redirect->private_data == tty) { + f = redirect; + redirect = NULL; + } + spin_unlock(&redirect_lock); + if (f) + fput(f); check_tty_count(tty, "do_tty_hangup"); file_list_lock(); @@ -770,7 +776,7 @@ static ssize_t tty_write(struct file * f { int is_console; struct tty_struct * tty; - struct inode *inode; + struct inode *inode = file->f_dentry->d_inode; /* Can't seek (pwrite) on ttys. */ if (ppos != &file->f_pos) @@ -784,10 +790,24 @@ static ssize_t tty_write(struct file * f is_console = (inode->i_rdev == SYSCONS_DEV || inode->i_rdev == CONSOLE_DEV); - if (is_console && redirect) - tty = redirect; - else - tty = (struct tty_struct *)file->private_data; + if (is_console) { + struct file *p = NULL; + + spin_lock(&redirect_lock); + if (redirect) { + get_file(redirect); + p = redirect; + } + spin_unlock(&redirect_lock); + + if (p) { + ssize_t res = p->f_op->write(p, buf, count, &p->f_pos); + fput(p); + return res; + } + } + + tty = (struct tty_struct *)file->private_data; if (tty_paranoia_check(tty, inode->i_rdev, "tty_write")) return -EIO; if (!tty || !tty->driver.write || (test_bit(TTY_IO_ERROR, &tty->flags))) @@ -1255,7 +1275,7 @@ static void release_dev(struct file * fi /* * If _either_ side is closing, make sure there aren't any * processes that still think tty or o_tty is their controlling - * tty. Also, clear redirect if it points to either tty. + * tty. */ if (tty_closing || o_tty_closing) { struct task_struct *p; @@ -1266,9 +1286,6 @@ static void release_dev(struct file * fi p->tty = NULL; } read_unlock(&tasklist_lock); - - if (redirect == tty || (o_tty && redirect == o_tty)) - redirect = NULL; } /* check whether both sides are closing ... */ @@ -1593,23 +1610,33 @@ static int tiocswinsz(struct tty_struct return 0; } -static int tioccons(struct inode *inode, - struct tty_struct *tty, struct tty_struct *real_tty) +static int tioccons(struct inode *inode, struct file *file) { if (inode->i_rdev == SYSCONS_DEV || inode->i_rdev == CONSOLE_DEV) { + struct file *f; #ifdef CONFIG_GRKERNSEC if (!capable(CAP_SYS_TTY_CONFIG)) #else if (!suser()) #endif return -EPERM; + spin_lock(&redirect_lock); + f = redirect; redirect = NULL; + spin_unlock(&redirect_lock); + if (f) + fput(f); return 0; } - if (redirect) + spin_lock(&redirect_lock); + if (redirect) { + spin_unlock(&redirect_lock); return -EBUSY; - redirect = real_tty; + } + get_file(file); + redirect = file; + spin_unlock(&redirect_lock); return 0; } @@ -1833,7 +1860,7 @@ int tty_ioctl(struct inode * inode, stru case TIOCSWINSZ: return tiocswinsz(tty, real_tty, (struct winsize *) arg); case TIOCCONS: - return tioccons(inode, tty, real_tty); + return real_tty!=tty ? -EINVAL : tioccons(inode, file); case FIONBIO: return fionbio(file, (int *) arg); case TIOCEXCL: diff -Naurp linux-2.4.20-wolk4.1s/drivers/i2c/Config.in linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/Config.in --- linux-2.4.20-wolk4.1s/drivers/i2c/Config.in 2003-05-15 21:52:26.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/Config.in 2003-06-01 18:14:29.000000000 +0200 @@ -44,6 +44,10 @@ if [ "$CONFIG_I2C" != "n" ]; then fi fi + if [ "$CONFIG_ALL_PPC" = "y" ] ; then + dep_tristate 'Keywest I2C interface in Apple Core99 machines' CONFIG_I2C_KEYWEST $CONFIG_I2C + fi + # This is needed for automatic patch generation: sensors code starts here bool 'I2C mainboard interfaces' CONFIG_I2C_MAINBOARD if [ "$CONFIG_I2C_MAINBOARD" = "y" ]; then diff -Naurp linux-2.4.20-wolk4.1s/drivers/i2c/i2c-adap-ite.c linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-adap-ite.c --- linux-2.4.20-wolk4.1s/drivers/i2c/i2c-adap-ite.c 2002-09-27 23:25:43.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-adap-ite.c 2003-06-01 18:14:27.000000000 +0200 @@ -82,7 +82,7 @@ static void iic_ite_setiic(void *data, i unsigned long j = jiffies + 10; DEB3(printk(" Write 0x%02x to 0x%x\n",(unsigned short)val, ctl&0xff)); - DEB3({while (jiffies < j) schedule();}) + DEB3({while (time_before(jiffies, j)) schedule();}) outw(val,ctl); } diff -Naurp linux-2.4.20-wolk4.1s/drivers/i2c/i2c-algo-bit.c linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-algo-bit.c --- linux-2.4.20-wolk4.1s/drivers/i2c/i2c-algo-bit.c 2003-05-15 21:52:26.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-algo-bit.c 2003-06-01 18:14:27.000000000 +0200 @@ -48,7 +48,7 @@ /* respectively. This makes sure that the algorithm works. Some chips */ /* might not like this, as they have an internal timeout of some mils */ /* -#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ +#define SLO_IO jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\ if (need_resched) schedule(); */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/i2c/i2c-algo-ibm_ocp.c linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-algo-ibm_ocp.c --- linux-2.4.20-wolk4.1s/drivers/i2c/i2c-algo-ibm_ocp.c 2003-05-15 21:52:26.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-algo-ibm_ocp.c 2003-06-01 18:14:27.000000000 +0200 @@ -84,7 +84,7 @@ MODULE_LICENSE("GPL"); /* respectively. This makes sure that the algorithm works. Some chips */ /* might not like this, as they have an internal timeout of some mils */ /* -#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ +#define SLO_IO jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\ if (need_resched) schedule(); */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/i2c/i2c-algo-ite.c linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-algo-ite.c --- linux-2.4.20-wolk4.1s/drivers/i2c/i2c-algo-ite.c 2001-10-11 17:05:47.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-algo-ite.c 2003-06-01 18:14:27.000000000 +0200 @@ -66,7 +66,7 @@ /* respectively. This makes sure that the algorithm works. Some chips */ /* might not like this, as they have an internal timeout of some mils */ /* -#define SLO_IO jif=jiffies;while(jiffies<=jif+i2c_table[minor].veryslow)\ +#define SLO_IO jif=jiffies;while(time_before_eq(jiffies, jif+i2c_table[minor].veryslow))\ if (need_resched) schedule(); */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/i2c/i2c-algo-pcf.c linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-algo-pcf.c --- linux-2.4.20-wolk4.1s/drivers/i2c/i2c-algo-pcf.c 2003-05-15 21:52:26.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-algo-pcf.c 2003-06-01 18:14:27.000000000 +0200 @@ -533,9 +533,7 @@ EXPORT_SYMBOL(i2c_pcf_del_bus); #ifdef MODULE MODULE_AUTHOR("Hans Berglund "); MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif MODULE_PARM(pcf_scan, "i"); MODULE_PARM(i2c_debug,"i"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/i2c/i2c-dev.c linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-dev.c --- linux-2.4.20-wolk4.1s/drivers/i2c/i2c-dev.c 2003-05-15 21:52:26.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-dev.c 2003-06-01 18:14:27.000000000 +0200 @@ -537,9 +537,7 @@ EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Frodo Looijaard and Simon G. Vogl "); MODULE_DESCRIPTION("I2C /dev entries driver"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif module_init(i2c_dev_init); module_exit(i2cdev_cleanup); diff -Naurp linux-2.4.20-wolk4.1s/drivers/i2c/i2c-elektor.c linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-elektor.c --- linux-2.4.20-wolk4.1s/drivers/i2c/i2c-elektor.c 2003-05-15 21:52:26.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-elektor.c 2003-06-01 18:14:27.000000000 +0200 @@ -307,9 +307,7 @@ EXPORT_NO_SYMBOLS; #ifdef MODULE MODULE_AUTHOR("Hans Berglund "); MODULE_DESCRIPTION("I2C-Bus adapter routines for PCF8584 ISA bus adapter"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif MODULE_PARM(base, "i"); MODULE_PARM(irq, "i"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/i2c/i2c-elv.c linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-elv.c --- linux-2.4.20-wolk4.1s/drivers/i2c/i2c-elv.c 2003-05-15 21:52:26.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-elv.c 2003-06-01 18:14:27.000000000 +0200 @@ -198,9 +198,7 @@ EXPORT_NO_SYMBOLS; #ifdef MODULE MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus adapter routines for ELV parallel port adapter"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif MODULE_PARM(base, "i"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/i2c/i2c-philips-par.c linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-philips-par.c --- linux-2.4.20-wolk4.1s/drivers/i2c/i2c-philips-par.c 2003-05-15 21:52:26.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-philips-par.c 2003-06-01 18:14:27.000000000 +0200 @@ -295,9 +295,7 @@ EXPORT_NO_SYMBOLS; MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus adapter routines for Philips parallel port adapter"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif MODULE_PARM(type, "i"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/i2c/i2c-proc.c linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-proc.c --- linux-2.4.20-wolk4.1s/drivers/i2c/i2c-proc.c 2003-05-15 21:52:26.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-proc.c 2003-06-01 18:14:27.000000000 +0200 @@ -922,9 +922,7 @@ EXPORT_SYMBOL(i2c_sysctl_real); MODULE_AUTHOR("Frodo Looijaard "); MODULE_DESCRIPTION("i2c-proc driver"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif module_init(sensors_init); module_exit(i2c_cleanup); diff -Naurp linux-2.4.20-wolk4.1s/drivers/i2c/i2c-velleman.c linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-velleman.c --- linux-2.4.20-wolk4.1s/drivers/i2c/i2c-velleman.c 2003-05-15 21:52:26.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/i2c/i2c-velleman.c 2003-06-01 18:14:27.000000000 +0200 @@ -189,9 +189,7 @@ EXPORT_NO_SYMBOLS; #ifdef MODULE MODULE_AUTHOR("Simon G. Vogl "); MODULE_DESCRIPTION("I2C-Bus adapter routines for Velleman K8000 adapter"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif MODULE_PARM(base, "i"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/ide/ide.c linux-2.4.20-wolk4.2-fullkernel/drivers/ide/ide.c --- linux-2.4.20-wolk4.1s/drivers/ide/ide.c 2003-05-15 21:52:27.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/ide/ide.c 2003-06-05 23:30:57.000000000 +0200 @@ -3748,7 +3748,8 @@ static int ide_notify_reboot (struct not return NOTIFY_DONE; } - printk("flushing ide devices: "); + if(console_loglevel > 8) + printk(KERN_INFO "flushing ide devices: "); for (i = 0; i < MAX_HWIFS; i++) { hwif = &ide_hwifs[i]; @@ -3760,7 +3761,8 @@ static int ide_notify_reboot (struct not continue; /* set the drive to standby */ - printk("%s ", drive->name); + if(console_loglevel > 8) + printk("%s ", drive->name); if (event != SYS_RESTART) if (drive->driver != NULL && DRIVER(drive)->standby(drive)) continue; @@ -3769,7 +3771,8 @@ static int ide_notify_reboot (struct not continue; } } - printk("\n"); + if(console_loglevel > 8) + printk("\n"); return NOTIFY_DONE; } diff -Naurp linux-2.4.20-wolk4.1s/drivers/md/dm-table.c linux-2.4.20-wolk4.2-fullkernel/drivers/md/dm-table.c --- linux-2.4.20-wolk4.1s/drivers/md/dm-table.c 2003-05-15 21:52:27.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/md/dm-table.c 2003-06-02 17:21:03.000000000 +0200 @@ -256,7 +256,7 @@ static int lookup_device(const char *pat struct nameidata nd; struct inode *inode; - if (!path_lookup(path, LOOKUP_FOLLOW, &nd)) + if (!path_init(path, LOOKUP_FOLLOW, &nd)) return 0; if ((r = path_walk(path, &nd))) diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/3c90x.c linux-2.4.20-wolk4.2-fullkernel/drivers/net/3c90x.c --- linux-2.4.20-wolk4.1s/drivers/net/3c90x.c 2003-05-15 21:52:28.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/3c90x.c 2003-06-05 13:12:26.000000000 +0200 @@ -281,20 +281,8 @@ Return Value: --*/ -#if LINUX_VERSION_CODE >= 0x20400 -int init_module(void) -{ - return tc90x_init(); -} - -void cleanup_module(void) -{ - tc90x_cleanup(); -} -#else module_init(tc90x_init); module_exit(tc90x_cleanup); -#endif static INT tc90x_init(VOID) { diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/eepro100.c linux-2.4.20-wolk4.2-fullkernel/drivers/net/eepro100.c --- linux-2.4.20-wolk4.1s/drivers/net/eepro100.c 2003-05-15 21:52:28.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/eepro100.c 2003-06-02 17:23:43.000000000 +0200 @@ -1651,7 +1651,7 @@ static void speedo_interrupt(int irq, vo /* Clear all interrupt sources. */ /* Will change from 0xfc00 to 0xff00 when we start handling FCP and ER interrupts --Dragan */ - outw(0xfc00, ioaddr + SCBStatus); + outw(status & 0xfc00, ioaddr + SCBStatus); break; } } while (1); @@ -2418,6 +2418,12 @@ static struct pci_device_id eepro100_pci { PCI_VENDOR_ID_INTEL, 0x103C, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, 0x103D, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, 0x103E, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x1050, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x1051, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x1052, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x1053, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x1054, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, 0x1055, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, 0x1059, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, 0x1227, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_INTEL, 0x1228, PCI_ANY_ID, PCI_ANY_ID, }, diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/ppp_generic.c linux-2.4.20-wolk4.2-fullkernel/drivers/net/ppp_generic.c --- linux-2.4.20-wolk4.1s/drivers/net/ppp_generic.c 2003-05-15 21:52:29.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/ppp_generic.c 2003-06-01 18:15:35.000000000 +0200 @@ -64,6 +64,26 @@ #define MIN_FRAG_SIZE 64 /* +* brute force -- redefine PPP_HDRLEN to allow a little +* extra room for MPPE headers +*/ +#undef PPP_HDRLEN +#define PPP_HDRLEN 8 +/* +* End +*/ + +/* +* increase CCP_MAX_OPTION_LENGTH to allow room for 2 128-bit +* MPPE keys +*/ +#undef CCP_MAX_OPTION_LENGTH +#define CCP_MAX_OPTION_LENGTH 64 +/* +* End +*/ + +/* * An instance of /dev/ppp can be associated with either a ppp * interface unit or a ppp channel. In both cases, file->private_data * points to one of these. diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap.c linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap.c --- linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap.c 2003-05-15 21:52:31.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap.c 2003-06-02 17:04:07.000000000 +0200 @@ -78,7 +78,7 @@ static int prism2_hostapd(struct ap_data static void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, struct prism2_crypt_data ***crypt); static void ap_control_kickall(struct ap_data *ap); -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT static int ap_control_add_mac(struct mac_restrictions *mac_restrictions, u8 *mac); static int ap_control_del_mac(struct mac_restrictions *mac_restrictions, @@ -86,7 +86,7 @@ static int ap_control_del_mac(struct mac static void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); static int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac); -#endif /* PRISM2_HOSTAPD */ +#endif /* !PRISM2_NO_KERNEL_IEEE80211_MGMT */ #ifdef WIRELESS_EXT @@ -550,13 +550,10 @@ void hostap_netif_wake_queues(struct net if (local->dev) netif_wake_queue(local->dev); - -#ifdef PRISM2_HOSTAPD if (local->apdev) netif_wake_queue(local->apdev); if (local->stadev) netif_wake_queue(local->stadev); -#endif /* PRISM2_HOSTAPD */ spin_lock_irqsave(&local->wdslock, flags); wds = local->wds; @@ -577,13 +574,10 @@ void hostap_netif_stop_queues(struct net if (local->dev) netif_stop_queue(local->dev); - -#ifdef PRISM2_HOSTAPD if (local->apdev) netif_stop_queue(local->apdev); if (local->stadev) netif_stop_queue(local->stadev); -#endif /* PRISM2_HOSTAPD */ spin_lock_irqsave(&local->wdslock, flags); wds = local->wds; @@ -646,12 +640,10 @@ int hostap_80211_get_hdrlen(u16 fc) struct net_device_stats *hostap_get_stats(struct net_device *dev) { local_info_t *local = (local_info_t *) dev->priv; -#ifdef PRISM2_HOSTAPD if (local->apdev == dev) return &local->apdevstats; if (local->stadev == dev) return &local->stadevstats; -#endif /* PRISM2_HOSTAPD */ if (local->dev != dev) { prism2_wds_info_t *wds = (prism2_wds_info_t *) dev; return &wds->stats; @@ -666,12 +658,12 @@ static int prism2_close(struct net_devic PDEBUG(DEBUG_FLOW, "%s: prism2_close\n", dev->name); -#ifndef PRISM2_HOSTAPD - if (dev == local->dev && +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + if (!local->hostapd && dev == local->dev && (!local->func->card_present || local->func->card_present(local)) && local->hw_ready && local->ap && local->iw_mode == IW_MODE_MASTER) hostap_deauth_all_stas(dev, local->ap, 1); -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ if (local->func->dev_close && local->func->dev_close(local)) return 0; @@ -689,7 +681,7 @@ static int prism2_close(struct net_devic #ifdef NEW_MODULE_CODE module_put(local->hw_module); -#else +#elif MODULE __MOD_DEC_USE_COUNT(local->hw_module); #endif @@ -709,7 +701,7 @@ static int prism2_open(struct net_device #ifdef NEW_MODULE_CODE if (!try_module_get(local->hw_module)) return -ENODEV; -#else +#elif MODULE __MOD_INC_USE_COUNT(local->hw_module); #endif @@ -744,10 +736,10 @@ static int prism2_set_mac_address(struct dev = local->dev; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); -#ifdef PRISM2_HOSTAPD - memcpy(local->apdev->dev_addr, dev->dev_addr, ETH_ALEN); - memcpy(local->stadev->dev_addr, dev->dev_addr, ETH_ALEN); -#endif /* PRISM2_HOSTAPD */ + if (local->apdev) + memcpy(local->apdev->dev_addr, dev->dev_addr, ETH_ALEN); + if (local->stadev) + memcpy(local->stadev->dev_addr, dev->dev_addr, ETH_ALEN); spin_lock_irqsave(&local->wdslock, flags); wds = local->wds; while (wds != NULL) { @@ -873,6 +865,129 @@ void hostap_setup_dev(struct net_device } +static int hostap_enable_hostapd(local_info_t *local, int rtnl_locked) +{ + struct net_device *dev = local->dev; + int ret; + + printk(KERN_DEBUG "%s: enabling hostapd mode\n", dev->name); + + local->apdev = kmalloc(sizeof(struct net_device) + PRISM2_NETDEV_EXTRA, + GFP_KERNEL); + if (local->apdev == NULL) + return -ENOMEM; + memset(local->apdev, 0, sizeof(struct net_device) + + PRISM2_NETDEV_EXTRA); + prism2_set_dev_name(local->apdev, local->apdev + 1); + + local->apdev->priv = local; + memcpy(local->apdev->dev_addr, dev->dev_addr, ETH_ALEN); + hostap_setup_dev(local->apdev, local, 0); + local->apdev->hard_start_xmit = local->func->tx_80211; + local->apdev->type = ARPHRD_IEEE80211; + local->apdev->hard_header_parse = hostap_80211_header_parse; + + local->apdev->base_addr = dev->base_addr; + local->apdev->irq = dev->irq; + local->apdev->mem_start = dev->mem_start; + local->apdev->mem_end = dev->mem_end; + sprintf(local->apdev->name, "%sap", dev->name); + if (rtnl_locked) + ret = register_netdevice(local->apdev); + else + ret = register_netdev(local->apdev); + if (ret) { + printk(KERN_WARNING "%s: register_netdevice(AP) failed!\n", + dev->name); + return -1; + } + printk(KERN_DEBUG "%s: Registered netdevice %s for AP management\n", + dev->name, local->apdev->name); + + + local->stadev = kmalloc(sizeof(struct net_device) + + PRISM2_NETDEV_EXTRA, + GFP_KERNEL); + if (local->stadev == NULL) + return -ENOMEM; + memset(local->stadev, 0, sizeof(struct net_device) + + PRISM2_NETDEV_EXTRA); + prism2_set_dev_name(local->stadev, local->stadev + 1); + + local->stadev->priv = local; + memcpy(local->stadev->dev_addr, dev->dev_addr, ETH_ALEN); + hostap_setup_dev(local->stadev, local, 0); + + local->stadev->base_addr = dev->base_addr; + local->stadev->irq = dev->irq; + local->stadev->mem_start = dev->mem_start; + local->stadev->mem_end = dev->mem_end; + sprintf(local->stadev->name, "%ssta", dev->name); + if (rtnl_locked) + ret = register_netdevice(local->stadev); + else + ret = register_netdev(local->stadev); + if (ret) { + printk(KERN_WARNING "%s: register_netdevice(STA) failed!\n", + dev->name); + return -1; + } + printk(KERN_DEBUG "%s: Registered netdevice %s for STA use\n", + dev->name, local->stadev->name); + + return 0; +} + + +static int hostap_disable_hostapd(local_info_t *local, int rtnl_locked) +{ + struct net_device *dev = local->dev; + + printk(KERN_DEBUG "%s: disabling hostapd mode\n", dev->name); + + if (local->apdev && local->apdev->name && local->apdev->name[0]) { + if (rtnl_locked) + unregister_netdevice(local->apdev); + else + unregister_netdev(local->apdev); + printk(KERN_DEBUG "%s: Netdevice %s unregistered\n", + dev->name, local->apdev->name); + } + kfree(local->apdev); + local->apdev = NULL; + + if (local->stadev && local->stadev->name && local->stadev->name[0]) { + if (rtnl_locked) + unregister_netdevice(local->stadev); + else + unregister_netdev(local->stadev); + printk(KERN_DEBUG "%s: Netdevice %s unregistered\n", + dev->name, local->stadev->name); + } + kfree(local->stadev); + local->stadev = NULL; + + return 0; +} + + +int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked) +{ + if (val < 0 || val > 1) + return -EINVAL; + + if (local->hostapd == val) + return 0; + + local->hostapd = val; + + if (val) + return hostap_enable_hostapd(local, rtnl_locked); + else + return hostap_disable_hostapd(local, rtnl_locked); +} + + struct proc_dir_entry *hostap_proc; static int __init hostap_init(void) @@ -914,6 +1029,7 @@ EXPORT_SYMBOL(hostap_get_stats); EXPORT_SYMBOL(hostap_setup_dev); EXPORT_SYMBOL(hostap_proc); EXPORT_SYMBOL(hostap_set_multicast_list_queue); +EXPORT_SYMBOL(hostap_set_hostapd); module_init(hostap_init); module_exit(hostap_exit); diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap.h linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap.h --- linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap.h 2003-05-15 21:52:31.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap.h 2003-06-02 17:04:07.000000000 +0200 @@ -27,6 +27,7 @@ struct net_device_stats *hostap_get_stat void hostap_setup_dev(struct net_device *dev, local_info_t *local, int main_dev); void hostap_set_multicast_list_queue(void *data); +int hostap_set_hostapd(local_info_t *local, int val, int rtnl_locked); /* hostap_proc.c */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_ap.c linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_ap.c --- linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_ap.c 2003-05-15 21:52:31.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_ap.c 2003-06-02 17:04:07.000000000 +0200 @@ -45,13 +45,13 @@ static void hostap_event_expired_sta(str struct sta_info *sta); static void handle_add_proc_queue(void *data); -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT static void handle_add_wds_queue(void *data); static void prism2_send_mgmt(struct net_device *dev, int type, int subtype, char *body, int body_len, int txevent, u8 *addr, u16 tx_cb_idx); -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ #ifndef PRISM2_NO_PROCFS_DEBUG @@ -128,14 +128,14 @@ static void ap_free_sta(struct ap_data * dev_kfree_skb(skb); ap->num_sta--; -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT if (sta->aid > 0) ap->sta_aid[sta->aid - 1] = NULL; if (!sta->ap && sta->u.sta.challenge) kfree(sta->u.sta.challenge); del_timer(&sta->timer); -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ kfree(sta); } @@ -250,7 +250,7 @@ static void hostap_event_expired_sta(str } -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT static void ap_handle_timer(unsigned long data) { @@ -567,7 +567,7 @@ static int ap_control_kick_mac(struct ap return 0; } -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ static void ap_control_kickall(struct ap_data *ap) @@ -589,7 +589,7 @@ static void ap_control_kickall(struct ap } -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT #define PROC_LIMIT (PAGE_SIZE - 80) @@ -647,7 +647,7 @@ static int prism2_ap_proc_read(char *pag return (p - page - off); } -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ void hostap_check_sta_fw_version(struct ap_data *ap, int major, int minor, @@ -671,8 +671,6 @@ void hostap_check_sta_fw_version(struct } -#ifdef PRISM2_HOSTAPD - /* Called only as a tasklet (software IRQ) */ static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data) { @@ -680,6 +678,11 @@ static void hostap_ap_tx_cb(struct sk_bu u16 fc; struct hostap_ieee80211_hdr *hdr; + if (!ap->local->hostapd || !ap->local->apdev) { + dev_kfree_skb(skb); + return; + } + hdr = (struct hostap_ieee80211_hdr *) skb->data; fc = le16_to_cpu(hdr->frame_control); @@ -698,8 +701,8 @@ static void hostap_ap_tx_cb(struct sk_bu netif_rx(skb); } -#else /* PRISM2_HOSTAPD */ +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT /* Called only as a tasklet (software IRQ) */ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) { @@ -710,6 +713,11 @@ static void hostap_ap_tx_cb_auth(struct struct sta_info *sta = NULL; char *txt = NULL; + if (ap->local->hostapd) { + dev_kfree_skb(skb); + return; + } + hdr = (struct hostap_ieee80211_hdr *) skb->data; fc = le16_to_cpu(hdr->frame_control); if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || @@ -771,6 +779,11 @@ static void hostap_ap_tx_cb_assoc(struct struct sta_info *sta = NULL; char *txt = NULL; + if (ap->local->hostapd) { + dev_kfree_skb(skb); + return; + } + hdr = (struct hostap_ieee80211_hdr *) skb->data; fc = le16_to_cpu(hdr->frame_control); if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT || @@ -820,8 +833,7 @@ static void hostap_ap_tx_cb_assoc(struct } dev_kfree_skb(skb); } - -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ void hostap_init_data(local_info_t *local) @@ -862,13 +874,12 @@ void hostap_init_data(local_info_t *loca HOSTAP_QUEUE_INIT(&local->ap->add_sta_proc_queue, handle_add_proc_queue, ap); -#ifdef PRISM2_HOSTAPD ap->tx_callback_idx = hostap_tx_callback_register(local, hostap_ap_tx_cb, ap); if (ap->tx_callback_idx == 0) printk(KERN_WARNING "%s: failed to register TX callback for " "AP\n", local->dev->name); -#else /* PRISM2_HOSTAPD */ +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT HOSTAP_QUEUE_INIT(&local->ap->add_wds_queue, handle_add_wds_queue, local); @@ -889,7 +900,7 @@ void hostap_init_data(local_info_t *loca create_proc_read_entry("ap", 0, ap->proc, prism2_ap_proc_read, ap); -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ ap->initialized = 1; } @@ -904,11 +915,11 @@ void hostap_free_data(struct ap_data *ap return; } -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT if (ap->crypt) ap->crypt->deinit(ap->crypt_priv); ap->crypt = ap->crypt_priv = NULL; -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ ptr = ap->sta_list.next; while (ptr != NULL && ptr != &ap->sta_list) { @@ -935,13 +946,13 @@ void hostap_free_data(struct ap_data *ap } #endif /* PRISM2_NO_PROCFS_DEBUG */ -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT if (ap->proc != NULL) { remove_proc_entry("ap", ap->proc); remove_proc_entry("ap_control", ap->proc); } ap_control_flush_macs(&ap->mac_restrictions); -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ ap->initialized = 0; } @@ -959,7 +970,7 @@ static struct sta_info* ap_get_sta(struc } -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT /* Called from timer handler and from scheduled AP queue handlers */ static void prism2_send_mgmt(struct net_device *dev, @@ -1026,7 +1037,7 @@ static void prism2_send_mgmt(struct net_ skb->mac.raw = skb->nh.raw = skb->data; dev_queue_xmit(skb); } -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ static int prism2_sta_proc_read(char *page, char **start, off_t off, @@ -1086,7 +1097,7 @@ static int prism2_sta_proc_read(char *pa sta->txexc); if (sta->crypt && sta->crypt->ops) p += sprintf(p, "crypt=%s\n", sta->crypt->ops->name); -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT if (sta->ap) { if (sta->u.ap.channel >= 0) p += sprintf(p, "channel=%d\n", sta->u.ap.channel); @@ -1098,7 +1109,7 @@ static int prism2_sta_proc_read(char *pa sta->u.ap.ssid[i]); p += sprintf(p, "\n"); } -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ return (p - page); } @@ -1179,13 +1190,14 @@ static struct sta_info * ap_add_sta(stru printk(KERN_DEBUG "Failed to add STA proc data\n"); } -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT init_timer(&sta->timer); sta->timer.expires = jiffies + ap->max_inactivity; sta->timer.data = (unsigned long) sta; sta->timer.function = ap_handle_timer; - add_timer(&sta->timer); -#endif /* PRISM2_HOSTAPD */ + if (!ap->local->hostapd) + add_timer(&sta->timer); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ return sta; } @@ -1253,7 +1265,7 @@ static void prism2_check_tx_rates(struct } -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT static void ap_crypt_init(struct ap_data *ap) { @@ -1532,9 +1544,11 @@ static void handle_authen(local_info_t * atomic_dec(&sta->users); } +#if 0 PDEBUG(DEBUG_AP, "%s: " MACSTR " auth (alg=%d trans#=%d stat=%d len=%d" " fc=%04x) ==> %d (%s)\n", dev->name, MAC2STR(rxdesc->addr2), auth_alg, auth_transaction, status_code, len, fc, resp, txt); +#endif } @@ -1736,10 +1750,12 @@ static void handle_assoc(local_info_t *l atomic_dec(&sta->users); } +#if 0 PDEBUG(DEBUG_AP, "%s: " MACSTR " %sassoc (len=%d prev_ap=" MACSTR ") => %d(%d) (%s)\n", dev->name, MAC2STR(rxdesc->addr2), reassoc ? "re" : "", len, MAC2STR(prev_ap), resp, send_deauth, txt); +#endif } @@ -1873,7 +1889,7 @@ static void ap_handle_dropped_data(local atomic_dec(&sta->users); } -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ /* Called only as a scheduled task for pending AP frames. */ @@ -2009,7 +2025,7 @@ static void prism2_ap_update_sq(struct s } -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT static void handle_add_wds_queue(void *data) { @@ -2200,15 +2216,15 @@ static void handle_beacon(local_info_t * } } -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ /* Called only as a tasklet. */ static void handle_ap_item(local_info_t *local, struct sk_buff *skb) { -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT struct net_device *dev = local->dev; -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ u16 fc, type, stype; struct hfa384x_rx_frame *rxdesc; @@ -2219,8 +2235,8 @@ static void handle_ap_item(local_info_t type = WLAN_FC_GET_TYPE(fc); stype = WLAN_FC_GET_STYPE(fc); -#ifndef PRISM2_HOSTAPD - if (type == WLAN_FC_TYPE_DATA) { +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + if (!local->hostapd && type == WLAN_FC_TYPE_DATA) { PDEBUG(DEBUG_AP, "handle_ap_item - data frame\n"); if (!(fc & WLAN_FC_TODS) || (fc & WLAN_FC_FROMDS)) { @@ -2249,7 +2265,7 @@ static void handle_ap_item(local_info_t ap_handle_dropped_data(local, rxdesc); goto done; } -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ if (type == WLAN_FC_TYPE_CTRL && stype == WLAN_FC_STYPE_PSPOLL) { @@ -2257,11 +2273,13 @@ static void handle_ap_item(local_info_t goto done; } -#ifdef PRISM2_HOSTAPD - PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x " - "subtype=0x%02x\n", type, stype); + if (local->hostapd) { + PDEBUG(DEBUG_AP, "Unknown frame in AP queue: type=0x%02x " + "subtype=0x%02x\n", type, stype); + goto done; + } -#else /* PRISM2_HOSTAPD */ +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT if (type != WLAN_FC_TYPE_MGMT) { PDEBUG(DEBUG_AP, "handle_ap_item - not a management frame?\n"); goto done; @@ -2313,7 +2331,7 @@ static void handle_ap_item(local_info_t PDEBUG(DEBUG_AP, "Unknown mgmt frame subtype 0x%02x\n", stype); break; } -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ done: dev_kfree_skb(skb); @@ -2436,7 +2454,7 @@ static int prism2_ap_translate_scan(stru struct iw_event iwe; char *current_ev = buffer; char *end_buf = buffer + IW_SCAN_MAX_DATA; -#if !defined(PRISM2_HOSTAPD) && (WIRELESS_EXT > 14) +#if !defined(PRISM2_NO_KERNEL_IEEE80211_MGMT) && (WIRELESS_EXT > 14) char buf[64]; #endif @@ -2483,7 +2501,7 @@ static int prism2_ap_translate_scan(stru current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN); -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT if (sta->ap) { memset(&iwe, 0, sizeof(iwe)); iwe.cmd = SIOCGIWESSID; @@ -2527,7 +2545,7 @@ static int prism2_ap_translate_scan(stru &iwe, buf); #endif /* WIRELESS_EXT > 14 */ } -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ sta->last_rx_updated = 0; @@ -2542,7 +2560,6 @@ static int prism2_ap_translate_scan(stru #endif /* WIRELESS_EXT */ -#ifdef PRISM2_HOSTAPD static int prism2_hostapd_add_sta(struct ap_data *ap, struct prism2_hostapd_param *param) { @@ -2642,7 +2659,6 @@ static int prism2_hostapd_reset_txexc_st return sta ? 0 : -ENOENT; } -#endif /* PRISM2_HOSTAPD */ static int prism2_hostapd_set_flags_sta(struct ap_data *ap, @@ -2669,7 +2685,6 @@ static int prism2_hostapd(struct ap_data struct prism2_hostapd_param *param) { switch (param->cmd) { -#ifdef PRISM2_HOSTAPD case PRISM2_HOSTAPD_FLUSH: ap_control_kickall(ap); return 0; @@ -2681,7 +2696,6 @@ static int prism2_hostapd(struct ap_data return prism2_hostapd_get_info_sta(ap, param); case PRISM2_HOSTAPD_RESET_TXEXC_STA: return prism2_hostapd_reset_txexc_sta(ap, param); -#endif /* PRISM2_HOSTAPD */ case PRISM2_HOSTAPD_SET_FLAGS_STA: return prism2_hostapd_set_flags_sta(ap, param); default: @@ -2980,17 +2994,21 @@ ap_rx_ret hostap_handle_sta_rx(local_inf if (fc & WLAN_FC_TODS) { if (!wds && (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) { -#ifdef PRISM2_HOSTAPD - local->func->rx_80211(local->apdev, skb, - PRISM2_RX_NON_ASSOC, NULL, 0); -#else /* PRISM2_HOSTAPD */ - printk(KERN_DEBUG "%s: dropped received packet from " - "non-associated STA " MACSTR - " (type=0x%02x, subtype=0x%02x)\n", - dev->name, MAC2STR(rxdesc->addr2), type, stype); - skb->protocol = __constant_htons(ETH_P_HOSTAP); - hostap_rx(dev, skb); -#endif /* PRISM2_HOSTAPD */ + if (local->hostapd) { + local->func->rx_80211(local->apdev, skb, + PRISM2_RX_NON_ASSOC, + NULL, 0); +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + } else { + printk(KERN_DEBUG "%s: dropped received packet" + " from non-associated STA " MACSTR + " (type=0x%02x, subtype=0x%02x)\n", + dev->name, MAC2STR(rxdesc->addr2), type, + stype); + skb->protocol = __constant_htons(ETH_P_HOSTAP); + hostap_rx(dev, skb); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + } ret = AP_RX_EXIT; goto out; } @@ -3008,21 +3026,25 @@ ap_rx_ret hostap_handle_sta_rx(local_inf } } else if (stype == WLAN_FC_STYPE_NULLFUNC && sta == NULL && memcmp(rxdesc->addr1, dev->dev_addr, 6) == 0) { -#ifdef PRISM2_HOSTAPD - local->func->rx_80211(local->apdev, skb, - PRISM2_RX_NON_ASSOC, NULL, 0); -#else /* PRISM2_HOSTAPD */ - /* At least Lucent f/w seems to send data::nullfunc - * frames with no ToDS flag when the current AP returns - * after being unavailable for some time. Speed up - * re-association by informing the station about it not - * being associated. */ - printk(KERN_DEBUG "%s: rejected received nullfunc frame " - "without ToDS from not associated STA " MACSTR "\n", - dev->name, MAC2STR(rxdesc->addr2)); - skb->protocol = __constant_htons(ETH_P_HOSTAP); - hostap_rx(dev, skb); -#endif /* PRISM2_HOSTAPD */ + + if (local->hostapd) { + local->func->rx_80211(local->apdev, skb, + PRISM2_RX_NON_ASSOC, NULL, 0); +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + } else { + /* At least Lucent f/w seems to send data::nullfunc + * frames with no ToDS flag when the current AP returns + * after being unavailable for some time. Speed up + * re-association by informing the station about it not + * being associated. */ + printk(KERN_DEBUG "%s: rejected received nullfunc " + "frame without ToDS from not associated STA " + MACSTR "\n", + dev->name, MAC2STR(rxdesc->addr2)); + skb->protocol = __constant_htons(ETH_P_HOSTAP); + hostap_rx(dev, skb); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + } ret = AP_RX_EXIT; goto out; } else if (stype == WLAN_FC_STYPE_NULLFUNC) { @@ -3053,18 +3075,20 @@ ap_rx_ret hostap_handle_sta_rx(local_inf if (local->ap->nullfunc_ack && stype == WLAN_FC_STYPE_NULLFUNC && fc & WLAN_FC_TODS) { -#ifdef PRISM2_HOSTAPD - local->func->rx_80211(local->apdev, skb, - PRISM2_RX_NULLFUNC_ACK, NULL, 0); -#else /* PRISM2_HOSTAPD */ - /* some STA f/w's seem to require control::ACK frame - * for data::nullfunc, but Prism2 f/w 0.8.0 (at least - * from Compaq) does not send this.. Try to generate - * ACK for these frames from the host driver to make - * power saving work with, e.g., Lucent WaveLAN f/w */ - skb->protocol = __constant_htons(ETH_P_HOSTAP); - hostap_rx(dev, skb); -#endif /* PRISM2_HOSTAPD */ + if (local->hostapd) { + local->func->rx_80211(local->apdev, skb, + PRISM2_RX_NULLFUNC_ACK, NULL, 0); +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT + } else { + /* some STA f/w's seem to require control::ACK frame + * for data::nullfunc, but Prism2 f/w 0.8.0 (at least + * from Compaq) does not send this.. Try to generate + * ACK for these frames from the host driver to make + * power saving work with, e.g., Lucent WaveLAN f/w */ + skb->protocol = __constant_htons(ETH_P_HOSTAP); + hostap_rx(dev, skb); +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ + } ret = AP_RX_EXIT; goto out; } @@ -3280,6 +3304,6 @@ EXPORT_SYMBOL(hostap_update_rx_stats); EXPORT_SYMBOL(hostap_update_rates); EXPORT_SYMBOL(hostap_add_wds_links); EXPORT_SYMBOL(hostap_add_wds_link); -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT EXPORT_SYMBOL(hostap_deauth_all_stas); -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_ap.h linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_ap.h --- linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_ap.h 2003-05-15 21:52:31.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_ap.h 2003-06-02 17:04:07.000000000 +0200 @@ -84,7 +84,7 @@ struct sta_info { local_info_t *local; -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT union { struct { char *challenge; /* shared key authentication @@ -100,7 +100,7 @@ struct sta_info { struct timer_list timer; enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next; -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ }; @@ -200,9 +200,9 @@ struct ap_data { HOSTAP_QUEUE add_wds_queue; struct add_wds_data *add_wds_entries; -#ifdef PRISM2_HOSTAPD u16 tx_callback_idx; -#else /* PRISM2_HOSTAPD */ + +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT /* pointers to STA info; based on allocated AID or NULL if AID free * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1 * and so on @@ -215,7 +215,7 @@ struct ap_data { * authentication */ struct hostap_crypto_ops *crypt; void *crypt_priv; -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ }; @@ -255,9 +255,9 @@ void hostap_update_rates(local_info_t *l void hostap_add_wds_links(local_info_t *local); void hostap_add_wds_link(local_info_t *local, u8 *addr); -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT void hostap_deauth_all_stas(struct net_device *dev, struct ap_data *ap, int resend); -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ #endif /* HOSTAP_AP_H */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_config.h linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_config.h --- linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_config.h 2003-05-15 21:52:31.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_config.h 2003-06-02 17:04:07.000000000 +0200 @@ -1,16 +1,14 @@ #ifndef HOSTAP_CONFIG_H #define HOSTAP_CONFIG_H -#define PRISM2_VERSION "0.0.2 - 2003-05-03" +#define PRISM2_VERSION "0.0.3 - 2003-05-18" -/* define PRISM2_HOSTAPD to use user space daemon to handle management frames; - */ -/* #define PRISM2_HOSTAPD */ - -/* Allow kernel configuration to enable hostapd support. */ -#if !defined(PRISM2_HOSTAPD) && defined(CONFIG_HOSTAP_HOSTAPD) -#define PRISM2_HOSTAPD -#endif +/* In the previous versions of Host AP driver, support for user space version + * of IEEE 802.11 management (hostapd) used to be disabled in the default + * configuration. From now on, support for hostapd is always included and it is + * possible to disable kernel driver version of IEEE 802.11 management with a + * separate define, PRISM2_NO_KERNEL_IEEE80211_MGMT. */ +/* #define PRISM2_NO_KERNEL_IEEE80211_MGMT */ /* Maximum number of events handler per one interrupt */ #define PRISM2_MAX_INTERRUPT_EVENTS 20 diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_cs.c linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_cs.c --- linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_cs.c 2003-05-15 21:52:31.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_cs.c 2003-06-02 17:04:07.000000000 +0200 @@ -38,6 +38,13 @@ #include #endif /* __IN_PCMCIA_PACKAGE__ */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +/* This behavior changed in some Linux 2.5.x version. I don't remember when and + * don't really care if this does not work with some early 2.5.x versions.. + */ +#define HOSTAP_USE_RELEASE_TIMER +#endif + static char *version = PRISM2_VERSION " (Jouni Malinen )"; static dev_info_t dev_info = "hostap_cs"; @@ -279,8 +286,13 @@ static int prism2_pccard_dev_close(local local->link->open--; - if (local->link->state & DEV_STALE_CONFIG) - mod_timer(&local->link->release, jiffies + HZ / 20); + if (local->link->state & DEV_STALE_CONFIG) { +#ifdef HOSTAP_USE_RELEASE_TIMER + mod_timer(&local->link->release, jiffies + HZ / 20); +#else /* HOSTAP_USE_RELEASE_TIMER */ + prism2_release((u_long) local->link); +#endif /* HOSTAP_USE_RELEASE_TIMER */ + } return 0; } @@ -295,11 +307,13 @@ static struct prism2_helper_functions pr }; +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,68) static void cs_error(client_handle_t handle, int func, int ret) { error_info_t err = { func, ret }; CardServices(ReportError, handle, &err); } +#endif /* allocate local data and register with CardServices @@ -333,9 +347,11 @@ static dev_link_t *prism2_attach(void) link->priv = local->dev; local->link = link; +#ifdef HOSTAP_USE_RELEASE_TIMER init_timer(&link->release); link->release.function = &prism2_release; link->release.data = (u_long)link; +#endif /* HOSTAP_USE_RELEASE_TIMER */ PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info); link->conf.Vcc = 33; @@ -378,7 +394,9 @@ static void prism2_detach(dev_link_t *li return; } +#ifdef HOSTAP_USE_RELEASE_TIMER del_timer(&link->release); +#endif /* HOSTAP_USE_RELEASE_TIMER */ if (link->state & DEV_CONFIG) { printk("%s: detach postponed, '%s' still locked\n", dev_info, link->dev->dev_name); @@ -672,7 +690,11 @@ static int prism2_event(event_t event, i if (link->state & DEV_CONFIG) { hostap_netif_stop_queues(dev); netif_device_detach(dev); +#ifdef HOSTAP_USE_RELEASE_TIMER mod_timer(&link->release, jiffies + HZ / 20); +#else /* HOSTAP_USE_RELEASE_TIMER */ + prism2_release((u_long) link); +#endif /* HOSTAP_USE_RELEASE_TIMER */ } break; @@ -720,6 +742,30 @@ static int prism2_event(event_t event, i } +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,67) +static struct pcmcia_driver hostap_driver = { + .drv = { + .name = "hostap_cs", + }, + .attach = prism2_attach, + .detach = prism2_detach, + .owner = THIS_MODULE, +}; + +static int __init init_prism2_pccard(void) +{ + printk(KERN_INFO "%s: %s\n", dev_info, version); + return pcmcia_register_driver(&hostap_driver); +} + +static void __exit exit_prism2_pccard(void) +{ + pcmcia_unregister_driver(&hostap_driver); + printk(KERN_INFO "%s: Driver unloaded\n", dev_info); +} + +#else + static int __init init_prism2_pccard(void) { servinfo_t serv; @@ -742,7 +788,9 @@ static void __exit exit_prism2_pccard(vo unregister_pccard_driver(&dev_info); while (dev_list) { PDEBUG(DEBUG_FLOW, "exit_prism2 - detaching device\n"); +#ifdef HOSTAP_USE_RELEASE_TIMER del_timer(&dev_list->release); +#endif /* HOSTAP_USE_RELEASE_TIMER */ if (dev_list->state & DEV_CONFIG) prism2_release((u_long)dev_list); prism2_detach(dev_list); @@ -750,6 +798,7 @@ static void __exit exit_prism2_pccard(vo printk(KERN_INFO "%s: Driver unloaded\n", dev_info); } +#endif /* LINUX_VERSION_CODE > KERNEL_VERSION(2,5,67) */ module_init(init_prism2_pccard); diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_hw.c linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_hw.c --- linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_hw.c 2003-05-15 21:52:31.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_hw.c 2003-06-02 17:04:07.000000000 +0200 @@ -49,6 +49,7 @@ #if WIRELESS_EXT > 12 #include #endif /* WIRELESS_EXT > 12 */ +#include #include "hostap.h" @@ -132,7 +133,7 @@ static unsigned char bridge_tunnel_heade /* event mask, i.e., events that will result in an interrupt */ #define HFA384X_EVENT_MASK \ (HFA384X_BAP0_EVENTS | HFA384X_EV_ALLOC | HFA384X_EV_INFDROP | \ - HFA384X_EV_CMD | \ + HFA384X_EV_CMD | HFA384X_EV_TICK | \ EXTRA_EVENTS_WTERR | EXTRA_EVENTS_BUS_MASTER) /* Default TX control flags: use 802.11 headers and request interrupt for @@ -144,14 +145,14 @@ static unsigned char bridge_tunnel_heade /* ca. 1 usec */ -#define HFA384X_CMD_BUSY_TIMEOUT 1000 +#define HFA384X_CMD_BUSY_TIMEOUT 5000 /* ca. 10 usec */ -#define HFA384X_BAP_BUSY_TIMEOUT 1500 +#define HFA384X_BAP_BUSY_TIMEOUT 5000 #define HFA384X_INIT_TIMEOUT 50000 #define HFA384X_CMD_COMPL_TIMEOUT 20000 #define HFA384X_DL_COMPL_TIMEOUT 1000000 -#define HFA384X_ALLOC_COMPL_TIMEOUT 1000 +#define HFA384X_ALLOC_COMPL_TIMEOUT 5000 static void prism2_hw_reset(struct net_device *dev); @@ -738,10 +739,7 @@ static int hfa384x_set_rid(struct net_de static void hfa384x_disable_interrupts(struct net_device *dev) { - local_info_t *local = dev->priv; - /* disable interrupts and clear event status */ - local->event_mask = 0; HFA384X_OUTW(0, HFA384X_INTEN_OFF); HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); } @@ -749,10 +747,7 @@ static void hfa384x_disable_interrupts(s static void hfa384x_enable_interrupts(struct net_device *dev) { - local_info_t *local = dev->priv; - /* ack pending events and enable interrupts from selected events */ - local->event_mask = HFA384X_EVENT_MASK; HFA384X_OUTW(0xffff, HFA384X_EVACK_OFF); HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); } @@ -760,24 +755,19 @@ static void hfa384x_enable_interrupts(st static void hfa384x_events_no_bap0(struct net_device *dev) { - local_info_t *local = dev->priv; - local->event_mask = HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS; - HFA384X_OUTW(local->event_mask, HFA384X_INTEN_OFF); + HFA384X_OUTW(HFA384X_EVENT_MASK & ~HFA384X_BAP0_EVENTS, + HFA384X_INTEN_OFF); } static void hfa384x_events_all(struct net_device *dev) { - local_info_t *local = dev->priv; - local->event_mask = HFA384X_EVENT_MASK; HFA384X_OUTW(HFA384X_EVENT_MASK, HFA384X_INTEN_OFF); } static void hfa384x_events_only_cmd(struct net_device *dev) { - local_info_t *local = dev->priv; - local->event_mask = HFA384X_EV_CMD; HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_INTEN_OFF); } @@ -862,6 +852,8 @@ static int prism2_setup_rids(struct net_ u16 tmp; int ret = 0; + hostap_set_word(dev, HFA384X_RID_TICKTIME, 2000); + if (!local->fw_ap) { tmp = hostap_get_porttype(local); ret = hostap_set_word(dev, HFA384X_RID_CNFPORTTYPE, tmp); @@ -1080,7 +1072,7 @@ static int prism2_hw_init(struct net_dev printk("%s: card initialization timed out\n", dev_info); goto failed; } - printk(KERN_DEBUG "prism2_hw_config: initialized in %d iterations\n", + printk(KERN_DEBUG "prism2_hw_init: initialized in %d iterations\n", HFA384X_INIT_TIMEOUT - i); HFA384X_OUTW(HFA384X_EV_CMD, HFA384X_EVACK_OFF); @@ -1123,7 +1115,7 @@ static int prism2_hw_init(struct net_dev local->intransmitfid[i] = PRISM2_TXFID_EMPTY; } - hfa384x_enable_interrupts(dev); + hfa384x_events_only_cmd(dev); if (initial) { /* get card version information */ @@ -1138,10 +1130,12 @@ static int prism2_hw_init(struct net_dev printk("%s: could not get own MAC address\n", dev->name); } -#ifdef PRISM2_HOSTAPD - memcpy(local->apdev->dev_addr, dev->dev_addr, ETH_ALEN); - memcpy(local->stadev->dev_addr, dev->dev_addr, ETH_ALEN); -#endif /* PRISM2_HOSTAPD */ + if (local->apdev) + memcpy(local->apdev->dev_addr, dev->dev_addr, + ETH_ALEN); + if (local->stadev) + memcpy(local->stadev->dev_addr, dev->dev_addr, + ETH_ALEN); } else if (local->fw_ap) prism2_check_sta_fw_version(local); @@ -1159,6 +1153,7 @@ static int prism2_hw_init(struct net_dev static int prism2_hw_enable(struct net_device *dev, int initial) { local_info_t *local = (local_info_t *) dev->priv; + int was_resetting = local->hw_resetting; if (hfa384x_cmd(dev, HFA384X_CMDCODE_ENABLE, 0, NULL, NULL)) { printk("%s: MAC port 0 enabling failed\n", dev->name); @@ -1167,6 +1162,7 @@ static int prism2_hw_enable(struct net_d local->hw_ready = 1; local->hw_reset_tries = 0; + local->hw_resetting = 0; hfa384x_enable_interrupts(dev); /* at least D-Link DWL-650 seems to require additional port reset @@ -1177,6 +1173,13 @@ static int prism2_hw_enable(struct net_d return 1; } + if (was_resetting && netif_queue_stopped(dev)) { + /* If hw_reset() was called during pending transmit, netif + * queue was stopped. Wake it up now since the wlan card has + * been resetted. */ + hostap_netif_wake_queues(dev); + } + return 0; } @@ -1205,6 +1208,9 @@ static void prism2_hw_shutdown(struct ne { local_info_t *local = (local_info_t *) dev->priv; + /* Allow only command completion events during disable */ + hfa384x_events_only_cmd(dev); + local->hw_ready = 0; if (local->dev_enabled) prism2_callback(local, PRISM2_CALLBACK_DISABLE); @@ -1216,9 +1222,6 @@ static void prism2_hw_shutdown(struct ne return; } - /* Allow only command completion events during disable */ - hfa384x_events_only_cmd(dev); - if ((no_disable & HOSTAP_HW_NO_DISABLE) == 0 && hfa384x_cmd(dev, HFA384X_CMDCODE_DISABLE, 0, NULL, NULL)) printk(KERN_WARNING "%s: Shutdown failed\n", dev_info); @@ -1269,10 +1272,19 @@ static void prism2_hw_reset(struct net_d } printk(KERN_WARNING "%s: %s: resetting card\n", dev_info, dev->name); - local->hw_resetting = 1; hfa384x_disable_interrupts(dev); - if (local->func->cor_sreset) + local->hw_resetting = 1; + if (local->func->cor_sreset) { + /* Host system seems to hang in some cases with high traffic + * load or shared interrupts during COR sreset. Disable shared + * interrupts during reset to avoid these crashes. COS sreset + * takes quite a long time, so it is unfortunate that this + * seems to be needed. Anyway, I do not know of any better way + * of avoiding the crash. */ + disable_irq(dev->irq); local->func->cor_sreset(local); + enable_irq(dev->irq); + } prism2_hw_shutdown(dev, 1); prism2_hw_config(dev, 0); local->hw_resetting = 0; @@ -1320,13 +1332,10 @@ static void prism2_netif_update_trans_st if (local->dev) local->dev->trans_start = jiffies; - -#ifdef PRISM2_HOSTAPD if (local->apdev) local->apdev->trans_start = jiffies; if (local->stadev) local->stadev->trans_start = jiffies; -#endif /* PRISM2_HOSTAPD */ wds = local->wds; while (wds != NULL) { @@ -1592,8 +1601,9 @@ static int prism2_tx(struct sk_buff *skb if ((local->func->card_present && !local->func->card_present(local)) || !local->hw_ready) { - printk(KERN_DEBUG "%s: prism2_tx: hw not ready - skipping\n", - dev->name); + if (net_ratelimit()) + printk(KERN_DEBUG "%s: prism2_tx: hw not ready - " + "skipping\n", dev->name); ret = 0; goto fail; } @@ -1610,13 +1620,11 @@ static int prism2_tx(struct sk_buff *skb use_wds = (local->iw_mode == IW_MODE_MASTER && !(local->wds_type & HOSTAP_WDS_STANDARD_FRAME)) ? WDS_OWN_FRAME : WDS_COMPLIANT_FRAME; -#ifdef PRISM2_HOSTAPD if (dev == local->stadev) { to_assoc_ap = 1; wds = NULL; use_wds = WDS_NO; } -#endif /* PRISM2_HOSTAPD */ } else { if (local->iw_mode == IW_MODE_REPEAT) { printk(KERN_DEBUG "%s: prism2_tx: trying to use " @@ -1748,12 +1756,8 @@ static int prism2_tx(struct sk_buff *skb } else if (local->iw_mode == IW_MODE_INFRA || to_assoc_ap) { fc |= WLAN_FC_TODS; /* To DS: Addr1 = BSSID, Addr2 = SA, Addr3 = DA */ -#ifdef PRISM2_HOSTAPD memcpy(&txdesc.addr1, to_assoc_ap ? local->assoc_ap_addr : local->bssid, ETH_ALEN); -#else /* PRISM2_HOSTAPD */ - memcpy(&txdesc.addr1, local->bssid, ETH_ALEN); -#endif /* PRISM2_HOSTAPD */ memcpy(&txdesc.addr2, skb->data + ETH_ALEN, ETH_ALEN); memcpy(&txdesc.addr3, skb->data, ETH_ALEN); } else if (local->iw_mode == IW_MODE_ADHOC) { @@ -1780,7 +1784,8 @@ static int prism2_tx(struct sk_buff *skb case AP_TX_CONTINUE: break; case AP_TX_CONTINUE_NOT_AUTHORIZED: - if (local->ieee_802_1x && ethertype != ETH_P_PAE) { + if (local->ieee_802_1x && ethertype != ETH_P_PAE && + use_wds == WDS_NO) { printk(KERN_DEBUG "%s: dropped frame to unauthorized " "port (IEEE 802.1X): ethertype=0x%04x\n", dev->name, ethertype); @@ -2018,8 +2023,6 @@ static int prism2_tx(struct sk_buff *skb } -#ifdef PRISM2_HOSTAPD - /* Called only from software IRQ */ static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev) { @@ -2118,8 +2121,6 @@ static int prism2_tx_80211(struct sk_buf return ret; } -#endif /* PRISM2_HOSTAPD */ - /* Send RX frame to netif with 802.11 (and possible prism) header. * Called from hardware or software IRQ context. */ @@ -2134,6 +2135,13 @@ static int prism2_rx_80211(struct net_de dev->last_rx = jiffies; + if (skb->len < sizeof(rxdesc)) { + printk(KERN_DEBUG "%s: prism2_rx_80211() called with too " + "short skb (len=%d)\n", dev->name, skb->len); + dev_kfree_skb_any(skb); + return 0; + } + /* make a local copy of rxdesc, since we will be changing the head of * the skb data */ memcpy(&rxdesc, skb->data, sizeof(rxdesc)); @@ -2637,16 +2645,14 @@ hostap_rx_frame_mgmt(local_info_t *local &rxdesc->frame_control); } -#ifdef PRISM2_HOSTAPD - /* send management frames to the user space daemon for - * processing */ - if (type == WLAN_FC_TYPE_MGMT) { + if (local->hostapd && type == WLAN_FC_TYPE_MGMT) { + /* send management frames to the user space daemon for + * processing */ local->apdevstats.rx_packets++; local->apdevstats.rx_bytes += skb->len; prism2_rx_80211(local->apdev, skb, PRISM2_RX_MGMT, NULL, 0); return 0; } -#endif /* PRISM2_HOSTAPD */ if (local->iw_mode == IW_MODE_MASTER) { if (type != WLAN_FC_TYPE_MGMT && type != WLAN_FC_TYPE_CTRL) { @@ -2915,17 +2921,15 @@ static void hostap_rx_skb(local_info_t * stats = hostap_get_stats(dev); } -#ifdef PRISM2_HOSTAPD if (local->iw_mode == IW_MODE_MASTER && !wds && (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) == WLAN_FC_FROMDS && local->stadev && memcmp(rxdesc->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) { - /* Frame from BSSID of the for which we are a client */ + /* Frame from BSSID of the AP for which we are a client */ skb->dev = dev = local->stadev; stats = hostap_get_stats(dev); from_assoc_ap = 1; } -#endif /* PRISM2_HOSTAPD */ dev->last_rx = jiffies; @@ -3032,16 +3036,16 @@ static void hostap_rx_skb(local_info_t * if (ethertype == ETH_P_PAE) { printk(KERN_DEBUG "%s: RX: IEEE 802.1X frame\n", dev->name); -#ifdef PRISM2_HOSTAPD - /* Send IEEE 802.1X frames to the user space daemon for - * processing */ - prism2_rx_80211(local->apdev, skb, PRISM2_RX_MGMT, - NULL, 0); - local->apdevstats.rx_packets++; - local->apdevstats.rx_bytes += skb->len; - goto rx_exit; -#endif /* PRISM2_HOSTAPD */ - } else if (!frame_authorized) { + if (local->hostapd && local->apdev) { + /* Send IEEE 802.1X frames to the user + * space daemon for processing */ + prism2_rx_80211(local->apdev, skb, + PRISM2_RX_MGMT, NULL, 0); + local->apdevstats.rx_packets++; + local->apdevstats.rx_bytes += skb->len; + goto rx_exit; + } + } else if (!frame_authorized && !wds) { printk(KERN_DEBUG "%s: dropped frame from " "unauthorized port (IEEE 802.1X): " "ethertype=0x%04x\n", @@ -3534,6 +3538,8 @@ static void hostap_bap_tasklet(unsigned if (local->func->card_present && !local->func->card_present(local)) return; + set_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); + /* Process all pending BAP events without generating new interrupts * for them */ while (frames-- > 0) { @@ -3550,8 +3556,12 @@ static void hostap_bap_tasklet(unsigned prism2_txexc(local); } + set_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); + clear_bit(HOSTAP_BITS_BAP_TASKLET, &local->bits); + /* Enable interrupts for new BAP events */ hfa384x_events_all(dev); + clear_bit(HOSTAP_BITS_BAP_TASKLET2, &local->bits); } @@ -3601,6 +3611,30 @@ static void prism2_infdrop(struct net_de /* Called only from hardware IRQ */ +static void prism2_ev_tick(struct net_device *dev) +{ + local_info_t *local = (local_info_t *) dev->priv; + u16 evstat, inten; + + if (local->last_tick_timer + 5 * HZ < jiffies && + local->last_tick_timer) { + evstat = HFA384X_INW(HFA384X_EVSTAT_OFF); + inten = HFA384X_INW(HFA384X_INTEN_OFF); + printk(KERN_INFO "%s: SW TICK stuck? " + "bits=0x%lx EvStat=%04x IntEn=%04x\n", + dev->name, local->bits, evstat, inten); + local->sw_tick_stuck++; + if ((evstat & HFA384X_BAP0_EVENTS) && + (inten & HFA384X_BAP0_EVENTS)) { + printk(KERN_INFO "%s: trying to recover from IRQ " + "hang\n", dev->name); + hfa384x_events_no_bap0(dev); + } + } +} + + +/* Called only from hardware IRQ */ static inline void prism2_check_magic(local_info_t *local) { /* at least PCI Prism2.5 with bus mastering seems to sometimes @@ -3609,7 +3643,7 @@ static inline void prism2_check_magic(lo * cannot anyway be removed during normal operation, so there is not * really any need for this verification with them. */ -#if !defined(PRISM2_PCI) || !defined(PRISM2_BUS_MASTER) +#ifndef PRISM2_PCI #ifndef final_version static long int last_magic_err = 0; struct net_device *dev = local->dev; @@ -3624,7 +3658,7 @@ static inline void prism2_check_magic(lo HFA384X_INW(HFA384X_SWSUPPORT0_OFF), HFA384X_MAGIC); last_magic_err = jiffies; - } else { + } else if (net_ratelimit()) { printk(KERN_DEBUG "%s: interrupt - SWSUPPORT0=%04x " "MAGIC=%04x\n", dev->name, HFA384X_INW(HFA384X_SWSUPPORT0_OFF), @@ -3634,7 +3668,7 @@ static inline void prism2_check_magic(lo return; } #endif /* final_version */ -#endif /* !PRISM2_PCI or !PRISM2_BUS_MASTER */ +#endif /* !PRISM2_PCI */ } @@ -3668,7 +3702,7 @@ static irqreturn_t prism2_interrupt(int return IRQ_HANDLED; } - ev &= local->event_mask; + ev &= HFA384X_INW(HFA384X_INTEN_OFF); if (ev == 0) break; @@ -3687,14 +3721,28 @@ static irqreturn_t prism2_interrupt(int goto next_event; if ((ev & HFA384X_EVENT_MASK) == 0) return IRQ_HANDLED; - if (local->dev_enabled) + if (local->dev_enabled && (ev & ~HFA384X_EV_TICK) && + net_ratelimit()) { printk(KERN_DEBUG "%s: prism2_interrupt: hw " - "not ready; skipping events 0x%04x\n", - dev->name, ev); + "not ready; skipping events 0x%04x " + "(IntEn=0x%04x)%s%s%s\n", + dev->name, ev, + HFA384X_INW(HFA384X_INTEN_OFF), + !local->hw_ready ? " (!hw_ready)" : "", + local->hw_resetting ? + " (hw_resetting)" : "", + !local->dev_enabled ? + " (!dev_enabled)" : ""); + } HFA384X_OUTW(ev, HFA384X_EVACK_OFF); return IRQ_HANDLED; } + if (ev & HFA384X_EV_TICK) { + prism2_ev_tick(dev); + HFA384X_OUTW(HFA384X_EV_TICK, HFA384X_EVACK_OFF); + } + #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) if (ev & HFA384X_EV_PCI_M0) { prism2_bus_master_ev(dev, BAP0); @@ -3908,6 +3956,19 @@ static void hostap_passive_scan(unsigned } +/* Software watchdog - called as a timer. Hardware interrupt (Tick event) is + * used to monitor that local->last_tick_timer is being updated. If not, + * interrupt busy-loop is assumed and driver tries to recover by masking out + * some events. */ +static void hostap_tick_timer(unsigned long data) +{ + local_info_t *local = (local_info_t *) data; + local->last_tick_timer = jiffies; + local->tick_timer.expires = jiffies + 2 * HZ; + add_timer(&local->tick_timer); +} + + #ifndef PRISM2_NO_PROCFS_DEBUG static int prism2_registers_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) @@ -4005,25 +4066,6 @@ prism2_init_local_data(struct prism2_hel goto fail; #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ -#ifdef PRISM2_HOSTAPD - local->apdev = kmalloc(sizeof(struct net_device) + PRISM2_NETDEV_EXTRA, - GFP_KERNEL); - if (local->apdev == NULL) - goto fail; - memset(local->apdev, 0, sizeof(struct net_device) + - PRISM2_NETDEV_EXTRA); - prism2_set_dev_name(local->apdev, local->apdev + 1); - - local->stadev = kmalloc(sizeof(struct net_device) + - PRISM2_NETDEV_EXTRA, - GFP_KERNEL); - if (local->stadev == NULL) - goto fail; - memset(local->stadev, 0, sizeof(struct net_device) + - PRISM2_NETDEV_EXTRA); - prism2_set_dev_name(local->stadev, local->stadev + 1); -#endif /* PRISM2_HOSTAPD */ - local->dev = kmalloc(sizeof(struct net_device) + PRISM2_NETDEV_EXTRA, GFP_KERNEL); if (local->dev == NULL) @@ -4048,6 +4090,7 @@ prism2_init_local_data(struct prism2_hel local->func->download = prism2_download; #endif /* PRISM2_DOWNLOAD_SUPPORT */ local->func->rx_80211 = prism2_rx_80211; + local->func->tx_80211 = prism2_tx_80211; local->disable_on_close = disable_on_close; local->mtu = mtu; @@ -4129,38 +4172,26 @@ prism2_init_local_data(struct prism2_hel local->passive_scan_timer.data = (unsigned long) local; local->passive_scan_timer.function = hostap_passive_scan; - hostap_setup_dev(local->dev, local, 1); + init_timer(&local->tick_timer); + local->tick_timer.data = (unsigned long) local; + local->tick_timer.function = hostap_tick_timer; + local->tick_timer.expires = jiffies + 2 * HZ; + add_timer(&local->tick_timer); -#ifdef PRISM2_HOSTAPD - local->apdev->priv = local; - hostap_setup_dev(local->apdev, local, 0); - local->apdev->hard_start_xmit = prism2_tx_80211; - local->apdev->type = ARPHRD_IEEE80211; - local->apdev->hard_header_parse = hostap_80211_header_parse; - - local->stadev->priv = local; - hostap_setup_dev(local->stadev, local, 0); -#endif /* PRISM2_HOSTAPD */ + hostap_setup_dev(local->dev, local, 1); local->saved_eth_header_parse = local->dev->hard_header_parse; return local; fail: - if (local->ap != NULL) - kfree(local->ap); - if (local->dev != NULL) - kfree(local->dev); + kfree(local->ap); + kfree(local->dev); #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) - if (local->bus_m0_buf) - kfree(local->bus_m0_buf); + kfree(local->bus_m0_buf); #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ -#ifdef PRISM2_HOSTAPD - if (local->apdev != NULL) - kfree(local->apdev); - if (local->stadev != NULL) - kfree(local->stadev); -#endif /* PRISM2_HOSTAPD */ + kfree(local->apdev); + kfree(local->stadev); kfree(local); return NULL; } @@ -4187,34 +4218,6 @@ static int prism2_init_dev(local_info_t } printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name); -#ifdef PRISM2_HOSTAPD - local->apdev->base_addr = dev->base_addr; - local->apdev->irq = dev->irq; - local->apdev->mem_start = dev->mem_start; - local->apdev->mem_end = dev->mem_end; - sprintf(local->apdev->name, "%sap", dev->name); - if (register_netdev(local->apdev)) { - printk(KERN_WARNING "%s: register_netdev(AP) failed!\n", - dev_info); - return 1; - } - printk(KERN_INFO "%s: Registered netdevice %s for AP management\n", - dev_info, local->apdev->name); - - local->stadev->base_addr = dev->base_addr; - local->stadev->irq = dev->irq; - local->stadev->mem_start = dev->mem_start; - local->stadev->mem_end = dev->mem_end; - sprintf(local->stadev->name, "%ssta", dev->name); - if (register_netdev(local->stadev)) { - printk(KERN_WARNING "%s: register_netdev(STA) failed!\n", - dev_info); - return 1; - } - printk(KERN_INFO "%s: Registered netdevice %s for STA use\n", - dev_info, local->stadev->name); -#endif /* PRISM2_HOSTAPD */ - hostap_init_proc(local); #ifndef PRISM2_NO_PROCFS_DEBUG create_proc_read_entry("registers", 0, local->proc, @@ -4243,6 +4246,9 @@ static void prism2_free_local_data(local if (timer_pending(&local->passive_scan_timer)) del_timer(&local->passive_scan_timer); + if (timer_pending(&local->tick_timer)) + del_timer(&local->tick_timer); + prism2_clear_cmd_queue(local); while ((skb = skb_dequeue(&local->info_list)) != NULL) @@ -4292,31 +4298,14 @@ static void prism2_free_local_data(local kfree(tx_cb_prev); } -#ifdef PRISM2_HOSTAPD - if (local->apdev && local->apdev->name && local->apdev->name[0]) { - unregister_netdev(local->apdev); - printk(KERN_INFO "%s: Netdevice %s unregistered\n", - dev_info, local->apdev->name); - } - if (local->apdev) - kfree(local->apdev); - - if (local->stadev && local->stadev->name && local->stadev->name[0]) { - unregister_netdev(local->stadev); - printk(KERN_INFO "%s: Netdevice %s unregistered\n", - dev_info, local->stadev->name); - } - if (local->stadev) - kfree(local->stadev); -#endif /* PRISM2_HOSTAPD */ + hostap_set_hostapd(local, 0, 0); if (local->dev && local->dev->name && local->dev->name[0]) { unregister_netdev(local->dev); printk(KERN_INFO "%s: Netdevice %s unregistered\n", dev_info, local->dev->name); } - if (local->dev) - kfree(local->dev); + kfree(local->dev); for (i = 0; i < PRISM2_FRAG_CACHE_LEN; i++) { if (local->frag_cache[i].skb != NULL) @@ -4324,18 +4313,11 @@ static void prism2_free_local_data(local } kfree(local->ap); - #if defined(PRISM2_PCI) && defined(PRISM2_BUS_MASTER) - if (local->bus_m0_buf) - kfree(local->bus_m0_buf); + kfree(local->bus_m0_buf); #endif /* PRISM2_PCI and PRISM2_BUS_MASTER */ - - if (local->pda) - kfree(local->pda); - - if (local->last_scan_results) - kfree(local->last_scan_results); - + kfree(local->pda); + kfree(local->last_scan_results); kfree(local); } diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_ioctl.c linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_ioctl.c --- linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_ioctl.c 2003-05-15 21:52:31.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_ioctl.c 2003-06-02 17:04:07.000000000 +0200 @@ -244,8 +244,18 @@ static int prism2_ioctl_siwencode(struct done: local->open_wep = erq->flags & IW_ENCODE_OPEN; - if (hostap_set_encryption(local) || local->func->reset_port(dev)) { - printk(KERN_DEBUG "set_encryption or reset_port failed\n"); + if (hostap_set_encryption(local)) { + printk(KERN_DEBUG "%s: set_encryption failed\n", dev->name); + return -EINVAL; + } + + /* Do not reset port0 if card is in Managed mode since resetting will + * generate new IEEE 802.11 authentication which may end up in looping + * with IEEE 802.1X. Prism2 documentation seem to require port reset + * after WEP configuration. However, keys are apparently changed at + * least in Managed mode. */ + if (local->iw_mode != IW_MODE_INFRA && local->func->reset_port(dev)) { + printk(KERN_DEBUG "%s: reset_port failed\n", dev->name); return -EINVAL; } @@ -656,13 +666,11 @@ static int prism2_ioctl_giwap(struct net { local_info_t *local = (local_info_t *) dev->priv; -#ifdef PRISM2_HOSTAPD if (dev == local->stadev) { memcpy(&ap_addr->sa_data, local->assoc_ap_addr, ETH_ALEN); ap_addr->sa_family = ARPHRD_ETHER; return 0; } -#endif /* PRISM2_HOSTAPD */ if (local->func->get_rid(dev, HFA384X_RID_CURRENTBSSID, &ap_addr->sa_data, ETH_ALEN, 1) < 0) @@ -1061,12 +1069,10 @@ static int prism2_ioctl_giwmode(struct n { local_info_t *local = (local_info_t *) dev->priv; -#ifdef PRISM2_HOSTAPD if (dev == local->stadev) { *mode = IW_MODE_INFRA; return 0; } -#endif /* PRISM2_HOSTAPD */ *mode = local->iw_mode; return 0; @@ -1948,7 +1954,10 @@ static const struct iw_priv_args prism2_ IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "oper_rates" }, { PRISM2_PARAM_OPER_RATES, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "getoper_rates" }, - + { PRISM2_PARAM_HOSTAPD, + IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "hostapd" }, + { PRISM2_PARAM_HOSTAPD, + 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "gethostapd" }, #endif /* PRISM2_USE_WE_SUB_IOCTLS */ #endif /* WIRELESS_EXT >= 12 */ }; @@ -2299,6 +2308,10 @@ static int prism2_ioctl_priv_prism2_para ret = -EINVAL; break; + case PRISM2_PARAM_HOSTAPD: + ret = hostap_set_hostapd(local, value, 1); + break; + default: printk(KERN_DEBUG "%s: prism2_param: unknown param %d\n", dev->name, param); @@ -2480,6 +2493,10 @@ static int prism2_ioctl_priv_get_prism2_ *param = local->tx_rate_control; break; + case PRISM2_PARAM_HOSTAPD: + *param = local->hostapd; + break; + default: printk(KERN_DEBUG "%s: get_prism2_param: unknown param %d\n", dev->name, *param); @@ -2680,7 +2697,7 @@ static int prism2_ioctl_priv_set_rid_wor } -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT static int ap_mac_cmd_ioctl(local_info_t *local, int *cmd) { int ret = 0; @@ -2735,7 +2752,7 @@ static int ap_mac_ioctl(local_info_t *lo } } #endif /* PRISM2_USE_WE_TYPE_ADDR */ -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ #if defined(PRISM2_DOWNLOAD_SUPPORT) && WIRELESS_EXT > 8 @@ -2987,7 +3004,6 @@ static int prism2_ioctl_set_rid(local_in } -#ifdef PRISM2_HOSTAPD static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local, struct prism2_hostapd_param *param, int param_len) @@ -2997,7 +3013,6 @@ static int prism2_ioctl_set_assoc_ap_add memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN); return 0; } -#endif /* PRISM2_HOSTAPD */ static int prism2_ioctl_priv_hostapd(local_info_t *local, struct iw_point *p) @@ -3032,11 +3047,9 @@ static int prism2_ioctl_priv_hostapd(loc case PRISM2_HOSTAPD_SET_RID: ret = prism2_ioctl_set_rid(local, param, p->length); break; -#ifdef PRISM2_HOSTAPD case PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR: ret = prism2_ioctl_set_assoc_ap_addr(local, param, p->length); break; -#endif /* PRISM2_HOSTAPD */ default: ret = prism2_hostapd(local->ap, param); ap_ioctl = 1; @@ -3476,7 +3489,7 @@ int hostap_ioctl(struct net_device *dev, (int *) wrq->u.name); break; -#ifndef PRISM2_HOSTAPD +#ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT case PRISM2_IOCTL_MACCMD: if (!capable(CAP_NET_ADMIN)) ret = -EPERM; else ret = ap_mac_cmd_ioctl(local, (int *) wrq->u.name); @@ -3535,7 +3548,7 @@ int hostap_ioctl(struct net_device *dev, } break; #endif /* PRISM2_USE_WE_TYPE_ADDR */ -#endif /* PRISM2_HOSTAPD */ +#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ /* Private ioctls that are not used with iwpriv; diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_pci.c linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_pci.c --- linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_pci.c 2003-05-15 21:52:31.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_pci.c 2003-06-02 17:04:07.000000000 +0200 @@ -168,9 +168,6 @@ static int hfa384x_to_bap(struct net_dev /* FIX: This might change at some point.. */ #include "hostap_hw.c" -/* FIX: can jiffies be used this way from every place cor_sreset could be - * called? (mainly, spin_lock_irq? hw interrupt handler?) */ - static void prism2_pci_cor_sreset(local_info_t *local) { struct net_device *dev = local->dev; @@ -184,22 +181,17 @@ static void prism2_pci_cor_sreset(local_ /* #define PRISM2_PCI_USE_LONG_DELAYS */ #ifdef PRISM2_PCI_USE_LONG_DELAYS - int timeout; + int i; HFA384X_OUTW(0x0080, HFA384X_PCICOR_OFF); - timeout = jiffies + HZ / 4; - while (time_before(jiffies, timeout)) - udelay(5); + mdelay(250); HFA384X_OUTW(0x0, HFA384X_PCICOR_OFF); - timeout = jiffies + HZ / 2; - while (time_before(jiffies, timeout)) - udelay(5); + mdelay(500); /* Wait for f/w to complete initialization (CMD:BUSY == 0) */ - timeout = jiffies + 2 * HZ; - while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && - time_before(jiffies, timeout)) + i = 2000000 / 10; + while ((HFA384X_INW(HFA384X_CMD_OFF) & HFA384X_CMD_BUSY) && --i) udelay(10); #else /* PRISM2_PCI_USE_LONG_DELAYS */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_proc.c linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_proc.c --- linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_proc.c 2003-05-15 21:52:31.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_proc.c 2003-06-02 17:04:07.000000000 +0200 @@ -27,6 +27,7 @@ static int prism2_debug_proc_read(char * p += sprintf(p, "wds_max_connections=%d\n", local->wds_max_connections); p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled); + p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck); if (local->crypt && local->crypt->ops) p += sprintf(p, "crypt=%s\n", local->crypt->ops->name); diff -Naurp linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_wlan.h linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_wlan.h --- linux-2.4.20-wolk4.1s/drivers/net/wireless/hostap_wlan.h 2003-05-15 21:52:31.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/net/wireless/hostap_wlan.h 2003-06-03 00:14:48.000000000 +0200 @@ -888,6 +888,7 @@ enum { PRISM2_PARAM_IO_DEBUG = 31, PRISM2_PARAM_BASIC_RATES = 32, PRISM2_PARAM_OPER_RATES = 33, + PRISM2_PARAM_HOSTAPD = 34, }; enum { HOSTAP_ANTSEL_DO_NOT_TOUCH = 0, HOSTAP_ANTSEL_DIVERSITY = 1, @@ -1108,6 +1109,7 @@ struct prism2_helper_functions { #endif /* PRISM2_DOWNLOAD_SUPPORT */ int (*rx_80211)(struct net_device *dev, struct sk_buff *skb, int type, char *extra, int extra_len); + int (*tx_80211)(struct sk_buff *skb, struct net_device *dev); }; struct local_info { @@ -1133,6 +1135,8 @@ struct local_info { /* bitfield for atomic bitops */ #define HOSTAP_BITS_TRANSMIT 0 +#define HOSTAP_BITS_BAP_TASKLET 1 +#define HOSTAP_BITS_BAP_TASKLET2 2 long bits; struct ap_data *ap; @@ -1192,7 +1196,6 @@ struct local_info { #define HOSTAP_WDS_AP_CLIENT BIT(1) #define HOSTAP_WDS_STANDARD_FRAME BIT(2) u32 wds_type; - u16 event_mask; /* Mask for events, INTEN reg */ u16 tx_control; /* flags to be used in TX description */ int manual_retry_count; /* -1 = use f/w default; otherwise retry count * to be used with all frames */ @@ -1213,14 +1216,15 @@ struct local_info { int (*saved_eth_header_parse)(struct sk_buff *skb, unsigned char *haddr); int monitor_allow_fcserr; -#ifdef PRISM2_HOSTAPD + + int hostapd; /* whether user space daemon, hostapd, is used for AP + * management */ struct net_device *apdev; struct net_device_stats apdevstats; char assoc_ap_addr[ETH_ALEN]; struct net_device *stadev; struct net_device_stats stadevstats; -#endif /* PRISM2_HOSTAPD */ struct prism2_crypt_data *crypt; struct timer_list crypt_deinit_timer; @@ -1303,6 +1307,10 @@ struct local_info { int passive_scan_channel; enum { PASSIVE_SCAN_WAIT, PASSIVE_SCAN_LISTEN } passive_scan_state; + struct timer_list tick_timer; + unsigned long last_tick_timer; + unsigned int sw_tick_stuck; + #ifdef PRISM2_IO_DEBUG #define PRISM2_IO_DEBUG_SIZE 10000 u32 io_debug[PRISM2_IO_DEBUG_SIZE]; diff -Naurp linux-2.4.20-wolk4.1s/drivers/pci/quirks.c linux-2.4.20-wolk4.2-fullkernel/drivers/pci/quirks.c --- linux-2.4.20-wolk4.1s/drivers/pci/quirks.c 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/pci/quirks.c 2003-06-02 17:23:42.000000000 +0200 @@ -326,6 +326,9 @@ static void __init quirk_vt82c686_acpi(s #ifdef CONFIG_X86_IO_APIC + +#include + extern int nr_ioapics; /* @@ -449,6 +452,8 @@ static void __init quirk_cardbus_legacy( pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0); } +#ifdef CONFIG_X86_IO_APIC + /* * The AMD io apic can hang the box when an apic irq is masked. * We check all revs >= B0 (yet not in the pre production!) as the bug @@ -471,6 +476,14 @@ static void __init quirk_amd_ioapic(stru } } +static void __init quirk_ioapic_rmw(struct pci_dev *dev) +{ + if (dev->devfn == 0 && dev->bus->number == 0) + sis_apic_bug = 1; +} + +#endif /* CONFIG_X86_IO_APIC */ + /* * Following the PCI ordering rules is optional on the AMD762. I'm not * sure what the designers were smoking but let's not inhale... @@ -714,7 +727,10 @@ quirk_amd_8131_ioapic }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irqpic }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_6, quirk_via_irqpic }, +#ifdef CONFIG_X86_IO_APIC { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_ANY_ID, quirk_ioapic_rmw }, +#endif { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering }, /* * i82380FB mobile docking controller: its PCI-to-PCI bridge diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/Config.in linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/Config.in --- linux-2.4.20-wolk4.1s/drivers/scsi/Config.in 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/Config.in 2003-06-02 17:23:43.000000000 +0200 @@ -19,6 +19,8 @@ fi dep_tristate ' SCSI media changer support' CONFIG_CHR_DEV_SCH $CONFIG_SCSI dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI +dep_tristate ' SCSI monitor support' CONFIG_CHR_DEV_SM $CONFIG_SCSI + comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' bool ' Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN @@ -117,6 +119,21 @@ if [ "$CONFIG_PARPORT" != "n" ]; then bool ' ppa/imm option - Assume slow parport control register' CONFIG_SCSI_IZIP_SLOW_CTR fi fi + +dep_tristate 'Parallel Port SCSI adapters' CONFIG_PPSCSI $CONFIG_SCSI $CONFIG_PARPORT +if [ "$CONFIG_PPSCSI" != "n" ]; then + dep_tristate ' Adaptec APA-348 adapter' CONFIG_PPSCSI_T348 $CONFIG_PPSCSI + dep_tristate ' Adaptec APA-358 adapter' CONFIG_PPSCSI_T358 $CONFIG_PPSCSI + dep_tristate ' Iomega VPI0 adapter' CONFIG_PPSCSI_VPI0 $CONFIG_PPSCSI +# if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +# dep_tristate ' Iomega VPI2 adapter (EXPERIMENTAL)' CONFIG_PPSCSI_VPI2 $CONFIG_PPSCSI +# fi + dep_tristate ' OnSpec 90c26 adapter' CONFIG_PPSCSI_ONSCSI $CONFIG_PPSCSI + dep_tristate ' Shining SparSCI adapter' CONFIG_PPSCSI_SPARCSI $CONFIG_PPSCSI + dep_tristate ' Shuttle EPSA-2 adapter' CONFIG_PPSCSI_EPSA2 $CONFIG_PPSCSI + dep_tristate ' Shuttle EPST adapter' CONFIG_PPSCSI_EPST $CONFIG_PPSCSI +fi + dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI if [ "$CONFIG_MCA" = "y" ]; then dep_tristate 'NCR Dual 700 MCA SCSI support' CONFIG_SCSI_NCR_D700 $CONFIG_SCSI diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/Makefile linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/Makefile --- linux-2.4.20-wolk4.1s/drivers/scsi/Makefile 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/Makefile 2003-06-05 22:45:12.000000000 +0200 @@ -144,7 +144,6 @@ obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o obj-$(CONFIG_SCSI_FCAL) += fcal.o obj-$(CONFIG_SCSI_CPQFCTS) += cpqfc.o obj-$(CONFIG_SCSI_LASI700) += lasi700.o 53c700.o -obj-$(CONFIG_SCSI_NSP32) += nsp32.o subdir-$(CONFIG_ARCH_ACORN) += ../acorn/scsi obj-$(CONFIG_ARCH_ACORN) += ../acorn/scsi/acorn-scsi.o @@ -155,6 +154,16 @@ obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o obj-$(CONFIG_CHR_DEV_SCH) += ch.o +obj-$(CONFIG_CHR_DEV_SM) += scsimon.o +obj-$(CONFIG_PPSCSI) += ppscsi.o +obj-$(CONFIG_PPSCSI_T348) += t348.o +obj-$(CONFIG_PPSCSI_T358) += t358.o +obj-$(CONFIG_PPSCSI_ONSCSI) += onscsi.o +obj-$(CONFIG_PPSCSI_EPSA2) += epsa2.o +obj-$(CONFIG_PPSCSI_EPST) += epst.o +obj-$(CONFIG_PPSCSI_VPI0) += vpi0.o +obj-$(CONFIG_PPSCSI_VPI2) += vpi2.o +obj-$(CONFIG_PPSCSI_SPARCSI) += sparcsi.o list-multi := scsi_mod.o sd_mod.o sr_mod.o initio.o a100u2w.o cpqfc.o \ zalon7xx_mod.o diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/Makefile linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/Makefile --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/Makefile 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/Makefile 2003-06-05 22:45:12.000000000 +0200 @@ -17,14 +17,22 @@ EXTRA_CFLAGS += -I$(TOPDIR)/drivers/scsi #EXTRA_CFLAGS += -g # Platform Specific Files -obj-aic7xxx = aic7xxx_osm.o aic7xxx_proc.o aic7770_osm.o +obj-aic7xxx = aic7xxx_osm.o aic7xxx_proc.o # Core Files -obj-aic7xxx += aic7xxx_core.o aic7xxx_93cx6.o aic7770.o +obj-aic7xxx += aic7xxx_core.o aic7xxx_93cx6.o ifeq ($(CONFIG_AIC7XXX_REG_PRETTY_PRINT),y) obj-aic7xxx += aic7xxx_reg_print.o endif +#EISA Specific Files +AIC7XXX_EISA_ARCH = $(filter i386 alpha,$(ARCH)) +ifneq ($(AIC7XXX_EISA_ARCH),) +obj-aic7xxx += aic7770.o +# Platform Specific EISA Files +obj-aic7xxx += aic7770_osm.o +endif + #PCI Specific Files ifeq ($(CONFIG_PCI),y) obj-aic7xxx += aic7xxx_pci.o diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/README.aic79xx linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/README.aic79xx --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/README.aic79xx 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/README.aic79xx 2003-06-05 22:45:12.000000000 +0200 @@ -47,29 +47,121 @@ The following information is available i Ultra320 SCSI ASIC 2. Version History + 1.3.10 (June 3rd, 2003) + - Align the SCB_TAG field on a 16byte boundary. This avoids + SCB corruption on some PCI-33 busses. + - Correct non-zero luns on Rev B. hardware. + - Update for change in 2.5.X SCSI proc FS interface. + - When negotiation async via an 8bit WDTR message, send + an SDTR with an offset of 0 to be sure the target + knows we are async. This works around a firmware defect + in the Quantum Atlas 10K. + - Implement controller susupend and resume. + - Clear PCI error state during driver attach so that we + don't disable memory mapped I/O due to a stray write + by some other driver probe that occurred before we + claimed the controller. + + 1.3.9 (May 22nd, 2003) + - Fix compiler errors. + - Remove S/G splitting for segments that cross a 4GB boundary. + This is guaranteed not to happen in Linux. + - Add support for scsi_report_device_reset() found in + 2.5.X kernels. + - Add 7901B support. + - Simplify handling of the packtized lun Rev A workaround. + - Correct and simplify handling of the ignore wide residue + message. The previous code would fail to report a residual + if the transaction data length was even and we received + an IWR message. + + 1.3.8 (April 29th, 2003) + - Fix types accessed via the command line interface code. + - Perform a few firmware optimizations. + - Fix "Unexpected PKT busfree" errors. + - Use a sequencer interrupt to notify the host of + commands with bad status. We defer the notification + until there are no outstanding selections to ensure + that the host is interrupted for as short a time as + possible. + - Remove pre-2.2.X support. + - Add support for new 2.5.X interrupt API. + - Correct big-endian architecture support. + + 1.3.7 (April 16th, 2003) + - Use del_timer_sync() to ensure that no timeouts + are pending during controller shutdown. + - For pre-2.5.X kernels, carefully adjust our segment + list size to avoid SCSI malloc pool fragmentation. + - Cleanup channel display in our /proc output. + - Workaround duplicate device entries in the mid-layer + devlice list during add-single-device. + + 1.3.6 (March 28th, 2003) + - Correct a double free in the Domain Validation code. + - Correct a reference to free'ed memory during controller + shutdown. + - Reset the bus on an SE->LVD change. This is required + to reset our transcievers. + + 1.3.5 (March 24th, 2003) + - Fix a few register window mode bugs. + - Include read streaming in the PPR flags we display in + diagnostics as well as /proc. + - Add PCI hot plug support for 2.5.X kernels. + - Correct default precompensation value for RevA hardware. + - Fix Domain Validation thread shutdown. + - Add a firmware workaround to make the LED blink + brighter during packetized operations on the H2A4. + - Correct /proc display of user read streaming settings. + - Simplify driver locking by releasing the io_request_lock + upon driver entry from the mid-layer. + - Cleanup command line parsing and move much of this code + to aiclib. + + 1.3.4 (February 28th, 2003) + - Correct a race condition in our error recovery handler. + - Allow Test Unit Ready commands to take a full 5 seconds + during Domain Validation. + + 1.3.2 (February 19th, 2003) + - Correct a Rev B. regression due to the GEM318 + compatibility fix included in 1.3.1. + + 1.3.1 (February 11th, 2003) + - Add support for the 39320A. + - Improve recovery for certain PCI-X errors. + - Fix handling of LQ/DATA/LQ/DATA for the + same write transaction that can occur without + interveining training. + - Correct compatibility issues with the GEM318 + enclosure services device. + - Correct data corruption issue that occurred under + high tag depth write loads. + - Adapt to a change in the 2.5.X daemonize() API. + - Correct a "Missing case in ahd_handle_scsiint" panic. + + 1.3.0 (January 21st, 2003) + - Full regression testing for all U320 products completed. + - Added abort and target/lun reset error recovery handler and + interrupt coalessing. + + 1.2.0 (November 14th, 2002) + - Added support for Domain Validation + - Add support for the Hewlett-Packard version of the 39320D + and AIC-7902 adapters. + Support for previous adapters has not been fully tested and should + only be used at the customer's own risk. + + 1.1.1 (September 24th, 2002) + - Added support for the Linux 2.5.X kernel series + + 1.1.0 (September 17th, 2002) + - Added support for four additional SCSI products: + ASC-39320, ASC-29320, ASC-29320LP, AIC-7901. - (V1.3.0, January 2003) Full regression testing for all U320 products - completed. - - (V1.3.0 ALPHA, November 2002) Initial Alpha release. - Added abort and target/lun reset error recovery handler and - interrupt coalessing. - - (V1.2.0, November 2002) Added support for Domain Validation and - Hewlett-Packard version of the 39320D and AIC-7902 adapters. - Support for previous adapters has not been fully tested and should - only be used at the customer's own risk. - - (V1.1.1, September 2002) Added support for the Linux 2.5.X kernel series - - (V1.1.0, August 2002) Added support for four additional SCSI - products: ASC-39320, ASC-29320, ASC-29320LP, AIC-7901. - - (V1.1, August 2002) Added support for four additional SCSI - products: ASC-39320, ASC-29320, ASC-29320LP, AIC-7901. - - (V1.0, May 2002) This is the initial release of the - Ultra320 FMS. The following is a list of supported features: + 1.0.0 (May 30th, 2002) + - Initial driver release. 2.1. Software/Hardware Features - Support for the SPI-4 "Ultra320" standard: @@ -82,6 +174,7 @@ The following information is available i supported) - Support for the PCI-X standard up to 133MHz - Support for the PCI v2.2 standard + - Domain Validation 2.2. Operating System Support: - Redhat Linux 7.2, 7.3, 8.0, Advanced Server 2.1 diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/README.aic7xxx linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/README.aic7xxx --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/README.aic7xxx 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/README.aic7xxx 2003-06-05 22:45:12.000000000 +0200 @@ -131,22 +131,54 @@ The following information is available i SCSI "stub" effects. 2. Version History + 6.2.36 (June 3rd, 2003) + - Correct code that disables PCI parity error checking. + - Correct and simplify handling of the ignore wide residue + message. The previous code would fail to report a residual + if the transaction data length was even and we received + an IWR message. + - Add support for the 2.5.X EISA framework. + - Update for change in 2.5.X SCSI proc FS interface. + - Correct Domain Validation command-line option parsing. + - When negotiation async via an 8bit WDTR message, send + an SDTR with an offset of 0 to be sure the target + knows we are async. This works around a firmware defect + in the Quantum Atlas 10K. + - Clear PCI error state during driver attach so that we + don't disable memory mapped I/O due to a stray write + by some other driver probe that occurred before we + claimed the controller. + + 6.2.35 (May 14th, 2003) + - Fix a few GCC 3.3 compiler warnings. + - Correct operation on EISA Twin Channel controller. + - Add support for 2.5.X's scsi_report_device_reset(). + + 6.2.34 (May 5th, 2003) + - Fix locking regression instroduced in 6.2.29 that + could cuase a lock order reversal between the io_request_lock + and our per-softc lock. This was only possible on RH9, + SuSE, and kernel.org 2.4.X kernels. + + 6.2.33 (April 30th, 2003) + - Dynamically disable PCI parity error reporting after + 10 errors are reported to the user. These errors are + the result of some other device issuing PCI transactions + with bad parity. Once the user has been informed of the + problem, continuing to report the errors just degrades + our performance. + + 6.2.32 (March 28th, 2003) + - Dynamically sized S/G lists to avoid SCSI malloc + pool fragmentation and SCSI mid-layer deadlock. + + 6.2.28 (January 20th, 2003) + - Domain Validation Fixes + - Add ability to disable PCI parity error checking. + - Enhanced Memory Mapped I/O probe - 6.2.33 - Dynamically disable PCI parity error reporting after - 10 errors are reported to the user. These errors are - the result of some other device issuing PCI transactions - with bad parity. Once the user has been informed of the - problem, continuing to report the errors just degrades - our performance. - - 6.2.32 - Dynamically sized S/G lists to avoid SCSI malloc - pool fragmentation and SCSI mid-layer deadlock. - - 6.2.28 - Domain Validation Fixes - PCI parity error disable - Enhanced Memory Mapped I/O probe - - 6.2.20 - Added Domain Validation + 6.2.20 (November 7th, 2002) + - Added Domain Validation. 3. Command Line Options diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7770.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7770.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7770.c 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7770.c 2003-06-05 22:45:46.000000000 +0200 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#30 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#32 $ * * $FreeBSD$ */ @@ -68,8 +68,7 @@ static ahc_device_setup_t ahc_aic7770_VL static ahc_device_setup_t ahc_aic7770_EISA_setup;; static ahc_device_setup_t ahc_aic7770_setup; - -struct aic7770_identity aic7770_ident_table [] = +struct aic7770_identity aic7770_ident_table[] = { { ID_AHA_274x, @@ -84,6 +83,12 @@ struct aic7770_identity aic7770_ident_ta ahc_aic7770_VL_setup }, { + ID_AHA_284x, + 0xFFFFFFFE, + "Adaptec 284X SCSI adapter (BIOS Disabled)", + ahc_aic7770_VL_setup + }, + { ID_OLV_274x, 0xFFFFFFFF, "Adaptec (Olivetti OEM) 274X SCSI adapter", @@ -161,7 +166,7 @@ aic7770_config(struct ahc_softc *ahc, st ahc->bus_suspend = aic7770_suspend; ahc->bus_resume = aic7770_resume; - error = ahc_reset(ahc); + error = ahc_reset(ahc, /*reinit*/FALSE); if (error != 0) return (error); diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7770_osm.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7770_osm.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7770_osm.c 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7770_osm.c 2003-06-05 22:45:12.000000000 +0200 @@ -1,7 +1,7 @@ /* * Linux driver attachment glue for aic7770 based controllers. * - * Copyright (c) 2000-2001 Adaptec Inc. + * Copyright (c) 2000-2003 Adaptec Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,27 +36,90 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_osm.c#13 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_osm.c#14 $ */ #include "aic7xxx_osm.h" +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +#include +#include + +#define EISA_MFCTR_CHAR0(ID) (char)(((ID>>26) & 0x1F) | '@') /* Bits 26-30 */ +#define EISA_MFCTR_CHAR1(ID) (char)(((ID>>21) & 0x1F) | '@') /* Bits 21-25 */ +#define EISA_MFCTR_CHAR2(ID) (char)(((ID>>16) & 0x1F) | '@') /* Bits 16-20 */ +#define EISA_PRODUCT_ID(ID) (short)((ID>>4) & 0xFFF) /* Bits 4-15 */ +#define EISA_REVISION_ID(ID) (uint8_t)(ID & 0x0F) /* Bits 0-3 */ + +static int aic7770_eisa_dev_probe(struct device *dev); +static int aic7770_eisa_dev_remove(struct device *dev); +static struct eisa_driver aic7770_driver = { + .driver = { + .name = "aic7xxx", + .probe = aic7770_eisa_dev_probe, + .remove = aic7770_eisa_dev_remove, + } +}; + +typedef struct device *aic7770_dev_t; +#else #define MINSLOT 1 #define NUMSLOTS 16 #define IDOFFSET 0x80 -int -aic7770_linux_probe(Scsi_Host_Template *template) +typedef void *aic7770_dev_t; +#endif + +static int aic7770_linux_config(struct aic7770_identity *entry, + aic7770_dev_t dev, u_int eisaBase); + +void +ahc_linux_eisa_init(void) { -#if defined(__i386__) || defined(__alpha__) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + struct eisa_device_id *eid; + struct aic7770_identity *id; + int i; + + if (aic7xxx_probe_eisa_vl == 0) + return; + + /* + * Linux requires the EISA IDs to be specified in + * the EISA ID string format. Perform the conversion + * and setup a table with a NUL terminal entry. + */ + aic7770_driver.id_table = malloc(sizeof(struct eisa_device_id) * + (ahc_num_aic7770_devs + 1), + M_DEVBUF, M_NOWAIT); + if (aic7770_driver.id_table == NULL) + return; + + for (eid = (struct eisa_device_id *)aic7770_driver.id_table, + id = aic7770_ident_table, i = 0; + i < ahc_num_aic7770_devs; eid++, id++, i++) { + + sprintf(eid->sig, "%c%c%c%03X%01X", + EISA_MFCTR_CHAR0(id->full_id), + EISA_MFCTR_CHAR1(id->full_id), + EISA_MFCTR_CHAR2(id->full_id), + EISA_PRODUCT_ID(id->full_id), + EISA_REVISION_ID(id->full_id)); + eid->driver_data = i; + } + eid->sig[0] = 0; + + eisa_driver_register(&aic7770_driver); +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) */ struct aic7770_identity *entry; - struct ahc_softc *ahc; - int i, slot; - int eisaBase; - int found; + u_int slot; + u_int eisaBase; + u_int i; + + if (aic7xxx_probe_eisa_vl == 0) + return; eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET; - found = 0; for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) { uint32_t eisa_id; size_t id_size; @@ -83,45 +146,64 @@ aic7770_linux_probe(Scsi_Host_Template * continue; /* no EISA card in slot */ entry = aic7770_find_device(eisa_id); - if (entry != NULL) { - char buf[80]; - char *name; - int error; - - /* - * Allocate a softc for this card and - * set it up for attachment by our - * common detect routine. - */ - sprintf(buf, "ahc_eisa:%d", slot); - name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); - if (name == NULL) - break; - strcpy(name, buf); - ahc = ahc_alloc(template, name); - if (ahc == NULL) { - /* - * If we can't allocate this one, - * chances are we won't be able to - * allocate future card structures. - */ - break; - } - error = aic7770_config(ahc, entry, eisaBase); - if (error != 0) { - ahc->bsh.ioport = 0; - ahc_free(ahc); - continue; - } - found++; - } + if (entry != NULL) + aic7770_linux_config(entry, NULL, eisaBase); } - return (found); -#else - return (0); #endif } +void +ahc_linux_eisa_exit(void) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + if (aic7xxx_probe_eisa_vl == 0) + return; + + if (aic7770_driver.id_table != NULL) { + eisa_driver_unregister(&aic7770_driver); + free(aic7770_driver.id_table, M_DEVBUF); + } +#endif +} + +static int +aic7770_linux_config(struct aic7770_identity *entry, aic7770_dev_t dev, + u_int eisaBase) +{ + struct ahc_softc *ahc; + char buf[80]; + char *name; + int error; + + /* + * Allocate a softc for this card and + * set it up for attachment by our + * common detect routine. + */ + sprintf(buf, "ahc_eisa:%d", eisaBase >> 12); + name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); + if (name == NULL) + return (ENOMEM); + strcpy(name, buf); + ahc = ahc_alloc(&aic7xxx_driver_template, name); + if (ahc == NULL) { + free(name, M_DEVBUF); + return (ENOMEM); + } + error = aic7770_config(ahc, entry, eisaBase); + if (error != 0) { + ahc->bsh.ioport = 0; + ahc_free(ahc); + return (error); + } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + dev->driver_data = (void *)ahc; + if (aic7xxx_detect_complete) + error = ahc_linux_register_host(ahc, &aic7xxx_driver_template); +#endif + return (error); +} + int aic7770_map_registers(struct ahc_softc *ahc, u_int port) { @@ -129,6 +211,8 @@ aic7770_map_registers(struct ahc_softc * * Lock out other contenders for our i/o space. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) + if (check_region(port, AHC_EISA_IOSIZE) != 0) + return (ENOMEM); request_region(port, AHC_EISA_IOSIZE, "aic7xxx"); #else if (request_region(port, AHC_EISA_IOSIZE, "aic7xxx") == 0) @@ -155,3 +239,41 @@ aic7770_map_int(struct ahc_softc *ahc, u return (-error); } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) +static int +aic7770_eisa_dev_probe(struct device *dev) +{ + struct eisa_device *edev; + + edev = to_eisa_device(dev); + return (aic7770_linux_config(aic7770_ident_table + edev->id.driver_data, + dev, edev->base_addr+AHC_EISA_SLOT_OFFSET)); +} + +static int +aic7770_eisa_dev_remove(struct device *dev) +{ + struct ahc_softc *ahc; + u_long l; + + /* + * We should be able to just perform + * the free directly, but check our + * list for extra sanity. + */ + ahc_list_lock(&l); + ahc = ahc_find_softc((struct ahc_softc *)dev->driver_data); + if (ahc != NULL) { + u_long s; + + ahc_lock(ahc, &s); + ahc_intr_enable(ahc, FALSE); + ahc_unlock(ahc, &s); + ahc_free(ahc); + } + ahc_list_unlock(&l); + + return (0); +} +#endif diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx.h linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx.h --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx.h 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx.h 2003-06-05 22:45:12.000000000 +0200 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#89 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#92 $ * * $FreeBSD$ */ @@ -494,21 +494,21 @@ struct hardware_scb { * transfer. */ #define SG_PTR_MASK 0xFFFFFFF8 -/*16*/ uint64_t dataptr; -/*24*/ uint32_t datacnt; /* Byte 3 is spare. */ -/*28*/ uint32_t sgptr; -/*32*/ uint32_t hscb_busaddr; -/*36*/ uint32_t next_hscb_busaddr; -/*40*/ uint8_t control; /* See SCB_CONTROL in aic79xx.reg for details */ -/*41*/ uint8_t scsiid; /* +/*16*/ uint16_t tag; /* Reused by Sequencer. */ +/*18*/ uint8_t control; /* See SCB_CONTROL in aic79xx.reg for details */ +/*19*/ uint8_t scsiid; /* * Selection out Id * Our Id (bits 0-3) Their ID (bits 4-7) */ -/*42*/ uint8_t lun; -/*43*/ uint8_t task_attribute; -/*44*/ uint8_t cdb_len; -/*45*/ uint8_t task_management; -/*46*/ uint16_t tag; /* Reused by Sequencer. */ +/*20*/ uint8_t lun; +/*21*/ uint8_t task_attribute; +/*22*/ uint8_t cdb_len; +/*23*/ uint8_t task_management; +/*24*/ uint64_t dataptr; +/*32*/ uint32_t datacnt; /* Byte 3 is spare. */ +/*36*/ uint32_t sgptr; +/*40*/ uint32_t hscb_busaddr; +/*44*/ uint32_t next_hscb_busaddr; /********** Long lun field only downloaded for full 8 byte lun support ********/ /*48*/ uint8_t pkt_long_lun[8]; /******* Fields below are not Downloaded (Sequencer may use for scratch) ******/ @@ -1225,20 +1225,20 @@ struct ahd_softc { int seltime; /* - * Interrupt coalessing settings. + * Interrupt coalescing settings. */ -#define AHD_INT_COALESSING_TIMER_DEFAULT 250 /*us*/ -#define AHD_INT_COALESSING_MAXCMDS_DEFAULT 10 -#define AHD_INT_COALESSING_MAXCMDS_MAX 127 -#define AHD_INT_COALESSING_MINCMDS_DEFAULT 5 -#define AHD_INT_COALESSING_MINCMDS_MAX 127 -#define AHD_INT_COALESSING_THRESHOLD_DEFAULT 2000 -#define AHD_INT_COALESSING_STOP_THRESHOLD_DEFAULT 1000 - u_int int_coalessing_timer; - u_int int_coalessing_maxcmds; - u_int int_coalessing_mincmds; - u_int int_coalessing_threshold; - u_int int_coalessing_stop_threshold; +#define AHD_INT_COALESCING_TIMER_DEFAULT 250 /*us*/ +#define AHD_INT_COALESCING_MAXCMDS_DEFAULT 10 +#define AHD_INT_COALESCING_MAXCMDS_MAX 127 +#define AHD_INT_COALESCING_MINCMDS_DEFAULT 5 +#define AHD_INT_COALESCING_MINCMDS_MAX 127 +#define AHD_INT_COALESCING_THRESHOLD_DEFAULT 2000 +#define AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT 1000 + u_int int_coalescing_timer; + u_int int_coalescing_maxcmds; + u_int int_coalescing_mincmds; + u_int int_coalescing_threshold; + u_int int_coalescing_stop_threshold; uint16_t user_discenable;/* Disconnection allowed */ uint16_t user_tagenable;/* Tagged Queuing allowed */ @@ -1362,11 +1362,11 @@ int ahd_parse_vpddata(struct ahd_soft int ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc); void ahd_intr_enable(struct ahd_softc *ahd, int enable); -void ahd_update_coalessing_values(struct ahd_softc *ahd, +void ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds, u_int mincmds); -void ahd_enable_coalessing(struct ahd_softc *ahd, +void ahd_enable_coalescing(struct ahd_softc *ahd, int enable); void ahd_pause_and_flushwork(struct ahd_softc *ahd); int ahd_suspend(struct ahd_softc *ahd); @@ -1379,13 +1379,13 @@ struct scb *ahd_get_scb(struct ahd_soft void ahd_free_scb(struct ahd_softc *ahd, struct scb *scb); void ahd_alloc_scbs(struct ahd_softc *ahd); void ahd_free(struct ahd_softc *ahd); -int ahd_reset(struct ahd_softc *ahd); +int ahd_reset(struct ahd_softc *ahd, int reinit); void ahd_shutdown(void *arg); -int ahd_write_flexport(struct ahd_softc *ahd, - u_int addr, u_int value); -int ahd_read_flexport(struct ahd_softc *ahd, u_int addr, - uint8_t *value); -int ahd_wait_flexport(struct ahd_softc *ahd); +int ahd_write_flexport(struct ahd_softc *ahd, + u_int addr, u_int value); +int ahd_read_flexport(struct ahd_softc *ahd, u_int addr, + uint8_t *value); +int ahd_wait_flexport(struct ahd_softc *ahd); /*************************** Interrupt Services *******************************/ void ahd_pci_intr(struct ahd_softc *ahd); @@ -1514,7 +1514,7 @@ extern uint32_t ahd_debug; #define AHD_SHOW_QUEUE 0x02000 #define AHD_SHOW_TQIN 0x04000 #define AHD_SHOW_SG 0x08000 -#define AHD_SHOW_INT_COALESSING 0x10000 +#define AHD_SHOW_INT_COALESCING 0x10000 #define AHD_DEBUG_SEQUENCER 0x20000 #endif void ahd_print_scb(struct scb *scb); diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx.reg linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx.reg --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx.reg 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx.reg 2003-06-05 22:45:12.000000000 +0200 @@ -39,7 +39,7 @@ * * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -286,7 +286,7 @@ register HS_MAILBOX { address 0x00B access_mode RW mask HOST_TQINPOS 0x80 /* Boundary at either 0 or 128 */ - mask ENINT_COALESS 0x40 /* Perform interrupt coalessing */ + mask ENINT_COALESCE 0x40 /* Perform interrupt coalescing */ } /* @@ -1377,7 +1377,10 @@ register LUNLEN { address 0x030 access_mode RW modes M_CFG + mask ILUNLEN 0x0F + mask TLUNLEN 0xF0 } +const LUNLEN_SINGLE_LEVEL_LUN 0xF /* * CDB Limit @@ -3704,28 +3707,28 @@ scratch_ram { } /* - * The maximum amount of time to wait, when interrupt coalessing + * The maximum amount of time to wait, when interrupt coalescing * is enabled, before issueing a CMDCMPLT interrupt for a completed * command. */ - INT_COALESSING_TIMER { + INT_COALESCING_TIMER { size 2 } /* - * The maximum number of commands to coaless into a single interrupt. + * The maximum number of commands to coalesce into a single interrupt. * Actually the 2's complement of that value to simplify sequencer * code. */ - INT_COALESSING_MAXCMDS { + INT_COALESCING_MAXCMDS { size 1 } /* * The minimum number of commands still outstanding required - * to continue coalessing (2's complement of value). + * to continue coalescing (2's complement of value). */ - INT_COALESSING_MINCMDS { + INT_COALESCING_MINCMDS { size 1 } @@ -3737,9 +3740,9 @@ scratch_ram { } /* - * The count of commands that have been coalessed. + * The count of commands that have been coalesced. */ - INT_COALESSING_CMDCOUNT { + INT_COALESCING_CMDCOUNT { size 1 } @@ -3797,32 +3800,8 @@ scb { size 4 alias SCB_NEXT_COMPLETE } - SCB_DATAPTR { - size 8 - } - SCB_DATACNT { - /* - * The last byte is really the high address bits for - * the data address. - */ - size 4 - field SG_LAST_SEG 0x80 /* In the fourth byte */ - field SG_HIGH_ADDR_BITS 0x7F /* In the fourth byte */ - } - SCB_SGPTR { - size 4 - field SG_STATUS_VALID 0x04 /* In the first byte */ - field SG_FULL_RESID 0x02 /* In the first byte */ - field SG_LIST_NULL 0x01 /* In the first byte */ - } - SCB_BUSADDR { - size 4 - } - SCB_NEXT { - alias SCB_NEXT_SCB_BUSADDR - size 2 - } - SCB_NEXT2 { + SCB_TAG { + alias SCB_FIFO_USE_COUNT size 2 } SCB_CONTROL { @@ -3842,10 +3821,15 @@ scb { } SCB_LUN { size 1 - field LID 0xff + field LID 0xff } SCB_TASK_ATTRIBUTE { size 1 + /* + * Overloaded field for non-packetized + * ignore wide residue message handling. + */ + field SCB_XFERLEN_ODD 0x01 } SCB_CDB_LEN { size 1 @@ -3854,8 +3838,32 @@ scb { SCB_TASK_MANAGEMENT { size 1 } - SCB_TAG { - alias SCB_FIFO_USE_COUNT + SCB_DATAPTR { + size 8 + } + SCB_DATACNT { + /* + * The last byte is really the high address bits for + * the data address. + */ + size 4 + field SG_LAST_SEG 0x80 /* In the fourth byte */ + field SG_HIGH_ADDR_BITS 0x7F /* In the fourth byte */ + } + SCB_SGPTR { + size 4 + field SG_STATUS_VALID 0x04 /* In the first byte */ + field SG_FULL_RESID 0x02 /* In the first byte */ + field SG_LIST_NULL 0x01 /* In the first byte */ + } + SCB_BUSADDR { + size 4 + } + SCB_NEXT { + alias SCB_NEXT_SCB_BUSADDR + size 2 + } + SCB_NEXT2 { size 2 } SCB_SPARE { diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx.seq linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx.seq --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx.seq 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx.seq 2003-06-05 22:45:12.000000000 +0200 @@ -40,7 +40,7 @@ * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $" PATCH_ARG_LIST = "struct ahd_softc *ahd" PREFIX = "ahd_" @@ -212,44 +212,44 @@ fill_qoutfifo_dmadone: qoutfifo_updated: /* * If there are more commands waiting to be dma'ed - * to the host, always coaless. Otherwise honor the + * to the host, always coalesce. Otherwise honor the * host's wishes. */ - cmp COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne coaless_by_count; - cmp COMPLETE_SCB_HEAD[1], SCB_LIST_NULL jne coaless_by_count; - test LOCAL_HS_MAILBOX, ENINT_COALESS jz issue_cmdcmplt; + cmp COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count; + cmp COMPLETE_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count; + test LOCAL_HS_MAILBOX, ENINT_COALESCE jz issue_cmdcmplt; /* * If we have relatively few commands outstanding, don't * bother waiting for another command to complete. */ - test CMDS_PENDING[1], 0xFF jnz coaless_by_count; + test CMDS_PENDING[1], 0xFF jnz coalesce_by_count; /* Add -1 so that jnc means <= not just < */ - add A, -1, INT_COALESSING_MINCMDS; + add A, -1, INT_COALESCING_MINCMDS; add NONE, A, CMDS_PENDING; jnc issue_cmdcmplt; /* - * If coalessing, only coaless up to the limit + * If coalescing, only coalesce up to the limit * provided by the host driver. */ -coaless_by_count: - mov A, INT_COALESSING_MAXCMDS; - add NONE, A, INT_COALESSING_CMDCOUNT; +coalesce_by_count: + mov A, INT_COALESCING_MAXCMDS; + add NONE, A, INT_COALESCING_CMDCOUNT; jc issue_cmdcmplt; /* * If the timer is not currently active, * fire it up. */ test INTCTL, SWTMINTMASK jz return; - bmov SWTIMER, INT_COALESSING_TIMER, 2; + bmov SWTIMER, INT_COALESCING_TIMER, 2; mvi CLRSEQINTSTAT, CLRSEQ_SWTMRTO; or INTCTL, SWTMINTEN|SWTIMER_START; and INTCTL, ~SWTMINTMASK ret; issue_cmdcmplt: mvi INTSTAT, CMDCMPLT; - clr INT_COALESSING_CMDCOUNT; + clr INT_COALESCING_CMDCOUNT; or INTCTL, SWTMINTMASK ret; BEGIN_CRITICAL; @@ -261,6 +261,15 @@ fetch_new_scb_done: clr A; add CMDS_PENDING, 1; adc CMDS_PENDING[1], A; + if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) { + /* + * "Short Luns" are not placed into outgoing LQ + * packets in the correct byte order. Use a full + * sized lun field instead and fill it with the + * one byte of lun information we support. + */ + mov SCB_PKT_LUN[6], SCB_LUN; + } /* * The FIFO use count field is shared with the * tag set by the host so that our SCB dma engine @@ -324,7 +333,7 @@ fill_qoutfifo_loop: mov CCSCBRAM, SCBPTR; or CCSCBRAM, A, SCBPTR[1]; mov NONE, SDSCB_QOFF; - inc INT_COALESSING_CMDCOUNT; + inc INT_COALESCING_CMDCOUNT; add CMDS_PENDING, -1; adc CMDS_PENDING[1], -1; cmp SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je fill_qoutfifo_done; @@ -863,7 +872,8 @@ mesgin_ign_wide_residue: mvi REG0 call inb_next; cmp REG0, 0x01 jne mesgin_reject; test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; - test DATA_COUNT_ODD, 0x1 jz mesgin_done; + test SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jnz mesgin_done; + SET_SEQINTCODE(IGN_WIDE_RES) jmp mesgin_done; mesgin_proto_violation: @@ -1308,8 +1318,6 @@ idle_sg_avail: bmov HADDR, CCSGRAM, 4; } bmov HCNT, CCSGRAM, 3; - test HCNT[0], 0x1 jz . + 2; - xor DATA_COUNT_ODD, 0x1; bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { and HADDR[4], SG_HIGH_ADDR_BITS, SCB_RESIDUAL_DATACNT[3]; @@ -1325,8 +1333,6 @@ sg_advance: adc SCB_RESIDUAL_SGPTR[2],A; adc SCB_RESIDUAL_SGPTR[3],A; mov SINDEX, SCB_RESIDUAL_SGPTR[0]; - test DATA_COUNT_ODD, 0x1 jz . + 2; - or SINDEX, ODD_SEG; test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 3; or SINDEX, LAST_SEG; clr SG_STATE; @@ -1352,12 +1358,9 @@ sg_advance: */ load_first_seg: bmov HADDR, SCB_DATAPTR, 11; - and DATA_COUNT_ODD, 0x1, SCB_DATACNT[0]; and REG_ISR, ~SG_FULL_RESID, SCB_SGPTR[0]; test SCB_DATACNT[3], SG_LAST_SEG jz . + 2; or REG_ISR, LAST_SEG; - test DATA_COUNT_ODD, 0x1 jz . + 2; - or REG_ISR, ODD_SEG; mov SG_CACHE_PRE, REG_ISR; mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN); /* @@ -1507,7 +1510,7 @@ data_phase_done: * send Ignore Wide Residue messages for data-in phases. test DFCNTRL, DIRECTION jz target_ITloop; test SSTAT1, REQINIT jnz .; - test DATA_COUNT_ODD, 0x1 jz target_ITloop; + test SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jz target_ITloop; SET_MODE(M_SCSI, M_SCSI) test NEGCONOPTS, WIDEXFER jz target_ITloop; */ @@ -1577,9 +1580,6 @@ sgptr_fixup: adc SCB_RESIDUAL_SGPTR[3], -1; sgptr_fixup_done: and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; - clr DATA_COUNT_ODD; - test SG_CACHE_SHADOW, ODD_SEG jz . + 2; - or DATA_COUNT_ODD, 0x1; clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ bmov SCB_RESIDUAL_DATACNT, SHCNT, 3 ret; diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_core.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_core.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_core.c 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_core.c 2003-06-05 22:45:13.000000000 +0200 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#190 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#197 $ * * $FreeBSD$ */ @@ -1880,21 +1880,32 @@ ahd_handle_nonpkt_busfree(struct ahd_sof tinfo->goal.ppr_options = 0; ahd_qinfifo_requeue_tail(ahd, scb); printerror = 0; - } else if ((ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE) - || ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE)) + } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE) && ppr_busfree == 0) { /* - * Negotiation Rejected. Go-async and + * Negotiation Rejected. Go-narrow and * retry command. */ #ifdef AHD_DEBUG if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - printf("Negotiation rejected busfree.\n"); + printf("WDTR negotiation rejected busfree.\n"); #endif ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, AHD_TRANS_CUR|AHD_TRANS_GOAL, /*paused*/TRUE); + ahd_qinfifo_requeue_tail(ahd, scb); + printerror = 0; + } else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE) + && ppr_busfree == 0) { + /* + * Negotiation Rejected. Go-async and + * retry command. + */ +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) + printf("SDTR negotiation rejected busfree.\n"); +#endif ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0, /*ppr_options*/0, @@ -3232,6 +3243,7 @@ ahd_build_transfer_msg(struct ahd_softc * may change. */ period = tinfo->goal.period; + offset = tinfo->goal.offset; ppr_options = tinfo->goal.ppr_options; /* Target initiated PPR is not allowed in the SCSI spec */ if (devinfo->role == ROLE_TARGET) @@ -3239,7 +3251,7 @@ ahd_build_transfer_msg(struct ahd_softc ahd_devlimited_syncrate(ahd, tinfo, &period, &ppr_options, devinfo->role); dowide = tinfo->curr.width != tinfo->goal.width; - dosync = tinfo->curr.period != period; + dosync = tinfo->curr.offset != offset || tinfo->curr.period != period; /* * Only use PPR if we have options that need it, even if the device * claims to support it. There might be an expander in the way @@ -3249,7 +3261,7 @@ ahd_build_transfer_msg(struct ahd_softc if (!dowide && !dosync && !doppr) { dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT; - dosync = tinfo->goal.period != 0; + dosync = tinfo->goal.offset != 0; } if (!dowide && !dosync && !doppr) { @@ -3983,22 +3995,30 @@ ahd_parse_msg(struct ahd_softc *ahd, str response = TRUE; sending_reply = TRUE; } + /* + * After a wide message, we are async, but + * some devices don't seem to honor this portion + * of the spec. Force a renegotiation of the + * sync component of our transfer agreement even + * if our goal is async. By updating our width + * after forcing the negotiation, we avoid + * renegotiating for width. + */ + ahd_update_neg_request(ahd, devinfo, tstate, + tinfo, AHD_NEG_ALWAYS); ahd_set_width(ahd, devinfo, bus_width, AHD_TRANS_ACTIVE|AHD_TRANS_GOAL, /*paused*/TRUE); - /* After a wide message, we are async */ - ahd_set_syncrate(ahd, devinfo, /*period*/0, - /*offset*/0, /*ppr_options*/0, - AHD_TRANS_ACTIVE, /*paused*/TRUE); if (sending_reply == FALSE && reject == FALSE) { - if (tinfo->goal.offset) { - ahd->msgout_index = 0; - ahd->msgout_len = 0; - ahd_build_transfer_msg(ahd, devinfo); - ahd->msgout_index = 0; - response = TRUE; - } + /* + * We will always have an SDTR to send. + */ + ahd->msgout_index = 0; + ahd->msgout_len = 0; + ahd_build_transfer_msg(ahd, devinfo); + ahd->msgout_index = 0; + response = TRUE; } done = MSGLOOP_MSGCOMPLETE; break; @@ -4401,7 +4421,7 @@ ahd_handle_ign_wide_residue(struct ahd_s sgptr = ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR); if ((sgptr & SG_LIST_NULL) != 0 - && ahd_inb(ahd, DATA_COUNT_ODD) == 1) { + && (ahd_inb(ahd, SCB_TASK_ATTRIBUTE) & SCB_XFERLEN_ODD) != 0) { /* * If the residual occurred on the last * transfer and the transfer request was @@ -4414,29 +4434,20 @@ ahd_handle_ign_wide_residue(struct ahd_s uint32_t sglen; /* Pull in the rest of the sgptr */ - sgptr |= - (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 3) << 24) - | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 2) << 16) - | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 1) << 8); - sgptr &= SG_PTR_MASK; - data_cnt = - (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+3) << 24) - | (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+2) << 16) - | (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+1) << 8) - | (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT)); - - data_addr = (((uint64_t)ahd_inb(ahd, SHADDR + 7)) << 56) - | (((uint64_t)ahd_inb(ahd, SHADDR + 6)) << 48) - | (((uint64_t)ahd_inb(ahd, SHADDR + 5)) << 40) - | (((uint64_t)ahd_inb(ahd, SHADDR + 4)) << 32) - | (ahd_inb(ahd, SHADDR + 3) << 24) - | (ahd_inb(ahd, SHADDR + 2) << 16) - | (ahd_inb(ahd, SHADDR + 1) << 8) - | (ahd_inb(ahd, SHADDR)); - + sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); + data_cnt = ahd_inl_scbram(ahd, SCB_RESIDUAL_DATACNT); + if ((sgptr & SG_LIST_NULL) != 0) { + /* + * The residual data count is not updated + * for the command run to completion case. + * Explicitly zero the count. + */ + data_cnt &= ~AHD_SG_LEN_MASK; + } + data_addr = ahd_inq(ahd, SHADDR); data_cnt += 1; data_addr -= 1; - + sgptr &= SG_PTR_MASK; if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { struct ahd_dma64_seg *sg; @@ -4504,16 +4515,17 @@ ahd_handle_ign_wide_residue(struct ahd_s sg); } } - ahd_outb(ahd, SCB_RESIDUAL_SGPTR + 3, sgptr >> 24); - ahd_outb(ahd, SCB_RESIDUAL_SGPTR + 2, sgptr >> 16); - ahd_outb(ahd, SCB_RESIDUAL_SGPTR + 1, sgptr >> 8); - ahd_outb(ahd, SCB_RESIDUAL_SGPTR, sgptr); - - ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 3, data_cnt >> 24); - ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 2, data_cnt >> 16); - ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 1, data_cnt >> 8); - ahd_outb(ahd, SCB_RESIDUAL_DATACNT, data_cnt); + /* + * Toggle the "oddness" of the transfer length + * to handle this mid-transfer ignore wide + * residue. This ensures that the oddness is + * correct for subsequent data transfers. + */ + ahd_outb(ahd, SCB_TASK_ATTRIBUTE, + ahd_inb(ahd, SCB_TASK_ATTRIBUTE) ^ SCB_XFERLEN_ODD); + ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); + ahd_outl(ahd, SCB_RESIDUAL_DATACNT, data_cnt); /* * The FIFO's pointers will be updated if/when the * sequencer re-enters a data phase. @@ -4806,12 +4818,12 @@ ahd_alloc(void *platform_arg, char *name | AHD_EXTENDED_TRANS_A|AHD_STPWLEVEL_A; ahd_timer_init(&ahd->reset_timer); ahd_timer_init(&ahd->stat_timer); - ahd->int_coalessing_timer = AHD_INT_COALESSING_TIMER_DEFAULT; - ahd->int_coalessing_maxcmds = AHD_INT_COALESSING_MAXCMDS_DEFAULT; - ahd->int_coalessing_mincmds = AHD_INT_COALESSING_MINCMDS_DEFAULT; - ahd->int_coalessing_threshold = AHD_INT_COALESSING_THRESHOLD_DEFAULT; - ahd->int_coalessing_stop_threshold = - AHD_INT_COALESSING_STOP_THRESHOLD_DEFAULT; + ahd->int_coalescing_timer = AHD_INT_COALESCING_TIMER_DEFAULT; + ahd->int_coalescing_maxcmds = AHD_INT_COALESCING_MAXCMDS_DEFAULT; + ahd->int_coalescing_mincmds = AHD_INT_COALESCING_MINCMDS_DEFAULT; + ahd->int_coalescing_threshold = AHD_INT_COALESCING_THRESHOLD_DEFAULT; + ahd->int_coalescing_stop_threshold = + AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT; if (ahd_platform_alloc(ahd, platform_arg) != 0) { ahd_free(ahd); @@ -5008,15 +5020,20 @@ ahd_shutdown(void *arg) ahd_timer_stop(&ahd->stat_timer); /* This will reset most registers to 0, but not all */ - ahd_reset(ahd); + ahd_reset(ahd, /*reinit*/FALSE); } /* * Reset the controller and record some information about it - * that is only available just after a reset. + * that is only available just after a reset. If "reinit" is + * non-zero, this reset occured after initial configuration + * and the caller requests that the chip be fully reinitialized + * to a runable state. Chip interrupts are *not* enabled after + * a reinitialization. The caller must enable interrupts via + * ahd_intr_enable(). */ int -ahd_reset(struct ahd_softc *ahd) +ahd_reset(struct ahd_softc *ahd, int reinit) { u_int sxfrctl1; int wait; @@ -5109,7 +5126,7 @@ ahd_reset(struct ahd_softc *ahd) * If a recovery action has forced a chip reset, * re-initialize the chip to our liking. */ - if (ahd->init_level > 0) + if (reinit != 0) ahd_chip_init(ahd); return (0); @@ -5722,6 +5739,7 @@ ahd_alloc_scbs(struct ahd_softc *ahd) next_scb->sg_list = segs; next_scb->sense_data = sense_data; next_scb->sense_busaddr = sense_busaddr; + memset(hscb, 0, sizeof(*hscb)); next_scb->hscb = hscb; hscb->hscb_busaddr = ahd_htole32(hscb_busaddr); @@ -6181,7 +6199,7 @@ ahd_chip_init(struct ahd_softc *ahd) ahd_outb(ahd, LUNLEN, sizeof(ahd->next_queued_hscb->pkt_long_lun) - 1); } else { - ahd_outb(ahd, LUNLEN, sizeof(ahd->next_queued_hscb->lun) - 1); + ahd_outb(ahd, LUNLEN, LUNLEN_SINGLE_LEVEL_LUN); } ahd_outb(ahd, CDBLIMIT, SCB_CDB_LEN_PTR - 1); ahd_outb(ahd, MAXCMD, 0xFF); @@ -6341,14 +6359,14 @@ ahd_chip_init(struct ahd_softc *ahd) ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF); /* - * Default to coalessing disabled. + * Default to coalescing disabled. */ - ahd_outw(ahd, INT_COALESSING_CMDCOUNT, 0); + ahd_outw(ahd, INT_COALESCING_CMDCOUNT, 0); ahd_outw(ahd, CMDS_PENDING, 0); - ahd_update_coalessing_values(ahd, ahd->int_coalessing_timer, - ahd->int_coalessing_maxcmds, - ahd->int_coalessing_mincmds); - ahd_enable_coalessing(ahd, FALSE); + ahd_update_coalescing_values(ahd, ahd->int_coalescing_timer, + ahd->int_coalescing_maxcmds, + ahd->int_coalescing_mincmds); + ahd_enable_coalescing(ahd, FALSE); ahd_loadseq(ahd); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); @@ -6601,30 +6619,30 @@ ahd_intr_enable(struct ahd_softc *ahd, i } void -ahd_update_coalessing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds, +ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds, u_int mincmds) { if (timer > AHD_TIMER_MAX_US) timer = AHD_TIMER_MAX_US; - ahd->int_coalessing_timer = timer; + ahd->int_coalescing_timer = timer; - if (maxcmds > AHD_INT_COALESSING_MAXCMDS_MAX) - maxcmds = AHD_INT_COALESSING_MAXCMDS_MAX; - if (mincmds > AHD_INT_COALESSING_MINCMDS_MAX) - mincmds = AHD_INT_COALESSING_MINCMDS_MAX; - ahd->int_coalessing_maxcmds = maxcmds; - ahd_outw(ahd, INT_COALESSING_TIMER, timer / AHD_TIMER_US_PER_TICK); - ahd_outb(ahd, INT_COALESSING_MAXCMDS, -maxcmds); - ahd_outb(ahd, INT_COALESSING_MINCMDS, -mincmds); + if (maxcmds > AHD_INT_COALESCING_MAXCMDS_MAX) + maxcmds = AHD_INT_COALESCING_MAXCMDS_MAX; + if (mincmds > AHD_INT_COALESCING_MINCMDS_MAX) + mincmds = AHD_INT_COALESCING_MINCMDS_MAX; + ahd->int_coalescing_maxcmds = maxcmds; + ahd_outw(ahd, INT_COALESCING_TIMER, timer / AHD_TIMER_US_PER_TICK); + ahd_outb(ahd, INT_COALESCING_MAXCMDS, -maxcmds); + ahd_outb(ahd, INT_COALESCING_MINCMDS, -mincmds); } void -ahd_enable_coalessing(struct ahd_softc *ahd, int enable) +ahd_enable_coalescing(struct ahd_softc *ahd, int enable) { - ahd->hs_mailbox &= ~ENINT_COALESS; + ahd->hs_mailbox &= ~ENINT_COALESCE; if (enable) - ahd->hs_mailbox |= ENINT_COALESS; + ahd->hs_mailbox |= ENINT_COALESCE; ahd_outb(ahd, HS_MAILBOX, ahd->hs_mailbox); ahd_flush_device_writes(ahd); ahd_run_qoutfifo(ahd); @@ -6710,141 +6728,24 @@ ahd_pause_and_flushwork(struct ahd_softc int ahd_suspend(struct ahd_softc *ahd) { -#if 0 - uint8_t *ptr; - int i; ahd_pause_and_flushwork(ahd); - if (LIST_FIRST(&ahd->pending_scbs) != NULL) - return (EBUSY); - -#if AHD_TARGET_MODE - /* - * XXX What about ATIOs that have not yet been serviced? - * Perhaps we should just refuse to be suspended if we - * are acting in a target role. - */ - if (ahd->pending_device != NULL) + if (LIST_FIRST(&ahd->pending_scbs) != NULL) { + ahd_unpause(ahd); return (EBUSY); -#endif - - /* Save volatile registers */ - ahd->suspend_state.channel[0].scsiseq = ahd_inb(ahd, SCSISEQ0); - ahd->suspend_state.channel[0].sxfrctl0 = ahd_inb(ahd, SXFRCTL0); - ahd->suspend_state.channel[0].sxfrctl1 = ahd_inb(ahd, SXFRCTL1); - ahd->suspend_state.channel[0].simode0 = ahd_inb(ahd, SIMODE0); - ahd->suspend_state.channel[0].simode1 = ahd_inb(ahd, SIMODE1); - ahd->suspend_state.channel[0].seltimer = ahd_inb(ahd, SELTIMER); - ahd->suspend_state.channel[0].seqctl = ahd_inb(ahd, SEQCTL0); - ahd->suspend_state.dscommand0 = ahd_inb(ahd, DSCOMMAND0); - ahd->suspend_state.dspcistatus = ahd_inb(ahd, DSPCISTATUS); - - if ((ahd->features & AHD_DT) != 0) { - u_int sfunct; - - sfunct = ahd_inb(ahd, SFUNCT) & ~ALT_MODE; - ahd_outb(ahd, SFUNCT, sfunct | ALT_MODE); - ahd->suspend_state.optionmode = ahd_inb(ahd, OPTIONMODE); - ahd_outb(ahd, SFUNCT, sfunct); - ahd->suspend_state.crccontrol1 = ahd_inb(ahd, CRCCONTROL1); - } - - if ((ahd->features & AHD_MULTI_FUNC) != 0) - ahd->suspend_state.scbbaddr = ahd_inb(ahd, SCBBADDR); - - if ((ahd->features & AHD_ULTRA2) != 0) - ahd->suspend_state.dff_thrsh = ahd_inb(ahd, DFF_THRSH); - - ptr = ahd->suspend_state.scratch_ram; - for (i = 0; i < 64; i++) - *ptr++ = ahd_inb(ahd, SRAM_BASE + i); - - if ((ahd->features & AHD_MORE_SRAM) != 0) { - for (i = 0; i < 16; i++) - *ptr++ = ahd_inb(ahd, TARG_OFFSET + i); - } - - ptr = ahd->suspend_state.btt; - for (i = 0;i < AHD_NUM_TARGETS; i++) { - int j; - - for (j = 0;j < AHD_NUM_LUNS_NONPKT; j++) { - u_int tcl; - - tcl = BUILD_TCL_RAW(i, 'A', j); - *ptr = ahd_find_busy_tcl(ahd, tcl); - } } ahd_shutdown(ahd); -#endif return (0); } int ahd_resume(struct ahd_softc *ahd) { -#if 0 - uint8_t *ptr; - int i; - - ahd_reset(ahd); - - ahd_build_free_scb_list(ahd); - - /* Restore volatile registers */ - ahd_outb(ahd, SCSISEQ0, ahd->suspend_state.channel[0].scsiseq); - ahd_outb(ahd, SXFRCTL0, ahd->suspend_state.channel[0].sxfrctl0); - ahd_outb(ahd, SXFRCTL1, ahd->suspend_state.channel[0].sxfrctl1); - ahd_outb(ahd, SIMODE0, ahd->suspend_state.channel[0].simode0); - ahd_outb(ahd, SIMODE1, ahd->suspend_state.channel[0].simode1); - ahd_outb(ahd, SELTIMER, ahd->suspend_state.channel[0].seltimer); - ahd_outb(ahd, SEQCTL0, ahd->suspend_state.channel[0].seqctl); - if ((ahd->features & AHD_ULTRA2) != 0) - ahd_outb(ahd, SCSIID_ULTRA2, ahd->our_id); - else - ahd_outb(ahd, SCSIID, ahd->our_id); - - ahd_outb(ahd, DSCOMMAND0, ahd->suspend_state.dscommand0); - ahd_outb(ahd, DSPCISTATUS, ahd->suspend_state.dspcistatus); - if ((ahd->features & AHD_DT) != 0) { - u_int sfunct; - - sfunct = ahd_inb(ahd, SFUNCT) & ~ALT_MODE; - ahd_outb(ahd, SFUNCT, sfunct | ALT_MODE); - ahd_outb(ahd, OPTIONMODE, ahd->suspend_state.optionmode); - ahd_outb(ahd, SFUNCT, sfunct); - ahd_outb(ahd, CRCCONTROL1, ahd->suspend_state.crccontrol1); - } - - if ((ahd->features & AHD_MULTI_FUNC) != 0) - ahd_outb(ahd, SCBBADDR, ahd->suspend_state.scbbaddr); - - if ((ahd->features & AHD_ULTRA2) != 0) - ahd_outb(ahd, DFF_THRSH, ahd->suspend_state.dff_thrsh); - - ptr = ahd->suspend_state.scratch_ram; - for (i = 0; i < 64; i++) - ahd_outb(ahd, SRAM_BASE + i, *ptr++); - - if ((ahd->features & AHD_MORE_SRAM) != 0) { - for (i = 0; i < 16; i++) - ahd_outb(ahd, TARG_OFFSET + i, *ptr++); - } - - ptr = ahd->suspend_state.btt; - for (i = 0;i < AHD_NUM_TARGETS; i++) { - int j; - - for (j = 0;j < AHD_NUM_LUNS; j++) { - u_int tcl; - - tcl = BUILD_TCL(i << 4, j); - ahd_busy_tcl(ahd, tcl, *ptr); - } - } -#endif + ahd_reset(ahd, /*reinit*/TRUE); + ahd_intr_enable(ahd, TRUE); + ahd_restart(ahd); return (0); } @@ -7497,7 +7398,7 @@ ahd_reset_current_bus(struct ahd_softc * * we must reset the chip. */ ahd_delay(AHD_BUSRESET_DELAY); - ahd_reset(ahd); + ahd_reset(ahd, /*reinit*/TRUE); ahd_intr_enable(ahd, /*enable*/TRUE); AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK); } @@ -7718,20 +7619,20 @@ ahd_stat_timer(void *arg) } ahd_lock(ahd, &s); - enint_coal = ahd->hs_mailbox & ENINT_COALESS; - if (ahd->cmdcmplt_total > ahd->int_coalessing_threshold) - enint_coal |= ENINT_COALESS; - else if (ahd->cmdcmplt_total < ahd->int_coalessing_stop_threshold) - enint_coal &= ~ENINT_COALESS; + enint_coal = ahd->hs_mailbox & ENINT_COALESCE; + if (ahd->cmdcmplt_total > ahd->int_coalescing_threshold) + enint_coal |= ENINT_COALESCE; + else if (ahd->cmdcmplt_total < ahd->int_coalescing_stop_threshold) + enint_coal &= ~ENINT_COALESCE; - if (enint_coal != (ahd->hs_mailbox & ENINT_COALESS)) { - ahd_enable_coalessing(ahd, enint_coal); + if (enint_coal != (ahd->hs_mailbox & ENINT_COALESCE)) { + ahd_enable_coalescing(ahd, enint_coal); #ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_INT_COALESSING) != 0) - printf("%s: Interrupt coalessing " + if ((ahd_debug & AHD_SHOW_INT_COALESCING) != 0) + printf("%s: Interrupt coalescing " "now %sabled. Cmds %d\n", ahd_name(ahd), - (enint_coal & ENINT_COALESS) ? "en" : "dis", + (enint_coal & ENINT_COALESCE) ? "en" : "dis", ahd->cmdcmplt_total); #endif } @@ -8279,8 +8180,6 @@ ahd_loadseq(struct ahd_softc *ahd) download_consts[PKT_OVERRUN_BUFOFFSET] = (ahd->overrun_buf - (uint8_t *)ahd->qoutfifo) / 256; download_consts[SCB_TRANSFER_SIZE] = SCB_TRANSFER_SIZE_1BYTE_LUN; - if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) - download_consts[SCB_TRANSFER_SIZE] = SCB_TRANSFER_SIZE_FULL_LUN; cur_patch = patches; downloaded = 0; skip_addr = 0; @@ -8509,7 +8408,7 @@ sized: } void -ahd_dump_all_cards_state() +ahd_dump_all_cards_state(void) { struct ahd_softc *list_ahd; @@ -9201,6 +9100,7 @@ ahd_handle_en_lun(struct ahd_softc *ahd, ahd->flags &= ~AHD_INITIATORROLE; ahd_pause(ahd); ahd_loadseq(ahd); + ahd_restart(ahd); ahd_unlock(ahd, &s); } cel = &ccb->cel; @@ -9434,6 +9334,11 @@ ahd_handle_en_lun(struct ahd_softc *ahd, ahd->flags |= AHD_INITIATORROLE; ahd_pause(ahd); ahd_loadseq(ahd); + ahd_restart(ahd); + /* + * Unpaused. The extra unpause + * that follows is harmless. + */ } } ahd_unpause(ahd); diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_inline.h linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_inline.h --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_inline.h 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_inline.h 2003-06-05 22:45:13.000000000 +0200 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#48 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#50 $ * * $FreeBSD$ */ @@ -271,11 +271,12 @@ ahd_setup_scb_common(struct ahd_softc *a scb->crc_retry_count = 0; if ((scb->flags & SCB_PACKETIZED) != 0) { /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */ - scb->hscb->task_attribute= scb->hscb->control & SCB_TAG_TYPE; - /* - * For Rev A short lun workaround. - */ - scb->hscb->pkt_long_lun[6] = scb->hscb->lun; + scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE; + } else { + if (ahd_get_transfer_length(scb) & 0x01) + scb->hscb->task_attribute = SCB_XFERLEN_ODD; + else + scb->hscb->task_attribute = 0; } if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_osm.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_osm.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_osm.c 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_osm.c 2003-06-05 22:45:13.000000000 +0200 @@ -1,7 +1,7 @@ /* * Adaptec AIC79xx device driver for Linux. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#160 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#169 $ * * -------------------------------------------------------------------------- * Copyright (c) 1994-2000 Justin T. Gibbs. @@ -62,11 +62,6 @@ #include /* For fetching system memory size */ -#define __KERNEL_SYSCALLS__ - -#include -static int errno; - /* * Lock protecting manipulation of the ahd softc list. */ @@ -755,34 +750,11 @@ ahd_linux_map_seg(struct ahd_softc *ahd, consumed = 1; sg->addr = ahd_htole32(addr & 0xFFFFFFFF); scb->platform_data->xfer_len += len; + if (sizeof(bus_addr_t) > 4 - && (ahd->flags & AHD_39BIT_ADDRESSING) != 0) { - /* - * Due to DAC restrictions, we can't - * cross a 4GB boundary. - */ - if ((addr ^ (addr + len - 1)) & 0xFFFFFFFF00000000ULL) { - struct ahd_dma_seg *next_sg; - uint32_t first_len; - uint32_t next_len; - - printf("Crossed Seg\n"); - if ((scb->sg_count + 2) > AHD_NSEG) - panic("Too few segs for dma mapping. " - "Increase AHD_NSEG\n"); - - consumed++; - next_sg = sg + 1; - next_sg->addr = 0; - first_len = 0x100000000ULL - (addr & 0xFFFFFFFF); - next_len = len - first_len; - len = next_len; - next_len |= - ((addr >> 8) + 0x1000000) & AHD_SG_HIGH_ADDR_MASK; - next_sg->len = ahd_htole32(next_len); - } + && (ahd->flags & AHD_39BIT_ADDRESSING) != 0) len |= (addr >> 8) & AHD_SG_HIGH_ADDR_MASK; - } + sg->len = ahd_htole32(len); return (consumed); } @@ -799,14 +771,18 @@ static int ahd_linux_queue(Scsi_Cmnd static int ahd_linux_slave_alloc(Scsi_Device *); static int ahd_linux_slave_configure(Scsi_Device *); static void ahd_linux_slave_destroy(Scsi_Device *); +#if defined(__i386__) static int ahd_linux_biosparam(struct scsi_device*, struct block_device*, sector_t, int[]); +#endif #else static int ahd_linux_release(struct Scsi_Host *); static void ahd_linux_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs); +#if defined(__i386__) static int ahd_linux_biosparam(Disk *, kdev_t, int[]); #endif +#endif static int ahd_linux_bus_reset(Scsi_Cmnd *); static int ahd_linux_dev_reset(Scsi_Cmnd *); static int ahd_linux_abort(Scsi_Cmnd *); @@ -1214,6 +1190,7 @@ ahd_linux_select_queue_depth(struct Scsi } #endif +#if defined(__i386__) /* * Return the disk geometry for the given SCSI device. */ @@ -1276,6 +1253,7 @@ ahd_linux_biosparam(Disk *disk, kdev_t d geom[2] = cylinders; return (0); } +#endif /* * Abort the current SCSI command(s). @@ -2201,7 +2179,7 @@ ahd_linux_register_host(struct ahd_softc } uint64_t -ahd_linux_get_memsize() +ahd_linux_get_memsize(void) { struct sysinfo si; @@ -2216,7 +2194,7 @@ ahd_linux_get_memsize() * scenario. */ static int -ahd_linux_next_unit() +ahd_linux_next_unit(void) { struct ahd_softc *ahd; int unit; @@ -2958,13 +2936,11 @@ ahd_linux_dv_transition(struct ahd_softc struct ahd_devinfo *devinfo, struct ahd_linux_target *targ) { - cam_status cam_status; u_int32_t status; - u_int scsi_status; - scsi_status = ahd_cmd_get_scsi_status(cmd); - cam_status = ahd_cmd_get_transaction_status(cmd); - status = aic_error_action(cmd, targ->inq_data, cam_status, scsi_status); + status = aic_error_action(cmd, targ->inq_data, + ahd_cmd_get_transaction_status(cmd), + ahd_cmd_get_scsi_status(cmd)); #ifdef AHD_DEBUG @@ -4214,7 +4190,7 @@ ahd_linux_run_device_queue(struct ahd_so /* * SCSI controller interrupt handler. */ -AIC_LINUX_IRQRETURN_T +irqreturn_t ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs) { struct ahd_softc *ahd; @@ -4228,7 +4204,7 @@ ahd_linux_isr(int irq, void *dev_id, str ahd_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_unlock(ahd, &flags); - AIC_LINUX_IRQRETURN(ours); + return IRQ_RETVAL(ours); } void @@ -4407,22 +4383,19 @@ ahd_send_async(struct ahd_softc *ahd, ch } case AC_SENT_BDR: { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + WARN_ON(lun != CAM_LUN_WILDCARD); + scsi_report_device_reset(ahd->platform_data->host, + channel - 'A', target); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) Scsi_Device *scsi_dev; /* * Find the SCSI device associated with this * request and indicate that a UA is expected. - * XXX This should really be handled by the mid-layer. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - list_for_each_entry(scsi_dev, - &ahd->platform_data->host->my_devices, - siblings) { -#else for (scsi_dev = ahd->platform_data->host->host_queue; scsi_dev != NULL; scsi_dev = scsi_dev->next) { -#endif if (channel - 'A' == scsi_dev->channel && target == scsi_dev->id && (lun == CAM_LUN_WILDCARD diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_osm.h linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_osm.h --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_osm.h 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_osm.h 2003-06-05 22:45:13.000000000 +0200 @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#130 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#135 $ * */ #ifndef _AIC79XX_LINUX_H_ @@ -246,7 +246,7 @@ int ahd_dmamap_unload(struct ahd_softc * typedef struct timer_list ahd_timer_t; /********************************** Includes **********************************/ -#if CONFIG_AIC79XX_REG_PRETTY_PRINT +#ifdef CONFIG_AIC79XX_REG_PRETTY_PRINT #define AIC_DEBUG_REGISTERS 1 #else #define AIC_DEBUG_REGISTERS 0 @@ -293,7 +293,7 @@ ahd_scb_timer_reset(struct scb *scb, u_i #define AHD_SCSI_HAS_HOST_LOCK 0 #endif -#define AIC79XX_DRIVER_VERSION "1.3.8" +#define AIC79XX_DRIVER_VERSION "1.3.10" /**************************** Front End Queues ********************************/ /* @@ -1006,7 +1006,12 @@ ahd_flush_device_writes(struct ahd_softc (((dev_softc)->dma_mask = mask) && 0) #endif /**************************** Proc FS Support *********************************/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) int ahd_linux_proc_info(char *, char **, off_t, int, int, int); +#else +int ahd_linux_proc_info(struct Scsi_Host *, char *, char **, + off_t, int, int); +#endif /*************************** Domain Validation ********************************/ #define AHD_DV_CMD(cmd) ((cmd)->scsi_done == ahd_linux_dv_complete) @@ -1211,7 +1216,7 @@ void ahd_platform_set_tags(struct ahd_so int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, int lun, u_int tag, role_t role, uint32_t status); -AIC_LINUX_IRQRETURN_T +irqreturn_t ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs); void ahd_platform_flushwork(struct ahd_softc *ahd); int ahd_softc_comp(struct ahd_softc *, struct ahd_softc *); diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_osm_pci.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_osm_pci.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_osm_pci.c 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_osm_pci.c 2003-06-05 22:45:13.000000000 +0200 @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#21 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#24 $ */ #include "aic79xx_osm.h" @@ -156,19 +156,21 @@ ahd_linux_pci_dev_probe(struct pci_dev * pci_set_master(pdev); if (sizeof(bus_addr_t) > 4) { - uint64_t memsize; + uint64_t memsize; + bus_addr_t mask_64bit; + bus_addr_t mask_39bit; memsize = ahd_linux_get_memsize(); - if (memsize >= 0x8000000000 - && ahd_pci_set_dma_mask(pdev, 0xFFFFFFFFFFFFFFFFULL) == 0) { + mask_64bit = (bus_addr_t)0xFFFFFFFFFFFFFFFFULL; + mask_39bit = (bus_addr_t)0x7FFFFFFFFFULL; + if (memsize >= 0x8000000000ULL + && ahd_pci_set_dma_mask(pdev, mask_64bit) == 0) { ahd->flags |= AHD_64BIT_ADDRESSING; - ahd->platform_data->hw_dma_mask = - (bus_addr_t)(0xFFFFFFFFFFFFFFFFULL&(bus_addr_t)~0); + ahd->platform_data->hw_dma_mask = mask_64bit; } else if (memsize > 0x80000000 - && ahd_pci_set_dma_mask(pdev, 0x7FFFFFFFFFULL) == 0) { + && ahd_pci_set_dma_mask(pdev, mask_39bit) == 0) { ahd->flags |= AHD_39BIT_ADDRESSING; - ahd->platform_data->hw_dma_mask = - (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0); + ahd->platform_data->hw_dma_mask = mask_39bit; } } else { ahd_pci_set_dma_mask(pdev, 0xFFFFFFFF); diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_pci.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_pci.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_pci.c 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_pci.c 2003-06-05 22:45:13.000000000 +0200 @@ -38,7 +38,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#71 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#75 $ * * $FreeBSD$ */ @@ -65,28 +65,29 @@ ahd_compose_id(u_int device, u_int vendo } #define ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull +#define ID_ALL_IROC_MASK 0xFFFFFF7FFFFFFFFFull #define ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull #define ID_9005_GENERIC_MASK 0xFFF0FFFF00000000ull +#define ID_9005_GENERIC_IROC_MASK 0xFFF0FF7F00000000ull #define ID_AIC7901 0x800F9005FFFF9005ull -#define ID_AIC7901A 0x801E9005FFFF9005ull -#define ID_AIC7901A_IROC 0x809E9005FFFF9005ull #define ID_AHA_29320A 0x8000900500609005ull +#define ID_AHA_29320ALP 0x8017900500449005ull + +#define ID_AIC7901A 0x801E9005FFFF9005ull +#define ID_AHA_29320 0x8012900500429005ull +#define ID_AHA_29320B 0x8013900500439005ull #define ID_AHA_29320LP 0x8014900500449005ull -#define ID_AHA_29320LP_IROC 0x8094900500449005ull #define ID_AIC7902 0x801F9005FFFF9005ull -#define ID_AIC7902_IROC 0x809F9005FFFF9005ull #define ID_AIC7902_B 0x801D9005FFFF9005ull -#define ID_AIC7902_B_IROC 0x809D9005FFFF9005ull #define ID_AHA_39320 0x8010900500409005ull +#define ID_AHA_39320_B 0x8015900500409005ull #define ID_AHA_39320A 0x8016900500409005ull #define ID_AHA_39320D 0x8011900500419005ull #define ID_AHA_39320D_B 0x801C900500419005ull #define ID_AHA_39320D_HP 0x8011900500AC0E11ull #define ID_AHA_39320D_B_HP 0x801C900500AC0E11ull -#define ID_AHA_29320 0x8012900500429005ull -#define ID_AHA_29320B 0x8013900500439005ull #define ID_AIC7902_PCI_REV_A4 0x3 #define ID_AIC7902_PCI_REV_B0 0x10 #define SUBID_HP 0x0E11 @@ -113,22 +114,42 @@ ahd_compose_id(u_int device, u_int vendo #define SUBID_9005_SEEPTYPE_NONE 0x0 #define SUBID_9005_SEEPTYPE_4K 0x1 +static ahd_device_setup_t ahd_aic7901_setup; static ahd_device_setup_t ahd_aic7901A_setup; static ahd_device_setup_t ahd_aic7902_setup; struct ahd_pci_identity ahd_pci_ident_table [] = { + /* aic7901 based controllers */ + { + ID_AHA_29320A, + ID_ALL_MASK, + "Adaptec 29320A Ultra320 SCSI adapter", + ahd_aic7901_setup + }, + { + ID_AHA_29320ALP, + ID_ALL_MASK, + "Adaptec 29320ALP Ultra320 SCSI adapter", + ahd_aic7901_setup + }, /* aic7901A based controllers */ { - ID_AHA_29320LP, + ID_AHA_29320, ID_ALL_MASK, - "Adaptec 29320LP Ultra320 SCSI adapter", + "Adaptec 29320 Ultra320 SCSI adapter", ahd_aic7901A_setup }, { - ID_AHA_29320A, + ID_AHA_29320B, ID_ALL_MASK, - "Adaptec 29320A Ultra320 SCSI adapter", + "Adaptec 29320B Ultra320 SCSI adapter", + ahd_aic7901A_setup + }, + { + ID_AHA_29320LP, + ID_ALL_MASK, + "Adaptec 29320LP Ultra320 SCSI adapter", ahd_aic7901A_setup }, /* aic7902 based controllers */ @@ -139,6 +160,12 @@ struct ahd_pci_identity ahd_pci_ident_ta ahd_aic7902_setup }, { + ID_AHA_39320_B, + ID_ALL_MASK, + "Adaptec 39320 Ultra320 SCSI adapter", + ahd_aic7902_setup + }, + { ID_AHA_39320A, ID_ALL_MASK, "Adaptec 39320A Ultra320 SCSI adapter", @@ -182,6 +209,12 @@ struct ahd_pci_identity ahd_pci_ident_ta }, /* Generic chip probes for devices we don't know 'exactly' */ { + ID_AIC7901 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec AIC7901 Ultra320 SCSI adapter", + ahd_aic7901_setup + }, + { ID_AIC7901A & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, "Adaptec AIC7901A Ultra320 SCSI adapter", @@ -332,9 +365,9 @@ ahd_pci_config(struct ahd_softc *ahd, st } /* Ensure busmastering is enabled */ - command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/1); + command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); command |= PCIM_CMD_BUSMASTEREN; - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/1); + ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/2); error = ahd_softc_init(ahd); if (error != 0) @@ -342,7 +375,7 @@ ahd_pci_config(struct ahd_softc *ahd, st ahd->bus_intr = ahd_pci_intr; - error = ahd_reset(ahd); + error = ahd_reset(ahd, /*reinit*/FALSE); if (error != 0) return (ENXIO); @@ -385,9 +418,11 @@ ahd_pci_config(struct ahd_softc *ahd, st int ahd_pci_test_register_access(struct ahd_softc *ahd) { - uint32_t cmd; - int error; - uint8_t hcntrl; + uint32_t cmd; + u_int targpcistat; + u_int pci_status1; + int error; + uint8_t hcntrl; error = EIO; @@ -421,6 +456,18 @@ ahd_pci_test_register_access(struct ahd_ ahd_outb(ahd, HCNTRL, hcntrl|PAUSE); while (ahd_is_paused(ahd) == 0) ; + + /* Clear any PCI errors that occurred before our driver attached. */ + ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); + targpcistat = ahd_inb(ahd, TARGPCISTAT); + ahd_outb(ahd, TARGPCISTAT, targpcistat); + pci_status1 = ahd_pci_read_config(ahd->dev_softc, + PCIR_STATUS + 1, /*bytes*/1); + ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1, + pci_status1, /*bytes*/1); + ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); + ahd_outb(ahd, CLRINT, CLRPCIINT); + ahd_outb(ahd, SEQCTL0, PERRORDIS); ahd_outl(ahd, SRAM_BASE, 0x5aa555aa); if (ahd_inl(ahd, SRAM_BASE) != 0x5aa555aa) @@ -439,8 +486,6 @@ ahd_pci_test_register_access(struct ahd_ fail: if ((ahd_inb(ahd, INTSTAT) & PCIINT) != 0) { - u_int targpcistat; - u_int pci_status1; ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG); targpcistat = ahd_inb(ahd, TARGPCISTAT); @@ -453,7 +498,6 @@ fail: pci_status1, /*bytes*/1); ahd_outb(ahd, CLRINT, CLRPCIINT); } - ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS); ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2); return (error); @@ -868,6 +912,18 @@ ahd_pci_split_intr(struct ahd_softc *ahd } static int +ahd_aic7901_setup(struct ahd_softc *ahd) +{ + int error; + + error = ahd_aic7902_setup(ahd); + if (error != 0) + return (error); + ahd->chip = AHD_AIC7901; + return (0); +} + +static int ahd_aic7901A_setup(struct ahd_softc *ahd) { int error; @@ -890,7 +946,7 @@ ahd_aic7902_setup(struct ahd_softc *ahd) if (rev < ID_AIC7902_PCI_REV_A4) { printf("%s: Unable to attach to unsupported chip revision %d\n", ahd_name(ahd), rev); - ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/1); + ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/2); return (ENXIO); } ahd->channel = ahd_get_pci_function(pci) + 'A'; diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_proc.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_proc.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_proc.c 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_proc.c 2003-06-05 22:45:13.000000000 +0200 @@ -37,7 +37,7 @@ * String handling code courtesy of Gerard Roudier's * sym driver. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#17 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#19 $ */ #include "aic79xx_osm.h" #include "aic79xx_inline.h" @@ -278,8 +278,13 @@ done: * Return information to handle /proc support for the driver. */ int +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ahd_linux_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout) + int length, int hostno, int inout) +#else +ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, + off_t offset, int length, int inout) +#endif { struct ahd_softc *ahd; struct info_str info; @@ -291,10 +296,14 @@ ahd_linux_proc_info(char *buffer, char * retval = -EINVAL; ahd_list_lock(&l); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) TAILQ_FOREACH(ahd, &ahd_tailq, links) { if (ahd->platform_data->host->host_no == hostno) break; } +#else + ahd = ahd_find_softc(*(struct ahd_softc **)shost->hostdata); +#endif if (ahd == NULL) goto done; diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_reg.h linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_reg.h --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_reg.h 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_reg.h 2003-06-05 22:45:13.000000000 +0200 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $ */ typedef int (ahd_reg_print_t)(u_int, u_int *, u_int); typedef struct ahd_reg_parse_entry { @@ -2134,24 +2134,24 @@ ahd_reg_print_t ahd_allocfifo_scbptr_pri #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_int_coalessing_timer_print; +ahd_reg_print_t ahd_int_coalescing_timer_print; #else -#define ahd_int_coalessing_timer_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INT_COALESSING_TIMER", 0x14a, regvalue, cur_col, wrap) +#define ahd_int_coalescing_timer_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "INT_COALESCING_TIMER", 0x14a, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_int_coalessing_maxcmds_print; +ahd_reg_print_t ahd_int_coalescing_maxcmds_print; #else -#define ahd_int_coalessing_maxcmds_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INT_COALESSING_MAXCMDS", 0x14c, regvalue, cur_col, wrap) +#define ahd_int_coalescing_maxcmds_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS", 0x14c, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_int_coalessing_mincmds_print; +ahd_reg_print_t ahd_int_coalescing_mincmds_print; #else -#define ahd_int_coalessing_mincmds_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INT_COALESSING_MINCMDS", 0x14d, regvalue, cur_col, wrap) +#define ahd_int_coalescing_mincmds_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS", 0x14d, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS @@ -2162,10 +2162,10 @@ ahd_reg_print_t ahd_cmds_pending_print; #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_int_coalessing_cmdcount_print; +ahd_reg_print_t ahd_int_coalescing_cmdcount_print; #else -#define ahd_int_coalessing_cmdcount_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INT_COALESSING_CMDCOUNT", 0x150, regvalue, cur_col, wrap) +#define ahd_int_coalescing_cmdcount_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT", 0x150, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS @@ -2239,94 +2239,94 @@ ahd_reg_print_t ahd_scb_sense_busaddr_pr #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_dataptr_print; +ahd_reg_print_t ahd_scb_tag_print; #else -#define ahd_scb_dataptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_DATAPTR", 0x190, regvalue, cur_col, wrap) +#define ahd_scb_tag_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_TAG", 0x190, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_datacnt_print; +ahd_reg_print_t ahd_scb_control_print; #else -#define ahd_scb_datacnt_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_DATACNT", 0x198, regvalue, cur_col, wrap) +#define ahd_scb_control_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_CONTROL", 0x192, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_sgptr_print; +ahd_reg_print_t ahd_scb_scsiid_print; #else -#define ahd_scb_sgptr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_SGPTR", 0x19c, regvalue, cur_col, wrap) +#define ahd_scb_scsiid_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_SCSIID", 0x193, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_busaddr_print; +ahd_reg_print_t ahd_scb_lun_print; #else -#define ahd_scb_busaddr_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_BUSADDR", 0x1a0, regvalue, cur_col, wrap) +#define ahd_scb_lun_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_LUN", 0x194, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_next_print; +ahd_reg_print_t ahd_scb_task_attribute_print; #else -#define ahd_scb_next_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_NEXT", 0x1a4, regvalue, cur_col, wrap) +#define ahd_scb_task_attribute_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_TASK_ATTRIBUTE", 0x195, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_next2_print; +ahd_reg_print_t ahd_scb_cdb_len_print; #else -#define ahd_scb_next2_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_NEXT2", 0x1a6, regvalue, cur_col, wrap) +#define ahd_scb_cdb_len_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_CDB_LEN", 0x196, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_control_print; +ahd_reg_print_t ahd_scb_task_management_print; #else -#define ahd_scb_control_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_CONTROL", 0x1a8, regvalue, cur_col, wrap) +#define ahd_scb_task_management_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_TASK_MANAGEMENT", 0x197, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_scsiid_print; +ahd_reg_print_t ahd_scb_dataptr_print; #else -#define ahd_scb_scsiid_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_SCSIID", 0x1a9, regvalue, cur_col, wrap) +#define ahd_scb_dataptr_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_DATAPTR", 0x198, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_lun_print; +ahd_reg_print_t ahd_scb_datacnt_print; #else -#define ahd_scb_lun_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_LUN", 0x1aa, regvalue, cur_col, wrap) +#define ahd_scb_datacnt_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_DATACNT", 0x1a0, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_task_attribute_print; +ahd_reg_print_t ahd_scb_sgptr_print; #else -#define ahd_scb_task_attribute_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_TASK_ATTRIBUTE", 0x1ab, regvalue, cur_col, wrap) +#define ahd_scb_sgptr_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_SGPTR", 0x1a4, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_cdb_len_print; +ahd_reg_print_t ahd_scb_busaddr_print; #else -#define ahd_scb_cdb_len_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_CDB_LEN", 0x1ac, regvalue, cur_col, wrap) +#define ahd_scb_busaddr_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_BUSADDR", 0x1a8, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_task_management_print; +ahd_reg_print_t ahd_scb_next_print; #else -#define ahd_scb_task_management_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_TASK_MANAGEMENT", 0x1ad, regvalue, cur_col, wrap) +#define ahd_scb_next_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_NEXT", 0x1ac, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_scb_tag_print; +ahd_reg_print_t ahd_scb_next2_print; #else -#define ahd_scb_tag_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "SCB_TAG", 0x1ae, regvalue, cur_col, wrap) +#define ahd_scb_next2_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "SCB_NEXT2", 0x1ae, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS @@ -2432,7 +2432,7 @@ ahd_reg_print_t ahd_scb_disconnected_lis #define HS_MAILBOX 0x0b #define HOST_TQINPOS 0x80 -#define ENINT_COALESS 0x40 +#define ENINT_COALESCE 0x40 #define CLRSEQINTSTAT 0x0c #define CLRSEQ_SWTMRTO 0x10 @@ -2557,6 +2557,8 @@ ahd_reg_print_t ahd_scb_disconnected_lis #define SHORTTHRESH 0x2f #define LUNLEN 0x30 +#define TLUNLEN 0xf0 +#define ILUNLEN 0x0f #define CDBLIMIT 0x31 @@ -3612,15 +3614,15 @@ ahd_reg_print_t ahd_scb_disconnected_lis #define ALLOCFIFO_SCBPTR 0x148 -#define INT_COALESSING_TIMER 0x14a +#define INT_COALESCING_TIMER 0x14a -#define INT_COALESSING_MAXCMDS 0x14c +#define INT_COALESCING_MAXCMDS 0x14c -#define INT_COALESSING_MINCMDS 0x14d +#define INT_COALESCING_MINCMDS 0x14d #define CMDS_PENDING 0x14e -#define INT_COALESSING_CMDCOUNT 0x150 +#define INT_COALESCING_CMDCOUNT 0x150 #define LOCAL_HS_MAILBOX 0x151 @@ -3648,25 +3650,10 @@ ahd_reg_print_t ahd_scb_disconnected_lis #define SCB_SENSE_BUSADDR 0x18c #define SCB_NEXT_COMPLETE 0x18c -#define SCB_DATAPTR 0x190 - -#define SCB_DATACNT 0x198 -#define SG_LAST_SEG 0x80 -#define SG_HIGH_ADDR_BITS 0x7f - -#define SCB_SGPTR 0x19c -#define SG_STATUS_VALID 0x04 -#define SG_FULL_RESID 0x02 -#define SG_LIST_NULL 0x01 +#define SCB_TAG 0x190 +#define SCB_FIFO_USE_COUNT 0x190 -#define SCB_BUSADDR 0x1a0 - -#define SCB_NEXT 0x1a4 -#define SCB_NEXT_SCB_BUSADDR 0x1a4 - -#define SCB_NEXT2 0x1a6 - -#define SCB_CONTROL 0x1a8 +#define SCB_CONTROL 0x192 #define TARGET_SCB 0x80 #define DISCENB 0x40 #define TAG_ENB 0x20 @@ -3675,22 +3662,38 @@ ahd_reg_print_t ahd_scb_disconnected_lis #define DISCONNECTED 0x04 #define SCB_TAG_TYPE 0x03 -#define SCB_SCSIID 0x1a9 +#define SCB_SCSIID 0x193 #define TID 0xf0 #define OID 0x0f -#define SCB_LUN 0x1aa +#define SCB_LUN 0x194 #define LID 0xff -#define SCB_TASK_ATTRIBUTE 0x1ab +#define SCB_TASK_ATTRIBUTE 0x195 +#define SCB_XFERLEN_ODD 0x01 -#define SCB_CDB_LEN 0x1ac +#define SCB_CDB_LEN 0x196 #define SCB_CDB_LEN_PTR 0x80 -#define SCB_TASK_MANAGEMENT 0x1ad +#define SCB_TASK_MANAGEMENT 0x197 + +#define SCB_DATAPTR 0x198 + +#define SCB_DATACNT 0x1a0 +#define SG_LAST_SEG 0x80 +#define SG_HIGH_ADDR_BITS 0x7f + +#define SCB_SGPTR 0x1a4 +#define SG_STATUS_VALID 0x04 +#define SG_FULL_RESID 0x02 +#define SG_LIST_NULL 0x01 + +#define SCB_BUSADDR 0x1a8 + +#define SCB_NEXT 0x1ac +#define SCB_NEXT_SCB_BUSADDR 0x1ac -#define SCB_TAG 0x1ae -#define SCB_FIFO_USE_COUNT 0x1ae +#define SCB_NEXT2 0x1ae #define SCB_SPARE 0x1b0 #define SCB_PKT_LUN 0x1b0 @@ -3719,6 +3722,7 @@ ahd_reg_print_t ahd_scb_disconnected_lis #define AHD_PRECOMP_CUTBACK_29 0x06 #define AHD_NUM_PER_DEV_ANNEXCOLS 0x04 #define B_CURRFIFO_0 0x02 +#define LUNLEN_SINGLE_LEVEL_LUN 0x0f #define NVRAM_SCB_OFFSET 0x2c #define AHD_TIMER_MAX_US 0x18ffe7 #define AHD_TIMER_MAX_TICKS 0xffff @@ -3768,5 +3772,5 @@ ahd_reg_print_t ahd_scb_disconnected_lis /* Exported Labels */ -#define LABEL_seq_isr 0x270 -#define LABEL_timer_isr 0x26c +#define LABEL_seq_isr 0x269 +#define LABEL_timer_isr 0x265 diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_reg_print.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_reg_print.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_reg_print.c 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_reg_print.c 2003-06-05 22:45:13.000000000 +0200 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $ */ #include "aic79xx_osm.h" @@ -161,7 +161,7 @@ ahd_hescb_qoff_print(u_int regvalue, u_i } static ahd_reg_parse_entry_t HS_MAILBOX_parse_table[] = { - { "ENINT_COALESS", 0x40, 0x40 }, + { "ENINT_COALESCE", 0x40, 0x40 }, { "HOST_TQINPOS", 0x80, 0x80 } }; @@ -489,10 +489,15 @@ ahd_shortthresh_print(u_int regvalue, u_ 0x2f, regvalue, cur_col, wrap)); } +static ahd_reg_parse_entry_t LUNLEN_parse_table[] = { + { "ILUNLEN", 0x0f, 0x0f }, + { "TLUNLEN", 0xf0, 0xf0 } +}; + int ahd_lunlen_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "LUNLEN", + return (ahd_print_register(LUNLEN_parse_table, 2, "LUNLEN", 0x30, regvalue, cur_col, wrap)); } @@ -3375,23 +3380,23 @@ ahd_allocfifo_scbptr_print(u_int regvalu } int -ahd_int_coalessing_timer_print(u_int regvalue, u_int *cur_col, u_int wrap) +ahd_int_coalescing_timer_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "INT_COALESSING_TIMER", + return (ahd_print_register(NULL, 0, "INT_COALESCING_TIMER", 0x14a, regvalue, cur_col, wrap)); } int -ahd_int_coalessing_maxcmds_print(u_int regvalue, u_int *cur_col, u_int wrap) +ahd_int_coalescing_maxcmds_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "INT_COALESSING_MAXCMDS", + return (ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS", 0x14c, regvalue, cur_col, wrap)); } int -ahd_int_coalessing_mincmds_print(u_int regvalue, u_int *cur_col, u_int wrap) +ahd_int_coalescing_mincmds_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "INT_COALESSING_MINCMDS", + return (ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS", 0x14d, regvalue, cur_col, wrap)); } @@ -3403,9 +3408,9 @@ ahd_cmds_pending_print(u_int regvalue, u } int -ahd_int_coalessing_cmdcount_print(u_int regvalue, u_int *cur_col, u_int wrap) +ahd_int_coalescing_cmdcount_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "INT_COALESSING_CMDCOUNT", + return (ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT", 0x150, regvalue, cur_col, wrap)); } @@ -3486,58 +3491,12 @@ ahd_scb_sense_busaddr_print(u_int regval } int -ahd_scb_dataptr_print(u_int regvalue, u_int *cur_col, u_int wrap) +ahd_scb_tag_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "SCB_DATAPTR", + return (ahd_print_register(NULL, 0, "SCB_TAG", 0x190, regvalue, cur_col, wrap)); } -static ahd_reg_parse_entry_t SCB_DATACNT_parse_table[] = { - { "SG_HIGH_ADDR_BITS", 0x7f, 0x7f }, - { "SG_LAST_SEG", 0x80, 0x80 } -}; - -int -ahd_scb_datacnt_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SCB_DATACNT_parse_table, 2, "SCB_DATACNT", - 0x198, regvalue, cur_col, wrap)); -} - -static ahd_reg_parse_entry_t SCB_SGPTR_parse_table[] = { - { "SG_LIST_NULL", 0x01, 0x01 }, - { "SG_FULL_RESID", 0x02, 0x02 }, - { "SG_STATUS_VALID", 0x04, 0x04 } -}; - -int -ahd_scb_sgptr_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(SCB_SGPTR_parse_table, 3, "SCB_SGPTR", - 0x19c, regvalue, cur_col, wrap)); -} - -int -ahd_scb_busaddr_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "SCB_BUSADDR", - 0x1a0, regvalue, cur_col, wrap)); -} - -int -ahd_scb_next_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "SCB_NEXT", - 0x1a4, regvalue, cur_col, wrap)); -} - -int -ahd_scb_next2_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahd_print_register(NULL, 0, "SCB_NEXT2", - 0x1a6, regvalue, cur_col, wrap)); -} - static ahd_reg_parse_entry_t SCB_CONTROL_parse_table[] = { { "SCB_TAG_TYPE", 0x03, 0x03 }, { "DISCONNECTED", 0x04, 0x04 }, @@ -3552,7 +3511,7 @@ int ahd_scb_control_print(u_int regvalue, u_int *cur_col, u_int wrap) { return (ahd_print_register(SCB_CONTROL_parse_table, 7, "SCB_CONTROL", - 0x1a8, regvalue, cur_col, wrap)); + 0x192, regvalue, cur_col, wrap)); } static ahd_reg_parse_entry_t SCB_SCSIID_parse_table[] = { @@ -3564,7 +3523,7 @@ int ahd_scb_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap) { return (ahd_print_register(SCB_SCSIID_parse_table, 2, "SCB_SCSIID", - 0x1a9, regvalue, cur_col, wrap)); + 0x193, regvalue, cur_col, wrap)); } static ahd_reg_parse_entry_t SCB_LUN_parse_table[] = { @@ -3575,14 +3534,18 @@ int ahd_scb_lun_print(u_int regvalue, u_int *cur_col, u_int wrap) { return (ahd_print_register(SCB_LUN_parse_table, 1, "SCB_LUN", - 0x1aa, regvalue, cur_col, wrap)); + 0x194, regvalue, cur_col, wrap)); } +static ahd_reg_parse_entry_t SCB_TASK_ATTRIBUTE_parse_table[] = { + { "SCB_XFERLEN_ODD", 0x01, 0x01 } +}; + int ahd_scb_task_attribute_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "SCB_TASK_ATTRIBUTE", - 0x1ab, regvalue, cur_col, wrap)); + return (ahd_print_register(SCB_TASK_ATTRIBUTE_parse_table, 1, "SCB_TASK_ATTRIBUTE", + 0x195, regvalue, cur_col, wrap)); } static ahd_reg_parse_entry_t SCB_CDB_LEN_parse_table[] = { @@ -3593,20 +3556,66 @@ int ahd_scb_cdb_len_print(u_int regvalue, u_int *cur_col, u_int wrap) { return (ahd_print_register(SCB_CDB_LEN_parse_table, 1, "SCB_CDB_LEN", - 0x1ac, regvalue, cur_col, wrap)); + 0x196, regvalue, cur_col, wrap)); } int ahd_scb_task_management_print(u_int regvalue, u_int *cur_col, u_int wrap) { return (ahd_print_register(NULL, 0, "SCB_TASK_MANAGEMENT", - 0x1ad, regvalue, cur_col, wrap)); + 0x197, regvalue, cur_col, wrap)); } int -ahd_scb_tag_print(u_int regvalue, u_int *cur_col, u_int wrap) +ahd_scb_dataptr_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "SCB_TAG", + return (ahd_print_register(NULL, 0, "SCB_DATAPTR", + 0x198, regvalue, cur_col, wrap)); +} + +static ahd_reg_parse_entry_t SCB_DATACNT_parse_table[] = { + { "SG_HIGH_ADDR_BITS", 0x7f, 0x7f }, + { "SG_LAST_SEG", 0x80, 0x80 } +}; + +int +ahd_scb_datacnt_print(u_int regvalue, u_int *cur_col, u_int wrap) +{ + return (ahd_print_register(SCB_DATACNT_parse_table, 2, "SCB_DATACNT", + 0x1a0, regvalue, cur_col, wrap)); +} + +static ahd_reg_parse_entry_t SCB_SGPTR_parse_table[] = { + { "SG_LIST_NULL", 0x01, 0x01 }, + { "SG_FULL_RESID", 0x02, 0x02 }, + { "SG_STATUS_VALID", 0x04, 0x04 } +}; + +int +ahd_scb_sgptr_print(u_int regvalue, u_int *cur_col, u_int wrap) +{ + return (ahd_print_register(SCB_SGPTR_parse_table, 3, "SCB_SGPTR", + 0x1a4, regvalue, cur_col, wrap)); +} + +int +ahd_scb_busaddr_print(u_int regvalue, u_int *cur_col, u_int wrap) +{ + return (ahd_print_register(NULL, 0, "SCB_BUSADDR", + 0x1a8, regvalue, cur_col, wrap)); +} + +int +ahd_scb_next_print(u_int regvalue, u_int *cur_col, u_int wrap) +{ + return (ahd_print_register(NULL, 0, "SCB_NEXT", + 0x1ac, regvalue, cur_col, wrap)); +} + +int +ahd_scb_next2_print(u_int regvalue, u_int *cur_col, u_int wrap) +{ + return (ahd_print_register(NULL, 0, "SCB_NEXT2", 0x1ae, regvalue, cur_col, wrap)); } diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_seq.h linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_seq.h --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic79xx_seq.h 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic79xx_seq.h 2003-06-05 22:45:13.000000000 +0200 @@ -2,30 +2,30 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $ */ static uint8_t seqprog[] = { 0xff, 0x02, 0x06, 0x78, - 0x00, 0xea, 0x4e, 0x59, + 0x00, 0xea, 0x50, 0x59, 0x01, 0xea, 0x04, 0x30, 0xff, 0x04, 0x0c, 0x78, - 0x19, 0xea, 0x4e, 0x59, + 0x19, 0xea, 0x50, 0x59, 0x19, 0xea, 0x04, 0x00, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x60, 0x3a, 0x1a, 0x68, 0x04, 0x47, 0x1b, 0x68, 0xff, 0x21, 0x1b, 0x70, - 0x40, 0x4b, 0x90, 0x69, - 0x00, 0xe2, 0x52, 0x59, - 0x40, 0x4b, 0x90, 0x69, - 0x20, 0x4b, 0x80, 0x69, + 0x40, 0x4b, 0x92, 0x69, + 0x00, 0xe2, 0x54, 0x59, + 0x40, 0x4b, 0x92, 0x69, + 0x20, 0x4b, 0x82, 0x69, 0xfc, 0x42, 0x24, 0x78, 0x10, 0x40, 0x24, 0x78, - 0x00, 0xe2, 0xd2, 0x5d, + 0x00, 0xe2, 0xc4, 0x5d, 0x20, 0x4d, 0x28, 0x78, - 0x00, 0xe2, 0xd2, 0x5d, + 0x00, 0xe2, 0xc4, 0x5d, 0x30, 0x3f, 0xc0, 0x09, 0x30, 0xe0, 0x30, 0x60, 0x7f, 0x4a, 0x94, 0x08, @@ -35,34 +35,34 @@ static uint8_t seqprog[] = { 0x00, 0xe2, 0x56, 0x58, 0x00, 0xe2, 0x66, 0x58, 0x00, 0xe2, 0x06, 0x40, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x01, 0x52, 0x64, 0x78, 0x02, 0x58, 0x50, 0x31, 0xff, 0xea, 0x10, 0x0b, - 0xff, 0xad, 0x4f, 0x78, + 0xff, 0x97, 0x4f, 0x78, 0x50, 0x4b, 0x4a, 0x68, 0xbf, 0x3a, 0x74, 0x08, - 0x14, 0xea, 0x4e, 0x59, + 0x14, 0xea, 0x50, 0x59, 0x14, 0xea, 0x04, 0x00, - 0x08, 0xa8, 0x51, 0x03, - 0xff, 0xae, 0x3f, 0x68, - 0x00, 0xe2, 0x50, 0x5b, + 0x08, 0x92, 0x25, 0x03, + 0xff, 0x90, 0x3f, 0x68, + 0x00, 0xe2, 0x56, 0x5b, 0x00, 0xe2, 0x3e, 0x40, - 0x00, 0xea, 0x42, 0x59, + 0x00, 0xea, 0x44, 0x59, 0x01, 0xea, 0x00, 0x30, 0x80, 0xf9, 0x5e, 0x68, - 0x00, 0xe2, 0x40, 0x59, - 0x11, 0xea, 0x42, 0x59, + 0x00, 0xe2, 0x42, 0x59, + 0x11, 0xea, 0x44, 0x59, 0x11, 0xea, 0x00, 0x00, - 0x80, 0xf9, 0x40, 0x79, + 0x80, 0xf9, 0x42, 0x79, 0xff, 0xea, 0xd4, 0x0d, - 0x22, 0xea, 0x42, 0x59, + 0x22, 0xea, 0x44, 0x59, 0x22, 0xea, 0x00, 0x00, 0x10, 0x16, 0x70, 0x78, 0x01, 0x0b, 0xa2, 0x32, 0x10, 0x16, 0x2c, 0x00, - 0x18, 0xad, 0xfe, 0x78, + 0x18, 0xad, 0x00, 0x79, 0x04, 0xad, 0xca, 0x68, 0x80, 0xad, 0x64, 0x78, 0x10, 0xad, 0x98, 0x78, @@ -71,15 +71,15 @@ static uint8_t seqprog[] = { 0x02, 0x8c, 0x59, 0x32, 0x02, 0x28, 0x19, 0x33, 0x02, 0xa8, 0x50, 0x36, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x40, 0x3a, 0x64, 0x68, 0x50, 0x4b, 0x64, 0x68, - 0x22, 0xea, 0x42, 0x59, + 0x22, 0xea, 0x44, 0x59, 0x22, 0xea, 0x00, 0x00, 0xe7, 0xad, 0x5a, 0x09, 0x02, 0x8c, 0x59, 0x32, - 0x1a, 0xea, 0x4e, 0x59, + 0x1a, 0xea, 0x50, 0x59, 0x1a, 0xea, 0x04, 0x00, 0xff, 0xea, 0xd4, 0x0d, 0xe7, 0xad, 0x5a, 0x09, @@ -113,29 +113,30 @@ static uint8_t seqprog[] = { 0xff, 0xea, 0xc0, 0x09, 0x01, 0x4e, 0x9d, 0x1a, 0x00, 0x4f, 0x9f, 0x22, - 0x01, 0xea, 0x5c, 0x33, - 0x04, 0xa4, 0x49, 0x32, - 0xff, 0xea, 0x4a, 0x03, - 0xff, 0xea, 0x4e, 0x03, + 0x01, 0x94, 0x6d, 0x33, + 0x01, 0xea, 0x20, 0x33, + 0x04, 0xac, 0x49, 0x32, + 0xff, 0xea, 0x5a, 0x03, + 0xff, 0xea, 0x5e, 0x03, 0x01, 0x10, 0xd4, 0x31, - 0x10, 0xa8, 0xf3, 0x68, - 0x3d, 0xa9, 0xc5, 0x29, + 0x10, 0x92, 0xf5, 0x68, + 0x3d, 0x93, 0xc5, 0x29, 0xfe, 0xe2, 0xc4, 0x09, 0x01, 0xea, 0xc6, 0x01, 0x02, 0xe2, 0xc8, 0x31, 0x02, 0xec, 0x50, 0x31, 0x02, 0xa0, 0xda, 0x31, - 0xff, 0xa9, 0xf2, 0x70, - 0x02, 0xa0, 0x48, 0x37, - 0xff, 0x21, 0xfb, 0x70, + 0xff, 0xa9, 0xf4, 0x70, + 0x02, 0xa0, 0x58, 0x37, + 0xff, 0x21, 0xfd, 0x70, 0x02, 0x22, 0x51, 0x31, - 0x02, 0xa0, 0x4c, 0x33, + 0x02, 0xa0, 0x5c, 0x33, 0x02, 0xa0, 0x44, 0x36, 0x02, 0xa0, 0x40, 0x32, 0x02, 0xa0, 0x44, 0x36, - 0x04, 0x47, 0x03, 0x69, - 0x40, 0x16, 0x2e, 0x69, - 0xff, 0x2d, 0x33, 0x61, + 0x04, 0x47, 0x05, 0x69, + 0x40, 0x16, 0x30, 0x69, + 0xff, 0x2d, 0x35, 0x61, 0xff, 0x29, 0x65, 0x70, 0x01, 0x37, 0xc1, 0x31, 0x02, 0x28, 0x55, 0x32, @@ -148,20 +149,20 @@ static uint8_t seqprog[] = { 0x01, 0x50, 0xa1, 0x1a, 0xff, 0x4e, 0x9d, 0x1a, 0xff, 0x4f, 0x9f, 0x22, - 0xff, 0x8d, 0x27, 0x71, - 0x80, 0xac, 0x26, 0x71, - 0x20, 0x16, 0x26, 0x69, + 0xff, 0x8d, 0x29, 0x71, + 0x80, 0xac, 0x28, 0x71, + 0x20, 0x16, 0x28, 0x69, 0x02, 0x8c, 0x51, 0x31, - 0x00, 0xe2, 0x10, 0x41, + 0x00, 0xe2, 0x12, 0x41, 0x01, 0xac, 0x08, 0x31, 0x09, 0xea, 0x5a, 0x01, 0x02, 0x8c, 0x51, 0x32, 0xff, 0xea, 0x1a, 0x07, 0x04, 0x24, 0xf9, 0x30, - 0x1d, 0xea, 0x38, 0x41, + 0x1d, 0xea, 0x3a, 0x41, 0x02, 0x2c, 0x51, 0x31, - 0x04, 0xa0, 0xf9, 0x30, - 0x19, 0xea, 0x38, 0x41, + 0x04, 0xa8, 0xf9, 0x30, + 0x19, 0xea, 0x3a, 0x41, 0x06, 0xea, 0x08, 0x81, 0x01, 0xe2, 0x5a, 0x35, 0x02, 0xf2, 0xf0, 0x35, @@ -178,24 +179,24 @@ static uint8_t seqprog[] = { 0x02, 0x20, 0xbd, 0x30, 0x02, 0x20, 0xb9, 0x30, 0x02, 0x20, 0x51, 0x31, - 0x4c, 0xa9, 0xd7, 0x28, - 0x10, 0xa8, 0x61, 0x79, + 0x4c, 0x93, 0xd7, 0x28, + 0x10, 0x92, 0x63, 0x79, 0x01, 0x6b, 0xc0, 0x30, 0x02, 0x64, 0xc8, 0x00, 0x40, 0x3a, 0x74, 0x04, 0x00, 0xe2, 0x56, 0x58, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x30, 0x3f, 0xc0, 0x09, - 0x30, 0xe0, 0x62, 0x61, - 0x20, 0x3f, 0x78, 0x69, - 0x10, 0x3f, 0x62, 0x79, + 0x30, 0xe0, 0x64, 0x61, + 0x20, 0x3f, 0x7a, 0x69, + 0x10, 0x3f, 0x64, 0x79, 0x02, 0xea, 0x7e, 0x00, - 0x00, 0xea, 0x42, 0x59, + 0x00, 0xea, 0x44, 0x59, 0x01, 0xea, 0x00, 0x30, 0x02, 0x48, 0x51, 0x35, 0x01, 0xea, 0x7e, 0x00, - 0x11, 0xea, 0x42, 0x59, + 0x11, 0xea, 0x44, 0x59, 0x11, 0xea, 0x00, 0x00, 0x02, 0x48, 0x51, 0x35, 0x08, 0xea, 0x98, 0x00, @@ -205,11 +206,11 @@ static uint8_t seqprog[] = { 0x0f, 0x67, 0xc0, 0x09, 0x00, 0x34, 0x69, 0x02, 0x20, 0xea, 0x96, 0x00, - 0x00, 0xe2, 0xf6, 0x41, - 0x40, 0x3a, 0xac, 0x69, + 0x00, 0xe2, 0xf8, 0x41, + 0x40, 0x3a, 0xae, 0x69, 0x02, 0x55, 0x06, 0x68, - 0x02, 0x56, 0xac, 0x69, - 0xff, 0x5b, 0xac, 0x61, + 0x02, 0x56, 0xae, 0x69, + 0xff, 0x5b, 0xae, 0x61, 0x02, 0x20, 0x51, 0x31, 0x80, 0xea, 0xb2, 0x01, 0x44, 0xea, 0x00, 0x00, @@ -217,144 +218,146 @@ static uint8_t seqprog[] = { 0x33, 0xea, 0x00, 0x00, 0xff, 0xea, 0xb2, 0x09, 0xff, 0xe0, 0xc0, 0x19, - 0xff, 0xe0, 0xae, 0x79, - 0x02, 0xa4, 0x51, 0x31, - 0x00, 0xe2, 0xa4, 0x41, + 0xff, 0xe0, 0xb0, 0x79, + 0x02, 0xac, 0x51, 0x31, + 0x00, 0xe2, 0xa6, 0x41, 0x02, 0x5e, 0x50, 0x31, 0x02, 0xa8, 0xb8, 0x30, 0x02, 0x5c, 0x50, 0x31, - 0xff, 0xa5, 0xbf, 0x71, - 0x02, 0xa4, 0x41, 0x31, + 0xff, 0xad, 0xc1, 0x71, + 0x02, 0xac, 0x41, 0x31, 0x02, 0x22, 0x51, 0x31, - 0x02, 0xa0, 0x4c, 0x33, + 0x02, 0xa0, 0x5c, 0x33, 0x02, 0xa0, 0x44, 0x32, - 0x00, 0xe2, 0xc8, 0x41, - 0x10, 0xa8, 0xc9, 0x69, - 0x3d, 0xa9, 0xc9, 0x29, + 0x00, 0xe2, 0xca, 0x41, + 0x10, 0x92, 0xcb, 0x69, + 0x3d, 0x93, 0xc9, 0x29, 0x01, 0xe4, 0xc8, 0x01, 0x01, 0xea, 0xca, 0x01, 0xff, 0xea, 0xda, 0x01, 0x02, 0x20, 0x51, 0x31, - 0x02, 0xa6, 0x41, 0x32, - 0xff, 0x21, 0xd1, 0x61, + 0x02, 0xae, 0x41, 0x32, + 0xff, 0x21, 0xd3, 0x61, 0xff, 0xea, 0x46, 0x02, 0x02, 0x5c, 0x50, 0x31, 0x40, 0xea, 0x96, 0x00, - 0x02, 0x56, 0xda, 0x6d, - 0x01, 0x55, 0xda, 0x6d, - 0x10, 0xa8, 0xdd, 0x79, - 0x10, 0x40, 0xe6, 0x69, - 0x01, 0x56, 0xe6, 0x79, - 0xff, 0xad, 0x07, 0x78, - 0x13, 0xea, 0x4e, 0x59, + 0x02, 0x56, 0xcc, 0x6d, + 0x01, 0x55, 0xcc, 0x6d, + 0x10, 0x92, 0xdf, 0x79, + 0x10, 0x40, 0xe8, 0x69, + 0x01, 0x56, 0xe8, 0x79, + 0xff, 0x97, 0x07, 0x78, + 0x13, 0xea, 0x50, 0x59, 0x13, 0xea, 0x04, 0x00, 0x00, 0xe2, 0x06, 0x40, 0xbf, 0x3a, 0x74, 0x08, 0x08, 0xea, 0x98, 0x00, 0x08, 0x57, 0xae, 0x00, - 0x01, 0xa9, 0x69, 0x32, - 0x01, 0xaa, 0x6b, 0x32, + 0x01, 0x93, 0x69, 0x32, + 0x01, 0x94, 0x6b, 0x32, 0x40, 0xea, 0x66, 0x02, 0x08, 0x3c, 0x78, 0x00, 0x80, 0xea, 0x62, 0x02, - 0x00, 0xe2, 0xb2, 0x5b, + 0x00, 0xe2, 0xb8, 0x5b, 0x01, 0x36, 0xc1, 0x31, - 0x9f, 0xe0, 0x54, 0x7c, - 0x80, 0xe0, 0x0a, 0x72, - 0xa0, 0xe0, 0x42, 0x72, - 0xc0, 0xe0, 0x38, 0x72, - 0xe0, 0xe0, 0x72, 0x72, - 0x01, 0xea, 0x4e, 0x59, + 0x9f, 0xe0, 0x4c, 0x7c, + 0x80, 0xe0, 0x0c, 0x72, + 0xa0, 0xe0, 0x44, 0x72, + 0xc0, 0xe0, 0x3a, 0x72, + 0xe0, 0xe0, 0x74, 0x72, + 0x01, 0xea, 0x50, 0x59, 0x01, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf6, 0x41, - 0x80, 0x33, 0x11, 0x7a, - 0x03, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0x80, 0x33, 0x13, 0x7a, + 0x03, 0xea, 0x50, 0x59, 0x03, 0xea, 0x04, 0x00, - 0xee, 0x00, 0x18, 0x6a, + 0xee, 0x00, 0x1a, 0x6a, 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x02, 0xa8, 0x90, 0x32, - 0x00, 0xe2, 0x68, 0x59, - 0xef, 0xac, 0xd5, 0x19, - 0x00, 0xe2, 0x28, 0x52, + 0x00, 0xe2, 0x6a, 0x59, + 0xef, 0x96, 0xd5, 0x19, + 0x00, 0xe2, 0x2a, 0x52, 0x09, 0x80, 0xe1, 0x30, 0x02, 0xea, 0x36, 0x00, 0xa8, 0xea, 0x32, 0x00, - 0x00, 0xe2, 0x2e, 0x42, - 0x01, 0xac, 0xd1, 0x30, + 0x00, 0xe2, 0x30, 0x42, + 0x01, 0x96, 0xd1, 0x30, 0x10, 0x80, 0x89, 0x31, 0x20, 0xea, 0x32, 0x00, 0xbf, 0x33, 0x67, 0x0a, - 0x20, 0x19, 0x30, 0x6a, - 0x02, 0x4d, 0xf6, 0x69, + 0x20, 0x19, 0x32, 0x6a, + 0x02, 0x4d, 0xf8, 0x69, 0x40, 0x33, 0x67, 0x02, - 0x00, 0xe2, 0xf6, 0x41, - 0x80, 0x33, 0xaf, 0x6a, + 0x00, 0xe2, 0xf8, 0x41, + 0x80, 0x33, 0xb5, 0x6a, 0x01, 0x44, 0x10, 0x33, - 0x08, 0xa8, 0x51, 0x03, - 0x00, 0xe2, 0xf6, 0x41, + 0x08, 0x92, 0x25, 0x03, + 0x00, 0xe2, 0xf8, 0x41, 0x10, 0xea, 0x80, 0x00, 0x01, 0x31, 0xc5, 0x31, - 0x80, 0xe2, 0x5e, 0x62, - 0x10, 0xa8, 0x83, 0x6a, - 0xc0, 0xaa, 0xc5, 0x01, - 0x40, 0xa8, 0x4f, 0x6a, + 0x80, 0xe2, 0x60, 0x62, + 0x10, 0x92, 0x85, 0x6a, + 0xc0, 0x94, 0xc5, 0x01, + 0x40, 0x92, 0x51, 0x6a, 0xbf, 0xe2, 0xc4, 0x09, - 0x20, 0xa8, 0x63, 0x7a, + 0x20, 0x92, 0x65, 0x7a, 0x01, 0xe2, 0x88, 0x30, - 0x00, 0xe2, 0xb2, 0x5b, - 0xa0, 0x36, 0x6b, 0x62, - 0x23, 0xa8, 0x89, 0x08, - 0x00, 0xe2, 0xb2, 0x5b, - 0xa0, 0x36, 0x6b, 0x62, - 0x00, 0xa8, 0x62, 0x42, - 0xff, 0xe2, 0x62, 0x62, - 0x00, 0xe2, 0x82, 0x42, + 0x00, 0xe2, 0xb8, 0x5b, + 0xa0, 0x36, 0x6d, 0x62, + 0x23, 0x92, 0x89, 0x08, + 0x00, 0xe2, 0xb8, 0x5b, + 0xa0, 0x36, 0x6d, 0x62, + 0x00, 0xa8, 0x64, 0x42, + 0xff, 0xe2, 0x64, 0x62, + 0x00, 0xe2, 0x84, 0x42, 0x40, 0xea, 0x98, 0x00, 0x01, 0xe2, 0x88, 0x30, - 0x00, 0xe2, 0xb2, 0x5b, - 0xa0, 0x36, 0x41, 0x72, + 0x00, 0xe2, 0xb8, 0x5b, + 0xa0, 0x36, 0x43, 0x72, 0x40, 0xea, 0x98, 0x00, 0x01, 0x31, 0x89, 0x32, 0x08, 0xea, 0x62, 0x02, - 0x00, 0xe2, 0xf6, 0x41, - 0xe0, 0xea, 0xce, 0x5b, - 0x80, 0xe0, 0xba, 0x6a, - 0x04, 0xe0, 0x60, 0x73, - 0x02, 0xe0, 0x90, 0x73, - 0x00, 0xea, 0x18, 0x73, - 0x03, 0xe0, 0xa0, 0x73, - 0x23, 0xe0, 0x94, 0x72, - 0x08, 0xe0, 0xb6, 0x72, - 0x00, 0xe2, 0xb2, 0x5b, - 0x07, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0xe0, 0xea, 0xd4, 0x5b, + 0x80, 0xe0, 0xc0, 0x6a, + 0x04, 0xe0, 0x66, 0x73, + 0x02, 0xe0, 0x96, 0x73, + 0x00, 0xea, 0x1e, 0x73, + 0x03, 0xe0, 0xa6, 0x73, + 0x23, 0xe0, 0x96, 0x72, + 0x08, 0xe0, 0xbc, 0x72, + 0x00, 0xe2, 0xb8, 0x5b, + 0x07, 0xea, 0x50, 0x59, 0x07, 0xea, 0x04, 0x00, - 0x08, 0x42, 0xf7, 0x71, - 0x04, 0x42, 0x91, 0x62, + 0x08, 0x42, 0xf9, 0x71, + 0x04, 0x42, 0x93, 0x62, 0x01, 0x43, 0x89, 0x30, - 0x00, 0xe2, 0x82, 0x42, + 0x00, 0xe2, 0x84, 0x42, 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0x82, 0x42, + 0x00, 0xe2, 0x84, 0x42, 0x01, 0x00, 0x60, 0x32, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x4c, 0x34, 0xc1, 0x28, 0x01, 0x64, 0xc0, 0x31, - 0x00, 0x30, 0x43, 0x59, + 0x00, 0x30, 0x45, 0x59, 0x01, 0x30, 0x01, 0x30, - 0x01, 0xe0, 0xb4, 0x7a, - 0xa0, 0xea, 0xc4, 0x5b, - 0x01, 0xa0, 0xb4, 0x62, - 0x01, 0x84, 0xad, 0x7a, - 0x01, 0xa7, 0xb6, 0x7a, - 0x00, 0xe2, 0xb6, 0x42, - 0x03, 0xea, 0x4e, 0x59, + 0x01, 0xe0, 0xba, 0x7a, + 0xa0, 0xea, 0xca, 0x5b, + 0x01, 0xa0, 0xba, 0x62, + 0x01, 0x84, 0xaf, 0x7a, + 0x01, 0x95, 0xbd, 0x6a, + 0x05, 0xea, 0x50, 0x59, + 0x05, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0xbc, 0x42, + 0x03, 0xea, 0x50, 0x59, 0x03, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xb6, 0x42, - 0x07, 0xea, 0xd6, 0x5b, + 0x00, 0xe2, 0xbc, 0x42, + 0x07, 0xea, 0xdc, 0x5b, 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0xf6, 0x41, + 0x00, 0xe2, 0xf8, 0x41, 0x3f, 0xe0, 0x6a, 0x0a, 0xc0, 0x34, 0xc1, 0x09, 0x00, 0x35, 0x51, 0x01, @@ -365,54 +368,54 @@ static uint8_t seqprog[] = { 0x01, 0xea, 0xc6, 0x01, 0x02, 0xe2, 0xc8, 0x31, 0x02, 0xec, 0x40, 0x31, - 0xff, 0xa1, 0xd6, 0x72, + 0xff, 0xa1, 0xdc, 0x72, 0x02, 0xe8, 0xda, 0x31, 0x02, 0xa0, 0x50, 0x31, - 0x00, 0xe2, 0xf8, 0x42, + 0x00, 0xe2, 0xfe, 0x42, 0x80, 0x33, 0x67, 0x02, 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0xb2, 0x5b, + 0x00, 0xe2, 0xb8, 0x5b, 0x01, 0x33, 0x67, 0x02, - 0xe0, 0x36, 0x13, 0x63, + 0xe0, 0x36, 0x19, 0x63, 0x02, 0x33, 0x67, 0x02, - 0x20, 0x46, 0x0c, 0x63, + 0x20, 0x46, 0x12, 0x63, 0xff, 0xea, 0x52, 0x09, - 0xa8, 0xea, 0xc4, 0x5b, - 0x04, 0xa8, 0xf3, 0x7a, + 0xa8, 0xea, 0xca, 0x5b, + 0x04, 0x92, 0xf9, 0x7a, 0x01, 0x34, 0xc1, 0x31, - 0x00, 0xa9, 0xf3, 0x62, + 0x00, 0x93, 0xf9, 0x62, 0x01, 0x35, 0xc1, 0x31, - 0x00, 0xaa, 0xfd, 0x72, + 0x00, 0x94, 0x03, 0x73, 0x01, 0xa9, 0x52, 0x11, - 0xff, 0xa9, 0xe8, 0x6a, - 0x00, 0xe2, 0x0c, 0x43, + 0xff, 0xa9, 0xee, 0x6a, + 0x00, 0xe2, 0x12, 0x43, 0x10, 0x33, 0x67, 0x02, - 0x04, 0xa8, 0x0d, 0x7b, - 0xfb, 0xa8, 0x51, 0x0b, + 0x04, 0x92, 0x13, 0x7b, + 0xfb, 0x92, 0x25, 0x0b, 0xff, 0xea, 0x66, 0x0a, - 0x01, 0x9c, 0x07, 0x6b, + 0x01, 0xa4, 0x0d, 0x6b, 0x02, 0xa8, 0x90, 0x32, - 0x00, 0xe2, 0x68, 0x59, - 0x10, 0xa8, 0xb7, 0x7a, - 0xff, 0xea, 0xd6, 0x5b, - 0x00, 0xe2, 0xb6, 0x42, - 0x04, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0x6a, 0x59, + 0x10, 0x92, 0xbd, 0x7a, + 0xff, 0xea, 0xdc, 0x5b, + 0x00, 0xe2, 0xbc, 0x42, + 0x04, 0xea, 0x50, 0x59, 0x04, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xb6, 0x42, - 0x04, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0xbc, 0x42, + 0x04, 0xea, 0x50, 0x59, 0x04, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf6, 0x41, - 0x08, 0xa8, 0xaf, 0x7a, - 0xc0, 0x33, 0x23, 0x7b, - 0x80, 0x33, 0xaf, 0x6a, - 0xff, 0x88, 0x23, 0x6b, - 0x40, 0x33, 0xaf, 0x6a, - 0x10, 0xa8, 0x29, 0x7b, - 0x0a, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0x08, 0x92, 0xb5, 0x7a, + 0xc0, 0x33, 0x29, 0x7b, + 0x80, 0x33, 0xb5, 0x6a, + 0xff, 0x88, 0x29, 0x6b, + 0x40, 0x33, 0xb5, 0x6a, + 0x10, 0x92, 0x2f, 0x7b, + 0x0a, 0xea, 0x50, 0x59, 0x0a, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x48, 0x5b, - 0x00, 0xe2, 0x7c, 0x43, - 0x50, 0x4b, 0x30, 0x6b, + 0x00, 0xe2, 0x4e, 0x5b, + 0x00, 0xe2, 0x82, 0x43, + 0x50, 0x4b, 0x36, 0x6b, 0xbf, 0x3a, 0x74, 0x08, 0x01, 0xe0, 0xf4, 0x31, 0xff, 0xea, 0xc0, 0x09, @@ -422,25 +425,25 @@ static uint8_t seqprog[] = { 0x01, 0xfa, 0xc0, 0x35, 0x02, 0xa8, 0x84, 0x32, 0x02, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x02, 0x42, 0x51, 0x31, - 0xff, 0xae, 0x65, 0x68, - 0xff, 0x88, 0x55, 0x6b, - 0x01, 0x9c, 0x51, 0x6b, - 0x02, 0x9c, 0x59, 0x6b, - 0x01, 0x84, 0x59, 0x7b, + 0xff, 0x90, 0x65, 0x68, + 0xff, 0x88, 0x5b, 0x6b, + 0x01, 0xa4, 0x57, 0x6b, + 0x02, 0xa4, 0x5f, 0x6b, + 0x01, 0x84, 0x5f, 0x7b, 0x02, 0x28, 0x19, 0x33, 0x02, 0xa8, 0x50, 0x36, - 0xff, 0x88, 0x59, 0x73, - 0x00, 0xe2, 0x2c, 0x5b, - 0x02, 0xa8, 0x5c, 0x33, + 0xff, 0x88, 0x5f, 0x73, + 0x00, 0xe2, 0x32, 0x5b, + 0x02, 0xa8, 0x20, 0x33, 0x02, 0x2c, 0x19, 0x33, 0x02, 0xa8, 0x58, 0x32, - 0x04, 0x9c, 0x39, 0x07, - 0xc0, 0x33, 0xaf, 0x6a, - 0x04, 0xa8, 0x51, 0x03, - 0x20, 0xa8, 0x7d, 0x6b, + 0x04, 0xa4, 0x49, 0x07, + 0xc0, 0x33, 0xb5, 0x6a, + 0x04, 0x92, 0x25, 0x03, + 0x20, 0x92, 0x83, 0x6b, 0x02, 0xa8, 0x40, 0x31, 0xc0, 0x34, 0xc1, 0x09, 0x00, 0x35, 0x51, 0x01, @@ -455,56 +458,56 @@ static uint8_t seqprog[] = { 0xf7, 0x57, 0xae, 0x08, 0x08, 0xea, 0x98, 0x00, 0x01, 0x44, 0xd4, 0x31, - 0xee, 0x00, 0x86, 0x6b, + 0xee, 0x00, 0x8c, 0x6b, 0x02, 0xea, 0xb4, 0x00, - 0x00, 0xe2, 0xae, 0x5b, - 0x09, 0x4c, 0x88, 0x7b, + 0x00, 0xe2, 0xb4, 0x5b, + 0x09, 0x4c, 0x8e, 0x7b, 0x08, 0x4c, 0x06, 0x68, - 0x0b, 0xea, 0x4e, 0x59, + 0x0b, 0xea, 0x50, 0x59, 0x0b, 0xea, 0x04, 0x00, 0x01, 0x44, 0xd4, 0x31, - 0x20, 0x33, 0xf7, 0x79, - 0x00, 0xe2, 0x98, 0x5b, - 0x00, 0xe2, 0xf6, 0x41, - 0x01, 0x84, 0x9d, 0x7b, - 0x01, 0x9c, 0x39, 0x07, - 0x08, 0x60, 0x20, 0x33, - 0x08, 0x80, 0x31, 0x37, + 0x20, 0x33, 0xf9, 0x79, + 0x00, 0xe2, 0x9e, 0x5b, + 0x00, 0xe2, 0xf8, 0x41, + 0x01, 0x84, 0xa3, 0x7b, + 0x01, 0xa4, 0x49, 0x07, + 0x08, 0x60, 0x30, 0x33, + 0x08, 0x80, 0x41, 0x37, 0xdf, 0x33, 0x67, 0x0a, - 0xee, 0x00, 0xaa, 0x6b, + 0xee, 0x00, 0xb0, 0x6b, 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, - 0x00, 0xe2, 0x68, 0x59, - 0x00, 0xe2, 0xb6, 0x42, + 0x00, 0xe2, 0x6a, 0x59, + 0x00, 0xe2, 0xbc, 0x42, 0x01, 0xea, 0x6c, 0x02, 0xc0, 0xea, 0x66, 0x06, - 0xff, 0x42, 0xbe, 0x6b, - 0x01, 0x41, 0xb2, 0x6b, - 0x02, 0x41, 0xb2, 0x7b, - 0xff, 0x42, 0xbe, 0x6b, - 0x01, 0x41, 0xb2, 0x6b, - 0x02, 0x41, 0xb2, 0x7b, - 0xff, 0x42, 0xbe, 0x7b, - 0x04, 0x4c, 0xb2, 0x6b, + 0xff, 0x42, 0xc4, 0x6b, + 0x01, 0x41, 0xb8, 0x6b, + 0x02, 0x41, 0xb8, 0x7b, + 0xff, 0x42, 0xc4, 0x6b, + 0x01, 0x41, 0xb8, 0x6b, + 0x02, 0x41, 0xb8, 0x7b, + 0xff, 0x42, 0xc4, 0x7b, + 0x04, 0x4c, 0xb8, 0x6b, 0xe0, 0x41, 0x6c, 0x0e, 0x01, 0x44, 0xd4, 0x31, - 0xff, 0x42, 0xc6, 0x7b, - 0x04, 0x4c, 0xc6, 0x6b, + 0xff, 0x42, 0xcc, 0x7b, + 0x04, 0x4c, 0xcc, 0x6b, 0xe0, 0x41, 0x6c, 0x0a, - 0xe0, 0x36, 0xf7, 0x61, + 0xe0, 0x36, 0xf9, 0x61, 0xff, 0xea, 0xca, 0x09, 0x01, 0xe2, 0xc8, 0x31, 0x01, 0x46, 0xda, 0x35, 0x01, 0x44, 0xd4, 0x35, 0x10, 0xea, 0x80, 0x00, 0x01, 0xe2, 0x62, 0x36, - 0x04, 0xa6, 0xde, 0x7b, + 0x04, 0xa6, 0xe4, 0x7b, 0xff, 0xea, 0x5a, 0x09, 0xff, 0xea, 0x4c, 0x0d, - 0x01, 0xa6, 0xfc, 0x6b, + 0x01, 0xa6, 0x02, 0x6c, 0x10, 0xad, 0x64, 0x78, - 0x80, 0xad, 0xf4, 0x6b, + 0x80, 0xad, 0xfa, 0x6b, 0x08, 0xad, 0x64, 0x68, 0x04, 0x84, 0xf9, 0x30, 0x00, 0xea, 0x08, 0x81, @@ -521,8 +524,6 @@ static uint8_t seqprog[] = { 0x08, 0xb0, 0xe0, 0x30, 0x04, 0xb0, 0xe0, 0x30, 0x03, 0xb0, 0xf0, 0x30, - 0x01, 0x78, 0x0a, 0x7c, - 0x01, 0xa7, 0x4e, 0x11, 0x01, 0xb0, 0x06, 0x33, 0x7f, 0x83, 0xe9, 0x08, 0x04, 0xac, 0x58, 0x19, @@ -532,9 +533,7 @@ static uint8_t seqprog[] = { 0x00, 0x86, 0x0d, 0x23, 0x00, 0x87, 0x0f, 0x23, 0x01, 0x84, 0xc5, 0x31, - 0x01, 0xa7, 0x20, 0x7c, - 0x04, 0xe2, 0xc4, 0x01, - 0x80, 0x83, 0x27, 0x7c, + 0x80, 0x83, 0x25, 0x7c, 0x02, 0xe2, 0xc4, 0x01, 0xff, 0xea, 0x4c, 0x09, 0x01, 0xe2, 0x36, 0x30, @@ -543,87 +542,81 @@ static uint8_t seqprog[] = { 0x01, 0xac, 0xd4, 0x99, 0x00, 0xe2, 0x64, 0x50, 0xfe, 0xa6, 0x4c, 0x0d, - 0x0b, 0x90, 0xe1, 0x30, - 0x01, 0x98, 0x4f, 0x09, - 0xfd, 0x9c, 0x49, 0x09, - 0x80, 0x9b, 0x3d, 0x7c, + 0x0b, 0x98, 0xe1, 0x30, + 0xfd, 0xa4, 0x49, 0x09, + 0x80, 0xa3, 0x39, 0x7c, 0x02, 0xa4, 0x48, 0x01, - 0x01, 0xa7, 0x40, 0x7c, - 0x04, 0xa4, 0x48, 0x01, 0x01, 0xa4, 0x36, 0x30, 0xa8, 0xea, 0x32, 0x00, - 0xfd, 0x9c, 0x39, 0x0b, - 0x05, 0x9b, 0x07, 0x33, - 0x80, 0x83, 0x4d, 0x6c, + 0xfd, 0xa4, 0x49, 0x0b, + 0x05, 0xa3, 0x07, 0x33, + 0x80, 0x83, 0x45, 0x6c, 0x02, 0xea, 0x4c, 0x05, 0xff, 0xea, 0x4c, 0x0d, - 0x00, 0xe2, 0x3c, 0x59, - 0x02, 0xa6, 0xe0, 0x6b, + 0x00, 0xe2, 0x3e, 0x59, + 0x02, 0xa6, 0xe6, 0x6b, 0x80, 0xf9, 0xf2, 0x05, - 0xc0, 0x33, 0x5b, 0x7c, - 0x03, 0xea, 0x4e, 0x59, + 0xc0, 0x33, 0x53, 0x7c, + 0x03, 0xea, 0x50, 0x59, 0x03, 0xea, 0x04, 0x00, - 0x20, 0x33, 0x7f, 0x7c, - 0x01, 0x84, 0x65, 0x6c, - 0x06, 0xea, 0x4e, 0x59, + 0x20, 0x33, 0x77, 0x7c, + 0x01, 0x84, 0x5d, 0x6c, + 0x06, 0xea, 0x50, 0x59, 0x06, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x82, 0x44, + 0x00, 0xe2, 0x7a, 0x44, 0x01, 0x00, 0x60, 0x32, - 0xee, 0x00, 0x6e, 0x6c, + 0xee, 0x00, 0x66, 0x6c, 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x80, 0x3d, 0x7a, 0x00, - 0xfc, 0x42, 0x70, 0x7c, + 0xfc, 0x42, 0x68, 0x7c, 0x7f, 0x3d, 0x7a, 0x08, - 0x00, 0x30, 0x43, 0x59, + 0x00, 0x30, 0x45, 0x59, 0x01, 0x30, 0x01, 0x30, - 0x09, 0xea, 0x4e, 0x59, + 0x09, 0xea, 0x50, 0x59, 0x09, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf6, 0x41, - 0x01, 0x9c, 0x65, 0x6c, - 0x00, 0xe2, 0x32, 0x5c, + 0x00, 0xe2, 0xf8, 0x41, + 0x01, 0xa4, 0x5d, 0x6c, + 0x00, 0xe2, 0x30, 0x5c, 0x20, 0x33, 0x67, 0x02, 0x01, 0x00, 0x60, 0x32, - 0x02, 0xa6, 0x8a, 0x7c, - 0x00, 0xe2, 0x4e, 0x5c, + 0x02, 0xa6, 0x82, 0x7c, + 0x00, 0xe2, 0x46, 0x5c, 0x00, 0xe2, 0x56, 0x58, 0x00, 0xe2, 0x66, 0x58, 0x00, 0xe2, 0x3a, 0x58, - 0x00, 0x30, 0x43, 0x59, + 0x00, 0x30, 0x45, 0x59, 0x01, 0x30, 0x01, 0x30, - 0x20, 0x19, 0x8a, 0x6c, - 0x00, 0xe2, 0xba, 0x5c, - 0x04, 0x19, 0xa4, 0x6c, + 0x20, 0x19, 0x82, 0x6c, + 0x00, 0xe2, 0xb2, 0x5c, + 0x04, 0x19, 0x9c, 0x6c, 0x02, 0x19, 0x32, 0x00, - 0x01, 0x84, 0xa5, 0x7c, - 0x01, 0x1b, 0x9e, 0x7c, - 0x01, 0x1a, 0xa4, 0x6c, - 0x00, 0xe2, 0x54, 0x44, - 0x80, 0x4b, 0xaa, 0x6c, - 0x01, 0x4c, 0xa6, 0x7c, - 0x03, 0x42, 0x54, 0x6c, - 0x00, 0xe2, 0xda, 0x5b, + 0x01, 0x84, 0x9d, 0x7c, + 0x01, 0x1b, 0x96, 0x7c, + 0x01, 0x1a, 0x9c, 0x6c, + 0x00, 0xe2, 0x4c, 0x44, + 0x80, 0x4b, 0xa2, 0x6c, + 0x01, 0x4c, 0x9e, 0x7c, + 0x03, 0x42, 0x4c, 0x6c, + 0x00, 0xe2, 0xe0, 0x5b, 0x80, 0xf9, 0xf2, 0x01, - 0x04, 0x33, 0xf7, 0x79, - 0x00, 0xe2, 0xf6, 0x41, - 0x08, 0x5d, 0xc2, 0x6c, + 0x04, 0x33, 0xf9, 0x79, + 0x00, 0xe2, 0xf8, 0x41, + 0x08, 0x5d, 0xba, 0x6c, 0x00, 0xe2, 0x56, 0x58, - 0x00, 0x30, 0x43, 0x59, + 0x00, 0x30, 0x45, 0x59, 0x01, 0x30, 0x01, 0x30, - 0x02, 0x1b, 0xb2, 0x7c, - 0x08, 0x5d, 0xc0, 0x7c, + 0x02, 0x1b, 0xaa, 0x7c, + 0x08, 0x5d, 0xb8, 0x7c, 0x03, 0x68, 0x00, 0x37, 0x01, 0x84, 0x09, 0x07, - 0x80, 0x1b, 0xcc, 0x7c, - 0x80, 0x84, 0xcd, 0x6c, + 0x80, 0x1b, 0xc4, 0x7c, + 0x80, 0x84, 0xc5, 0x6c, 0xff, 0x85, 0x0b, 0x1b, 0xff, 0x86, 0x0d, 0x23, 0xff, 0x87, 0x0f, 0x23, 0xf8, 0x1b, 0x08, 0x0b, - 0xff, 0xea, 0x4e, 0x09, - 0x04, 0x1b, 0xd4, 0x7c, - 0x01, 0xa7, 0x4e, 0x01, 0xff, 0xea, 0x06, 0x0b, 0x03, 0x68, 0x00, 0x37, 0x00, 0xe2, 0xc4, 0x58, @@ -631,161 +624,161 @@ static uint8_t seqprog[] = { 0xf9, 0xd9, 0xb2, 0x0d, 0x01, 0xd9, 0xb2, 0x05, 0x01, 0x52, 0x48, 0x31, - 0x20, 0xa4, 0xfc, 0x7c, - 0x20, 0x5b, 0xfc, 0x7c, - 0x80, 0xf9, 0x0a, 0x7d, + 0x20, 0xa4, 0xee, 0x7c, + 0x20, 0x5b, 0xee, 0x7c, + 0x80, 0xf9, 0xfc, 0x7c, 0x02, 0xea, 0xb4, 0x00, 0x11, 0x00, 0x00, 0x10, - 0x04, 0x19, 0x16, 0x7d, + 0x04, 0x19, 0x08, 0x7d, 0xdf, 0x19, 0x32, 0x08, - 0x60, 0x5b, 0xf4, 0x6c, - 0x01, 0x4c, 0xf0, 0x7c, + 0x60, 0x5b, 0xe6, 0x6c, + 0x01, 0x4c, 0xe2, 0x7c, 0x20, 0x19, 0x32, 0x00, 0x01, 0xd9, 0xb2, 0x05, 0x02, 0xea, 0xb4, 0x00, 0x01, 0xd9, 0xb2, 0x05, - 0x10, 0x5b, 0x0e, 0x6d, - 0x08, 0x5b, 0x18, 0x6d, - 0x20, 0x5b, 0x08, 0x6d, - 0x02, 0x5b, 0x38, 0x6d, - 0x0e, 0xea, 0x4e, 0x59, + 0x10, 0x5b, 0x00, 0x6d, + 0x08, 0x5b, 0x0a, 0x6d, + 0x20, 0x5b, 0xfa, 0x6c, + 0x02, 0x5b, 0x2a, 0x6d, + 0x0e, 0xea, 0x50, 0x59, 0x0e, 0xea, 0x04, 0x00, - 0x80, 0xf9, 0xf8, 0x6c, + 0x80, 0xf9, 0xea, 0x6c, 0xdf, 0x5c, 0xb8, 0x08, 0x01, 0xd9, 0xb2, 0x05, - 0x01, 0x9c, 0xf3, 0x6d, - 0x00, 0xe2, 0x32, 0x5c, - 0x00, 0xe2, 0x42, 0x5d, - 0x01, 0xae, 0x5d, 0x1b, + 0x01, 0xa4, 0xe5, 0x6d, + 0x00, 0xe2, 0x30, 0x5c, + 0x00, 0xe2, 0x34, 0x5d, + 0x01, 0x90, 0x21, 0x1b, 0x01, 0xd9, 0xb2, 0x05, - 0x00, 0xe2, 0x2c, 0x5b, - 0xf3, 0xac, 0xd5, 0x19, - 0x00, 0xe2, 0x26, 0x55, - 0x80, 0xac, 0x27, 0x6d, - 0x0f, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0x32, 0x5b, + 0xf3, 0x96, 0xd5, 0x19, + 0x00, 0xe2, 0x18, 0x55, + 0x80, 0x96, 0x19, 0x6d, + 0x0f, 0xea, 0x50, 0x59, 0x0f, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x2e, 0x45, + 0x00, 0xe2, 0x20, 0x45, 0x04, 0x8c, 0xe1, 0x30, 0x01, 0xea, 0xf2, 0x00, 0x02, 0xea, 0x36, 0x00, 0xa8, 0xea, 0x32, 0x00, - 0xff, 0xad, 0x35, 0x7d, - 0x14, 0xea, 0x4e, 0x59, + 0xff, 0x97, 0x27, 0x7d, + 0x14, 0xea, 0x50, 0x59, 0x14, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xa4, 0x5d, + 0x00, 0xe2, 0x96, 0x5d, 0x01, 0xd9, 0xb2, 0x05, 0x09, 0x80, 0xe1, 0x30, 0x02, 0xea, 0x36, 0x00, 0xa8, 0xea, 0x32, 0x00, - 0x00, 0xe2, 0x9c, 0x5d, + 0x00, 0xe2, 0x8e, 0x5d, 0x01, 0xd9, 0xb2, 0x05, - 0x02, 0xa6, 0x52, 0x7d, - 0x00, 0xe2, 0x3c, 0x59, - 0x20, 0x5b, 0x60, 0x6d, - 0xfc, 0x42, 0x4c, 0x7d, - 0x10, 0x40, 0x4e, 0x6d, - 0x20, 0x4d, 0x50, 0x7d, - 0x08, 0x5d, 0x60, 0x6d, - 0x02, 0xa6, 0xe0, 0x6b, - 0x00, 0xe2, 0x3c, 0x59, - 0x20, 0x5b, 0x60, 0x6d, - 0x01, 0x1b, 0x80, 0x6d, - 0xfc, 0x42, 0x5c, 0x7d, - 0x10, 0x40, 0x5e, 0x6d, + 0x02, 0xa6, 0x44, 0x7d, + 0x00, 0xe2, 0x3e, 0x59, + 0x20, 0x5b, 0x52, 0x6d, + 0xfc, 0x42, 0x3e, 0x7d, + 0x10, 0x40, 0x40, 0x6d, + 0x20, 0x4d, 0x42, 0x7d, + 0x08, 0x5d, 0x52, 0x6d, + 0x02, 0xa6, 0xe6, 0x6b, + 0x00, 0xe2, 0x3e, 0x59, + 0x20, 0x5b, 0x52, 0x6d, + 0x01, 0x1b, 0x72, 0x6d, + 0xfc, 0x42, 0x4e, 0x7d, + 0x10, 0x40, 0x50, 0x6d, 0x20, 0x4d, 0x64, 0x78, 0x08, 0x5d, 0x64, 0x78, 0x02, 0x19, 0x32, 0x00, 0x01, 0x5b, 0x40, 0x31, - 0x00, 0xe2, 0xba, 0x5c, - 0x00, 0xe2, 0x98, 0x5b, + 0x00, 0xe2, 0xb2, 0x5c, + 0x00, 0xe2, 0x9e, 0x5b, 0x20, 0xea, 0xb6, 0x00, - 0x00, 0xe2, 0xda, 0x5b, + 0x00, 0xe2, 0xe0, 0x5b, 0x20, 0x5c, 0xb8, 0x00, - 0x04, 0x19, 0x76, 0x6d, - 0x01, 0x1a, 0x76, 0x6d, - 0x00, 0xe2, 0x3c, 0x59, + 0x04, 0x19, 0x68, 0x6d, + 0x01, 0x1a, 0x68, 0x6d, + 0x00, 0xe2, 0x3e, 0x59, 0x01, 0x1a, 0x64, 0x78, 0x80, 0xf9, 0xf2, 0x01, - 0x20, 0xa0, 0xda, 0x7d, - 0xff, 0xae, 0x5d, 0x1b, - 0x08, 0xa8, 0x3d, 0x6b, + 0x20, 0xa0, 0xcc, 0x7d, + 0xff, 0x90, 0x21, 0x1b, + 0x08, 0x92, 0x43, 0x6b, 0x02, 0xea, 0xb4, 0x04, - 0x01, 0x9c, 0x39, 0x03, - 0x40, 0x5b, 0x90, 0x6d, - 0x00, 0xe2, 0x3c, 0x59, - 0x40, 0x5b, 0x90, 0x6d, - 0x04, 0x5d, 0xf4, 0x7d, - 0x01, 0x1a, 0xf4, 0x7d, + 0x01, 0xa4, 0x49, 0x03, + 0x40, 0x5b, 0x82, 0x6d, + 0x00, 0xe2, 0x3e, 0x59, + 0x40, 0x5b, 0x82, 0x6d, + 0x04, 0x5d, 0xe6, 0x7d, + 0x01, 0x1a, 0xe6, 0x7d, 0x20, 0x4d, 0x64, 0x78, - 0x40, 0x5b, 0xda, 0x7d, - 0x04, 0x5d, 0xf4, 0x7d, - 0x01, 0x1a, 0xf4, 0x7d, + 0x40, 0x5b, 0xcc, 0x7d, + 0x04, 0x5d, 0xe6, 0x7d, + 0x01, 0x1a, 0xe6, 0x7d, 0x80, 0xf9, 0xf2, 0x01, - 0xff, 0xae, 0x5d, 0x1b, - 0x08, 0xa8, 0x3d, 0x6b, + 0xff, 0x90, 0x21, 0x1b, + 0x08, 0x92, 0x43, 0x6b, 0x02, 0xea, 0xb4, 0x04, - 0x00, 0xe2, 0x3c, 0x59, + 0x00, 0xe2, 0x3e, 0x59, 0x01, 0x1b, 0x64, 0x78, 0x80, 0xf9, 0xf2, 0x01, 0x02, 0xea, 0xb4, 0x04, - 0x00, 0xe2, 0x3c, 0x59, - 0x01, 0x1b, 0xb8, 0x6d, - 0x40, 0x5b, 0xc6, 0x7d, - 0x01, 0x1b, 0xb8, 0x6d, + 0x00, 0xe2, 0x3e, 0x59, + 0x01, 0x1b, 0xaa, 0x6d, + 0x40, 0x5b, 0xb8, 0x7d, + 0x01, 0x1b, 0xaa, 0x6d, 0x02, 0x19, 0x32, 0x00, 0x01, 0x1a, 0x64, 0x78, 0x80, 0xf9, 0xf2, 0x01, 0xff, 0xea, 0x10, 0x03, - 0x08, 0xa8, 0x51, 0x03, - 0x00, 0xe2, 0x3c, 0x43, - 0x01, 0x1a, 0xc2, 0x7d, - 0x40, 0x5b, 0xbe, 0x7d, - 0x01, 0x1a, 0xac, 0x6d, + 0x08, 0x92, 0x25, 0x03, + 0x00, 0xe2, 0x42, 0x43, + 0x01, 0x1a, 0xb4, 0x7d, + 0x40, 0x5b, 0xb0, 0x7d, + 0x01, 0x1a, 0x9e, 0x6d, 0xfc, 0x42, 0x64, 0x78, - 0x01, 0x1a, 0xc6, 0x6d, - 0x10, 0xea, 0x4e, 0x59, + 0x01, 0x1a, 0xb8, 0x6d, + 0x10, 0xea, 0x50, 0x59, 0x10, 0xea, 0x04, 0x00, 0xfc, 0x42, 0x64, 0x78, - 0x10, 0x40, 0xcc, 0x6d, + 0x10, 0x40, 0xbe, 0x6d, 0x20, 0x4d, 0x64, 0x78, - 0x40, 0x5b, 0xac, 0x6d, + 0x40, 0x5b, 0x9e, 0x6d, 0x01, 0x1a, 0x64, 0x78, - 0x01, 0xae, 0x5d, 0x1b, + 0x01, 0x90, 0x21, 0x1b, 0x30, 0x3f, 0xc0, 0x09, 0x30, 0xe0, 0x64, 0x60, 0x40, 0x4b, 0x64, 0x68, 0xff, 0xea, 0x52, 0x01, - 0xee, 0x00, 0xe0, 0x6d, + 0xee, 0x00, 0xd2, 0x6d, 0x80, 0xf9, 0xf2, 0x01, - 0xff, 0xae, 0x5d, 0x1b, + 0xff, 0x90, 0x21, 0x1b, 0x02, 0xea, 0xb4, 0x00, 0x20, 0xea, 0x9a, 0x00, - 0xf3, 0x42, 0xec, 0x6d, - 0x12, 0xea, 0x4e, 0x59, + 0xf3, 0x42, 0xde, 0x6d, + 0x12, 0xea, 0x50, 0x59, 0x12, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf6, 0x41, - 0x0d, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0x0d, 0xea, 0x50, 0x59, 0x0d, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf6, 0x41, - 0x01, 0xae, 0x5d, 0x1b, - 0x11, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0x01, 0x90, 0x21, 0x1b, + 0x11, 0xea, 0x50, 0x59, 0x11, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x2c, 0x5b, + 0x00, 0xe2, 0x32, 0x5b, 0x08, 0x5a, 0xb4, 0x00, - 0x00, 0xe2, 0x1a, 0x5e, + 0x00, 0xe2, 0x0c, 0x5e, 0xa8, 0xea, 0x32, 0x00, - 0x00, 0xe2, 0x3c, 0x59, - 0x80, 0x1a, 0x08, 0x7e, - 0x00, 0xe2, 0x1a, 0x5e, + 0x00, 0xe2, 0x3e, 0x59, + 0x80, 0x1a, 0xfa, 0x7d, + 0x00, 0xe2, 0x0c, 0x5e, 0x80, 0x19, 0x32, 0x00, - 0x40, 0x5b, 0x0e, 0x6e, - 0x08, 0x5a, 0x0e, 0x7e, + 0x40, 0x5b, 0x00, 0x6e, + 0x08, 0x5a, 0x00, 0x7e, 0x20, 0x4d, 0x64, 0x78, 0x02, 0x84, 0x09, 0x03, - 0x40, 0x5b, 0xda, 0x7d, - 0xff, 0xae, 0x5d, 0x1b, + 0x40, 0x5b, 0xcc, 0x7d, + 0xff, 0x90, 0x21, 0x1b, 0x80, 0xf9, 0xf2, 0x01, - 0x08, 0xa8, 0x3d, 0x6b, + 0x08, 0x92, 0x43, 0x6b, 0x02, 0xea, 0xb4, 0x04, 0x01, 0x38, 0xe1, 0x30, 0x05, 0x39, 0xe3, 0x98, @@ -801,12 +794,20 @@ static uint8_t seqprog[] = { }; typedef int ahd_patch_func_t (struct ahd_softc *ahd); +static ahd_patch_func_t ahd_patch22_func; + +static int +ahd_patch22_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0); +} + static ahd_patch_func_t ahd_patch21_func; static int ahd_patch21_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0); + return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0); } static ahd_patch_func_t ahd_patch20_func; @@ -814,7 +815,7 @@ static ahd_patch_func_t ahd_patch20_func static int ahd_patch20_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0); + return ((ahd->features & AHD_RTI) == 0); } static ahd_patch_func_t ahd_patch19_func; @@ -822,7 +823,7 @@ static ahd_patch_func_t ahd_patch19_func static int ahd_patch19_func(struct ahd_softc *ahd) { - return ((ahd->features & AHD_RTI) == 0); + return ((ahd->flags & AHD_INITIATORROLE) != 0); } static ahd_patch_func_t ahd_patch18_func; @@ -830,7 +831,7 @@ static ahd_patch_func_t ahd_patch18_func static int ahd_patch18_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_INITIATORROLE) != 0); + return ((ahd->flags & AHD_TARGETROLE) != 0); } static ahd_patch_func_t ahd_patch17_func; @@ -838,7 +839,7 @@ static ahd_patch_func_t ahd_patch17_func static int ahd_patch17_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_TARGETROLE) != 0); + return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0); } static ahd_patch_func_t ahd_patch16_func; @@ -846,7 +847,7 @@ static ahd_patch_func_t ahd_patch16_func static int ahd_patch16_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0); + return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0); } static ahd_patch_func_t ahd_patch15_func; @@ -854,7 +855,7 @@ static ahd_patch_func_t ahd_patch15_func static int ahd_patch15_func(struct ahd_softc *ahd) { - return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0); + return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0); } static ahd_patch_func_t ahd_patch14_func; @@ -862,7 +863,7 @@ static ahd_patch_func_t ahd_patch14_func static int ahd_patch14_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0); + return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0); } static ahd_patch_func_t ahd_patch13_func; @@ -870,7 +871,7 @@ static ahd_patch_func_t ahd_patch13_func static int ahd_patch13_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0); + return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0); } static ahd_patch_func_t ahd_patch12_func; @@ -878,7 +879,7 @@ static ahd_patch_func_t ahd_patch12_func static int ahd_patch12_func(struct ahd_softc *ahd) { - return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0); + return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0); } static ahd_patch_func_t ahd_patch11_func; @@ -886,7 +887,7 @@ static ahd_patch_func_t ahd_patch11_func static int ahd_patch11_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0); + return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0); } static ahd_patch_func_t ahd_patch10_func; @@ -894,7 +895,7 @@ static ahd_patch_func_t ahd_patch10_func static int ahd_patch10_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0); + return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0); } static ahd_patch_func_t ahd_patch9_func; @@ -902,7 +903,7 @@ static ahd_patch_func_t ahd_patch9_func; static int ahd_patch9_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0); + return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0); } static ahd_patch_func_t ahd_patch8_func; @@ -910,7 +911,7 @@ static ahd_patch_func_t ahd_patch8_func; static int ahd_patch8_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0); + return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0); } static ahd_patch_func_t ahd_patch7_func; @@ -918,7 +919,7 @@ static ahd_patch_func_t ahd_patch7_func; static int ahd_patch7_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0); + return ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0); } static ahd_patch_func_t ahd_patch6_func; @@ -926,7 +927,7 @@ static ahd_patch_func_t ahd_patch6_func; static int ahd_patch6_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0); + return ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0); } static ahd_patch_func_t ahd_patch5_func; @@ -934,7 +935,7 @@ static ahd_patch_func_t ahd_patch5_func; static int ahd_patch5_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0); + return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0); } static ahd_patch_func_t ahd_patch4_func; @@ -942,7 +943,7 @@ static ahd_patch_func_t ahd_patch4_func; static int ahd_patch4_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0); + return ((ahd->bugs & AHD_PKT_LUN_BUG) != 0); } static ahd_patch_func_t ahd_patch3_func; @@ -1008,109 +1009,112 @@ static struct patch { { ahd_patch0_func, 70, 1, 1 }, { ahd_patch1_func, 73, 1, 2 }, { ahd_patch0_func, 74, 1, 1 }, - { ahd_patch2_func, 161, 6, 1 }, - { ahd_patch1_func, 167, 2, 1 }, - { ahd_patch4_func, 169, 1, 1 }, - { ahd_patch2_func, 178, 1, 2 }, - { ahd_patch0_func, 179, 1, 1 }, - { ahd_patch5_func, 180, 2, 2 }, - { ahd_patch0_func, 182, 6, 3 }, - { ahd_patch2_func, 185, 1, 2 }, - { ahd_patch0_func, 186, 1, 1 }, - { ahd_patch2_func, 189, 1, 2 }, - { ahd_patch0_func, 190, 1, 1 }, - { ahd_patch6_func, 192, 2, 1 }, - { ahd_patch4_func, 200, 16, 2 }, - { ahd_patch0_func, 216, 1, 1 }, - { ahd_patch7_func, 236, 2, 1 }, - { ahd_patch1_func, 240, 1, 2 }, - { ahd_patch0_func, 241, 1, 1 }, - { ahd_patch6_func, 244, 2, 1 }, - { ahd_patch1_func, 258, 1, 2 }, - { ahd_patch0_func, 259, 1, 1 }, - { ahd_patch1_func, 262, 1, 2 }, - { ahd_patch0_func, 263, 1, 1 }, - { ahd_patch2_func, 266, 1, 2 }, - { ahd_patch0_func, 267, 1, 1 }, - { ahd_patch1_func, 322, 1, 2 }, - { ahd_patch0_func, 323, 1, 1 }, - { ahd_patch2_func, 331, 1, 2 }, - { ahd_patch0_func, 332, 1, 1 }, - { ahd_patch2_func, 335, 1, 2 }, - { ahd_patch0_func, 336, 1, 1 }, + { ahd_patch4_func, 107, 1, 1 }, + { ahd_patch2_func, 162, 6, 1 }, + { ahd_patch1_func, 168, 2, 1 }, + { ahd_patch5_func, 170, 1, 1 }, + { ahd_patch2_func, 179, 1, 2 }, + { ahd_patch0_func, 180, 1, 1 }, + { ahd_patch6_func, 181, 2, 2 }, + { ahd_patch0_func, 183, 6, 3 }, + { ahd_patch2_func, 186, 1, 2 }, + { ahd_patch0_func, 187, 1, 1 }, + { ahd_patch2_func, 190, 1, 2 }, + { ahd_patch0_func, 191, 1, 1 }, + { ahd_patch7_func, 193, 2, 1 }, + { ahd_patch5_func, 201, 16, 2 }, + { ahd_patch0_func, 217, 1, 1 }, + { ahd_patch8_func, 237, 2, 1 }, + { ahd_patch1_func, 241, 1, 2 }, + { ahd_patch0_func, 242, 1, 1 }, + { ahd_patch7_func, 245, 2, 1 }, + { ahd_patch1_func, 259, 1, 2 }, + { ahd_patch0_func, 260, 1, 1 }, + { ahd_patch1_func, 263, 1, 2 }, + { ahd_patch0_func, 264, 1, 1 }, + { ahd_patch2_func, 267, 1, 2 }, + { ahd_patch0_func, 268, 1, 1 }, + { ahd_patch1_func, 323, 1, 2 }, + { ahd_patch0_func, 324, 1, 1 }, + { ahd_patch2_func, 332, 1, 2 }, + { ahd_patch0_func, 333, 1, 1 }, + { ahd_patch2_func, 336, 1, 2 }, + { ahd_patch0_func, 337, 1, 1 }, { ahd_patch1_func, 343, 1, 2 }, { ahd_patch0_func, 344, 1, 1 }, - { ahd_patch8_func, 363, 1, 1 }, - { ahd_patch8_func, 366, 1, 1 }, - { ahd_patch8_func, 368, 1, 1 }, - { ahd_patch8_func, 380, 1, 1 }, - { ahd_patch1_func, 390, 1, 2 }, - { ahd_patch0_func, 391, 1, 1 }, + { ahd_patch1_func, 346, 1, 2 }, + { ahd_patch0_func, 347, 1, 1 }, + { ahd_patch9_func, 366, 1, 1 }, + { ahd_patch9_func, 369, 1, 1 }, + { ahd_patch9_func, 371, 1, 1 }, + { ahd_patch9_func, 383, 1, 1 }, { ahd_patch1_func, 393, 1, 2 }, { ahd_patch0_func, 394, 1, 1 }, - { ahd_patch1_func, 402, 1, 2 }, - { ahd_patch0_func, 403, 1, 1 }, - { ahd_patch2_func, 416, 1, 2 }, - { ahd_patch0_func, 417, 1, 1 }, - { ahd_patch9_func, 447, 1, 1 }, - { ahd_patch1_func, 454, 1, 2 }, - { ahd_patch0_func, 455, 1, 1 }, - { ahd_patch2_func, 467, 1, 2 }, - { ahd_patch0_func, 468, 1, 1 }, - { ahd_patch10_func, 473, 6, 2 }, - { ahd_patch0_func, 479, 1, 1 }, - { ahd_patch11_func, 502, 1, 1 }, - { ahd_patch12_func, 511, 1, 1 }, - { ahd_patch13_func, 512, 1, 2 }, - { ahd_patch0_func, 513, 1, 1 }, - { ahd_patch14_func, 518, 1, 1 }, - { ahd_patch13_func, 519, 1, 1 }, - { ahd_patch15_func, 532, 1, 2 }, - { ahd_patch0_func, 533, 1, 1 }, + { ahd_patch1_func, 396, 1, 2 }, + { ahd_patch0_func, 397, 1, 1 }, + { ahd_patch1_func, 405, 1, 2 }, + { ahd_patch0_func, 406, 1, 1 }, + { ahd_patch2_func, 419, 1, 2 }, + { ahd_patch0_func, 420, 1, 1 }, + { ahd_patch10_func, 450, 1, 1 }, + { ahd_patch1_func, 457, 1, 2 }, + { ahd_patch0_func, 458, 1, 1 }, + { ahd_patch2_func, 470, 1, 2 }, + { ahd_patch0_func, 471, 1, 1 }, + { ahd_patch11_func, 476, 6, 2 }, + { ahd_patch0_func, 482, 1, 1 }, + { ahd_patch12_func, 505, 1, 1 }, + { ahd_patch13_func, 514, 1, 1 }, + { ahd_patch14_func, 515, 1, 2 }, + { ahd_patch0_func, 516, 1, 1 }, + { ahd_patch15_func, 519, 1, 1 }, + { ahd_patch14_func, 520, 1, 1 }, + { ahd_patch16_func, 531, 1, 2 }, + { ahd_patch0_func, 532, 1, 1 }, + { ahd_patch1_func, 551, 1, 2 }, + { ahd_patch0_func, 552, 1, 1 }, { ahd_patch1_func, 555, 1, 2 }, { ahd_patch0_func, 556, 1, 1 }, - { ahd_patch1_func, 559, 1, 2 }, - { ahd_patch0_func, 560, 1, 1 }, - { ahd_patch2_func, 565, 1, 2 }, - { ahd_patch0_func, 566, 1, 1 }, - { ahd_patch2_func, 570, 1, 2 }, - { ahd_patch0_func, 571, 1, 1 }, - { ahd_patch1_func, 572, 1, 2 }, - { ahd_patch0_func, 573, 1, 1 }, - { ahd_patch2_func, 584, 1, 2 }, - { ahd_patch0_func, 585, 1, 1 }, - { ahd_patch16_func, 589, 1, 1 }, - { ahd_patch17_func, 594, 1, 1 }, - { ahd_patch18_func, 595, 2, 1 }, - { ahd_patch17_func, 599, 1, 2 }, + { ahd_patch2_func, 561, 1, 2 }, + { ahd_patch0_func, 562, 1, 1 }, + { ahd_patch2_func, 566, 1, 2 }, + { ahd_patch0_func, 567, 1, 1 }, + { ahd_patch1_func, 568, 1, 2 }, + { ahd_patch0_func, 569, 1, 1 }, + { ahd_patch2_func, 580, 1, 2 }, + { ahd_patch0_func, 581, 1, 1 }, + { ahd_patch17_func, 585, 1, 1 }, + { ahd_patch18_func, 590, 1, 1 }, + { ahd_patch19_func, 591, 2, 1 }, + { ahd_patch18_func, 595, 1, 2 }, + { ahd_patch0_func, 596, 1, 1 }, + { ahd_patch2_func, 599, 1, 2 }, { ahd_patch0_func, 600, 1, 1 }, - { ahd_patch2_func, 603, 1, 2 }, - { ahd_patch0_func, 604, 1, 1 }, - { ahd_patch2_func, 622, 1, 2 }, - { ahd_patch0_func, 623, 1, 1 }, - { ahd_patch19_func, 624, 14, 1 }, - { ahd_patch1_func, 642, 1, 2 }, - { ahd_patch0_func, 643, 1, 1 }, - { ahd_patch19_func, 644, 1, 1 }, - { ahd_patch1_func, 656, 1, 2 }, - { ahd_patch0_func, 657, 1, 1 }, - { ahd_patch1_func, 664, 1, 2 }, - { ahd_patch0_func, 665, 1, 1 }, - { ahd_patch16_func, 688, 1, 1 }, - { ahd_patch16_func, 726, 1, 1 }, - { ahd_patch1_func, 737, 1, 2 }, - { ahd_patch0_func, 738, 1, 1 }, + { ahd_patch2_func, 615, 1, 2 }, + { ahd_patch0_func, 616, 1, 1 }, + { ahd_patch20_func, 617, 14, 1 }, + { ahd_patch1_func, 635, 1, 2 }, + { ahd_patch0_func, 636, 1, 1 }, + { ahd_patch20_func, 637, 1, 1 }, + { ahd_patch1_func, 649, 1, 2 }, + { ahd_patch0_func, 650, 1, 1 }, + { ahd_patch1_func, 657, 1, 2 }, + { ahd_patch0_func, 658, 1, 1 }, + { ahd_patch17_func, 681, 1, 1 }, + { ahd_patch17_func, 719, 1, 1 }, + { ahd_patch1_func, 730, 1, 2 }, + { ahd_patch0_func, 731, 1, 1 }, + { ahd_patch1_func, 748, 1, 2 }, + { ahd_patch0_func, 749, 1, 1 }, + { ahd_patch1_func, 751, 1, 2 }, + { ahd_patch0_func, 752, 1, 1 }, { ahd_patch1_func, 755, 1, 2 }, { ahd_patch0_func, 756, 1, 1 }, - { ahd_patch1_func, 758, 1, 2 }, - { ahd_patch0_func, 759, 1, 1 }, - { ahd_patch1_func, 762, 1, 2 }, - { ahd_patch0_func, 763, 1, 1 }, - { ahd_patch20_func, 765, 1, 2 }, - { ahd_patch0_func, 766, 2, 1 }, - { ahd_patch21_func, 769, 4, 2 }, - { ahd_patch0_func, 773, 1, 1 }, - { ahd_patch21_func, 781, 11, 1 } + { ahd_patch21_func, 758, 1, 2 }, + { ahd_patch0_func, 759, 2, 1 }, + { ahd_patch22_func, 762, 4, 2 }, + { ahd_patch0_func, 766, 1, 1 }, + { ahd_patch22_func, 774, 11, 1 } }; static struct cs { @@ -1121,14 +1125,14 @@ static struct cs { { 13, 14 }, { 29, 42 }, { 56, 59 }, - { 101, 127 }, - { 128, 156 }, - { 158, 161 }, - { 169, 177 }, - { 200, 249 }, - { 688, 704 }, - { 704, 718 }, - { 728, 732 } + { 101, 128 }, + { 129, 157 }, + { 159, 162 }, + { 170, 178 }, + { 201, 250 }, + { 681, 697 }, + { 697, 711 }, + { 721, 725 } }; static const int num_critical_sections = sizeof(critical_sections) diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx.h linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx.h --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx.h 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx.h 2003-06-05 22:45:13.000000000 +0200 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#75 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#79 $ * * $FreeBSD$ */ @@ -93,7 +93,7 @@ struct seeprom_descriptor; #define SCB_GET_CHANNEL(ahc, scb) \ SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid) #define SCB_GET_LUN(scb) \ - ((scb)->hscb->lun) + ((scb)->hscb->lun & LID) #define SCB_GET_TARGET_OFFSET(ahc, scb) \ (SCB_GET_TARGET(ahc, scb) + (SCB_IS_SCSIBUS_B(ahc, scb) ? 8 : 0)) #define SCB_GET_TARGET_MASK(ahc, scb) \ @@ -1047,6 +1047,11 @@ struct ahc_softc { uint8_t tqinfifonext; /* + * Cached copy of the sequencer control register. + */ + uint8_t seqctl; + + /* * Incoming and outgoing message handling. */ uint8_t send_msg_perror; @@ -1138,17 +1143,17 @@ struct ahc_pci_identity { char *name; ahc_device_setup_t *setup; }; -extern struct ahc_pci_identity ahc_pci_ident_table []; +extern struct ahc_pci_identity ahc_pci_ident_table[]; extern const u_int ahc_num_pci_devs; /***************************** VL/EISA Declarations ***************************/ struct aic7770_identity { uint32_t full_id; uint32_t id_mask; - char *name; + const char *name; ahc_device_setup_t *setup; }; -extern struct aic7770_identity aic7770_ident_table []; +extern struct aic7770_identity aic7770_ident_table[]; extern const int ahc_num_aic7770_devs; #define AHC_EISA_SLOT_OFFSET 0xc00 @@ -1200,7 +1205,7 @@ void ahc_set_unit(struct ahc_softc *, void ahc_set_name(struct ahc_softc *, char *); void ahc_alloc_scbs(struct ahc_softc *ahc); void ahc_free(struct ahc_softc *ahc); -int ahc_reset(struct ahc_softc *ahc); +int ahc_reset(struct ahc_softc *ahc, int reinit); void ahc_shutdown(void *arg); /*************************** Interrupt Services *******************************/ diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx.reg linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx.reg --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx.reg 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx.reg 2003-06-05 22:45:13.000000000 +0200 @@ -39,7 +39,7 @@ * * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -1080,7 +1080,8 @@ scb { mask OID 0x0f } SCB_LUN { - mask LID 0xff + field SCB_XFERLEN_ODD 0x80 + mask LID 0x3f size 1 } SCB_TAG { @@ -1239,7 +1240,6 @@ register SG_CACHE_PRE { access_mode WO address 0x0fc mask SG_ADDR_MASK 0xf8 - field ODD_SEG 0x04 field LAST_SEG 0x02 field LAST_SEG_DONE 0x01 } @@ -1248,7 +1248,6 @@ register SG_CACHE_SHADOW { access_mode RO address 0x0fc mask SG_ADDR_MASK 0xf8 - field ODD_SEG 0x04 field LAST_SEG 0x02 field LAST_SEG_DONE 0x01 } @@ -1478,14 +1477,6 @@ scratch_ram { field ENAUTOATNI 0x04 field ENAUTOATNP 0x02 } - - /* - * Track whether the transfer byte count for - * the current data phase is odd. - */ - DATA_COUNT_ODD { - size 1 - } } scratch_ram { diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx.seq linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx.seq --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx.seq 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx.seq 2003-06-05 22:45:13.000000000 +0200 @@ -40,7 +40,7 @@ * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $" PATCH_ARG_LIST = "struct ahc_softc *ahc" PREFIX = "ahc_" @@ -437,7 +437,7 @@ select_out: mov SCBPTR, WAITING_SCBH; mov WAITING_SCBH,SCB_NEXT; mov SAVED_SCSIID, SCB_SCSIID; - mov SAVED_LUN, SCB_LUN; + and SAVED_LUN, LID, SCB_LUN; call set_transfer_settings; if ((ahc->flags & AHC_TARGETROLE) != 0) { test SSTAT0, TARGET jz initiator_select; @@ -461,7 +461,7 @@ select_out: /* * Start out with a simple identify message. */ - or SCB_LUN, MSG_IDENTIFYFLAG call target_outb; + or SAVED_LUN, MSG_IDENTIFYFLAG call target_outb; /* * If we are the result of a tagged command, send @@ -768,16 +768,12 @@ idle_sg_avail: /* Does the hardware have space for another SG entry? */ test DFSTATUS, PRELOAD_AVAIL jz return; bmov HADDR, CCSGRAM, 7; - test HCNT[0], 0x1 jz . + 2; - xor DATA_COUNT_ODD, 0x1; bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr; } call sg_advance; mov SINDEX, SCB_RESIDUAL_SGPTR[0]; - test DATA_COUNT_ODD, 0x1 jz . + 2; - or SINDEX, ODD_SEG; test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; or SINDEX, LAST_SEG; mov SG_CACHE_PRE, SINDEX; @@ -875,7 +871,6 @@ data_phase_initialize: call calc_mwi_residual; } and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID; - and DATA_COUNT_ODD, 0x1, HCNT[0]; if ((ahc->features & AHC_ULTRA2) == 0) { if ((ahc->features & AHC_CMD_CHAN) != 0) { @@ -910,8 +905,6 @@ data_phase_inbounds: mov SINDEX, SCB_RESIDUAL_SGPTR[0]; test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; or SINDEX, LAST_SEG; - test DATA_COUNT_ODD, 0x1 jz . + 2; - or SINDEX, ODD_SEG; mov SG_CACHE_PRE, SINDEX; mov DFCNTRL, DMAPARAMS; ultra2_dma_loop: @@ -1006,10 +999,8 @@ sgptr_fixup: adc SCB_RESIDUAL_SGPTR[3], -1; sgptr_fixup_done: and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; - clr DATA_COUNT_ODD; - test SG_CACHE_SHADOW, ODD_SEG jz . + 2; - or DATA_COUNT_ODD, 0x1; - clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ + /* We are not the last seg */ + and SCB_RESIDUAL_DATACNT[3], ~SG_LAST_SEG; residuals_correct: /* * Go ahead and shut down the DMA engine now. @@ -1053,11 +1044,19 @@ ultra2_fifoflush: * LAST_SEG_DONE to come true on a completed transfer * and then test to see if the data FIFO is non-empty. */ - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 4; + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL + jz ultra2_wait_fifoemp; test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; + /* + * FIFOEMP can lag LAST_SEG_DONE. Wait a few + * clocks before calling this an overrun. + */ + test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; + test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; /* Overrun */ jmp data_phase_loop; +ultra2_wait_fifoemp: test DFSTATUS, FIFOEMP jz .; } ultra2_fifoempty: @@ -1246,9 +1245,6 @@ sg_load_done: } else { call set_stcnt_from_hcnt; } - /* Track odd'ness */ - test HCNT[0], 0x1 jz . + 2; - xor DATA_COUNT_ODD, 0x1; if ((ahc->flags & AHC_TARGETROLE) != 0) { test SSTAT0, TARGET jnz data_phase_loop; @@ -1350,7 +1346,7 @@ residual_update_done: */ test DFCNTRL, DIRECTION jz target_ITloop; test SSTAT1, REQINIT jnz .; - test DATA_COUNT_ODD, 0x1 jz target_ITloop; + test SCB_LUN, SCB_XFERLEN_ODD jz target_ITloop; test SCSIRATE, WIDEXFER jz target_ITloop; /* * Issue an Ignore Wide Residue Message. @@ -1510,7 +1506,7 @@ p_mesgout: cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; p_mesgout_identify: - or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; + or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SAVED_LUN; test SCB_CONTROL, DISCENB jnz . + 2; and SINDEX, ~DISCENB; /* @@ -1587,7 +1583,7 @@ if ((ahc->features & AHC_WIDE) != 0) { mvi ARG_1 call inb_next; cmp ARG_1, 0x01 jne mesgin_reject; test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; - test DATA_COUNT_ODD, 0x1 jz mesgin_done; + test SCB_LUN, SCB_XFERLEN_ODD jnz mesgin_done; mvi IGN_WIDE_RES call set_seqint; jmp mesgin_done; } @@ -1716,7 +1712,7 @@ mesgin_disconnect: } test SCB_CONTROL, TAG_ENB jnz await_busfree; mov ARG_1, SCB_TAG; - mov SAVED_LUN, SCB_LUN; + and SAVED_LUN, LID, SCB_LUN; mov SCB_SCSIID call set_busy_target; jmp await_busfree; @@ -1859,7 +1855,7 @@ mesgin_identify: * at a time. So, if the lun doesn't match, look * for a tag message. */ - mov A, SCB_LUN; + and A, LID, SCB_LUN; cmp SAVED_LUN, A je setup_SCB_id_lun_okay; if ((ahc->flags & AHC_PAGESCBS) != 0) { /* @@ -1917,7 +1913,7 @@ setup_SCB: or SEQ_FLAGS, 0x8; } setup_SCB_id_okay: - mov A, SCB_LUN; + and A, LID, SCB_LUN; cmp SAVED_LUN, A jne not_found_cleanup_scb; setup_SCB_id_lun_okay: if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_core.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_core.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_core.c 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_core.c 2003-06-05 22:45:43.000000000 +0200 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#128 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#133 $ * * $FreeBSD$ */ @@ -202,7 +202,7 @@ static void ahc_handle_devreset(struct struct ahc_devinfo *devinfo, cam_status status, char *message, int verbose_level); -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE static void ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct scb *scb); @@ -291,7 +291,7 @@ ahc_restart(struct ahc_softc *ahc) ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA); } ahc_outb(ahc, MWI_RESIDUAL, 0); - ahc_outb(ahc, SEQCTL, FASTMODE); + ahc_outb(ahc, SEQCTL, ahc->seqctl); ahc_outb(ahc, SEQADDR0, 0); ahc_outb(ahc, SEQADDR1, 0); ahc_unpause(ahc); @@ -705,7 +705,7 @@ ahc_handle_seqint(struct ahc_softc *ahc, ahc->msgin_index = 0; } } -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE else { if (bus_phase == P_MESGOUT) { ahc->msg_type = @@ -1304,17 +1304,23 @@ ahc_handle_scsiint(struct ahc_softc *ahc ahc_qinfifo_requeue_tail(ahc, scb); printerror = 0; } else if (ahc_sent_msg(ahc, AHCMSG_EXT, - MSG_EXT_WDTR, FALSE) - || ahc_sent_msg(ahc, AHCMSG_EXT, - MSG_EXT_SDTR, FALSE)) { + MSG_EXT_WDTR, FALSE)) { /* - * Negotiation Rejected. Go-async and + * Negotiation Rejected. Go-narrow and * retry command. */ ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, AHC_TRANS_CUR|AHC_TRANS_GOAL, /*paused*/TRUE); + ahc_qinfifo_requeue_tail(ahc, scb); + printerror = 0; + } else if (ahc_sent_msg(ahc, AHCMSG_EXT, + MSG_EXT_SDTR, FALSE)) { + /* + * Negotiation Rejected. Go-async and + * retry command. + */ ahc_set_syncrate(ahc, &devinfo, /*syncrate*/NULL, /*period*/0, /*offset*/0, @@ -1467,7 +1473,7 @@ ahc_clear_critical_section(struct ahc_so else ahc_outb(ahc, SIMODE1, 0); ahc_outb(ahc, CLRINT, CLRSCSIINT); - ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) | STEP); + ahc_outb(ahc, SEQCTL, ahc->seqctl | STEP); stepping = TRUE; } if ((ahc->features & AHC_DT) != 0) { @@ -1481,7 +1487,7 @@ ahc_clear_critical_section(struct ahc_so if (stepping) { ahc_outb(ahc, SIMODE0, simode0); ahc_outb(ahc, SIMODE1, simode1); - ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) & ~STEP); + ahc_outb(ahc, SEQCTL, ahc->seqctl); } } @@ -2373,6 +2379,7 @@ ahc_build_transfer_msg(struct ahc_softc * may change. */ period = tinfo->goal.period; + offset = tinfo->goal.offset; ppr_options = tinfo->goal.ppr_options; /* Target initiated PPR is not allowed in the SCSI spec */ if (devinfo->role == ROLE_TARGET) @@ -2380,7 +2387,7 @@ ahc_build_transfer_msg(struct ahc_softc rate = ahc_devlimited_syncrate(ahc, tinfo, &period, &ppr_options, devinfo->role); dowide = tinfo->curr.width != tinfo->goal.width; - dosync = tinfo->curr.period != period; + dosync = tinfo->curr.offset != offset || tinfo->curr.period != period; /* * Only use PPR if we have options that need it, even if the device * claims to support it. There might be an expander in the way @@ -3176,23 +3183,30 @@ ahc_parse_msg(struct ahc_softc *ahc, str response = TRUE; sending_reply = TRUE; } + /* + * After a wide message, we are async, but + * some devices don't seem to honor this portion + * of the spec. Force a renegotiation of the + * sync component of our transfer agreement even + * if our goal is async. By updating our width + * after forcing the negotiation, we avoid + * renegotiating for width. + */ + ahc_update_neg_request(ahc, devinfo, tstate, + tinfo, AHC_NEG_ALWAYS); ahc_set_width(ahc, devinfo, bus_width, AHC_TRANS_ACTIVE|AHC_TRANS_GOAL, /*paused*/TRUE); - /* After a wide message, we are async */ - ahc_set_syncrate(ahc, devinfo, - /*syncrate*/NULL, /*period*/0, - /*offset*/0, /*ppr_options*/0, - AHC_TRANS_ACTIVE, /*paused*/TRUE); if (sending_reply == FALSE && reject == FALSE) { - if (tinfo->goal.offset) { - ahc->msgout_index = 0; - ahc->msgout_len = 0; - ahc_build_transfer_msg(ahc, devinfo); - ahc->msgout_index = 0; - response = TRUE; - } + /* + * We will always have an SDTR to send. + */ + ahc->msgout_index = 0; + ahc->msgout_len = 0; + ahc_build_transfer_msg(ahc, devinfo); + ahc->msgout_index = 0; + response = TRUE; } done = MSGLOOP_MSGCOMPLETE; break; @@ -3573,7 +3587,7 @@ ahc_handle_ign_wide_residue(struct ahc_s sgptr = ahc_inb(ahc, SCB_RESIDUAL_SGPTR); if ((sgptr & SG_LIST_NULL) != 0 - && ahc_inb(ahc, DATA_COUNT_ODD) == 1) { + && (ahc_inb(ahc, SCB_LUN) & SCB_XFERLEN_ODD) != 0) { /* * If the residual occurred on the last * transfer and the transfer request was @@ -3586,25 +3600,27 @@ ahc_handle_ign_wide_residue(struct ahc_s uint32_t data_addr; uint32_t sglen; - /* Pull in the rest of the sgptr */ - sgptr |= (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24) - | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16) - | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8); - sgptr &= SG_PTR_MASK; - data_cnt = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+3) << 24) - | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+2) << 16) - | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+1) << 8) - | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT)); - - data_addr = (ahc_inb(ahc, SHADDR + 3) << 24) - | (ahc_inb(ahc, SHADDR + 2) << 16) - | (ahc_inb(ahc, SHADDR + 1) << 8) - | (ahc_inb(ahc, SHADDR)); + /* Pull in all of the sgptr */ + sgptr = ahc_inl(ahc, SCB_RESIDUAL_SGPTR); + data_cnt = ahc_inl(ahc, SCB_RESIDUAL_DATACNT); + + if ((sgptr & SG_LIST_NULL) != 0) { + /* + * The residual data count is not updated + * for the command run to completion case. + * Explicitly zero the count. + */ + data_cnt &= ~AHC_SG_LEN_MASK; + } + + data_addr = ahc_inl(ahc, SHADDR); data_cnt += 1; data_addr -= 1; + sgptr &= SG_PTR_MASK; sg = ahc_sg_bus_to_virt(scb, sgptr); + /* * The residual sg ptr points to the next S/G * to load so we must go back one. @@ -3630,19 +3646,17 @@ ahc_handle_ign_wide_residue(struct ahc_s */ sg++; sgptr = ahc_sg_virt_to_bus(scb, sg); - ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 3, - sgptr >> 24); - ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 2, - sgptr >> 16); - ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 1, - sgptr >> 8); - ahc_outb(ahc, SCB_RESIDUAL_SGPTR, sgptr); } - - ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 3, data_cnt >> 24); - ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 2, data_cnt >> 16); - ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 1, data_cnt >> 8); - ahc_outb(ahc, SCB_RESIDUAL_DATACNT, data_cnt); + ahc_outl(ahc, SCB_RESIDUAL_SGPTR, sgptr); + ahc_outl(ahc, SCB_RESIDUAL_DATACNT, data_cnt); + /* + * Toggle the "oddness" of the transfer length + * to handle this mid-transfer ignore wide + * residue. This ensures that the oddness is + * correct for subsequent data transfers. + */ + ahc_outb(ahc, SCB_LUN, + ahc_inb(ahc, SCB_LUN) ^ SCB_XFERLEN_ODD); } } } @@ -3826,6 +3840,12 @@ ahc_alloc(void *platform_arg, char *name ahc->features = AHC_FENONE; ahc->bugs = AHC_BUGNONE; ahc->flags = AHC_FNONE; + /* + * Default to all error reporting enabled with the + * sequencer operating at its fastest speed. + * The bus attach code may modify this. + */ + ahc->seqctl = FASTMODE; for (i = 0; i < AHC_NUM_TARGETS; i++) TAILQ_INIT(&ahc->untagged_queues[i]); @@ -3986,7 +4006,7 @@ ahc_free(struct ahc_softc *ahc) tstate = ahc->enabled_targets[i]; if (tstate != NULL) { -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE int j; for (j = 0; j < AHC_NUM_LUNS; j++) { @@ -4002,7 +4022,7 @@ ahc_free(struct ahc_softc *ahc) free(tstate, M_DEVBUF); } } -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE if (ahc->black_hole != NULL) { xpt_free_path(ahc->black_hole->path); free(ahc->black_hole, M_DEVBUF); @@ -4027,7 +4047,7 @@ ahc_shutdown(void *arg) ahc = (struct ahc_softc *)arg; /* This will reset most registers to 0, but not all */ - ahc_reset(ahc); + ahc_reset(ahc, /*reinit*/FALSE); ahc_outb(ahc, SCSISEQ, 0); ahc_outb(ahc, SXFRCTL0, 0); ahc_outb(ahc, DSPCISTATUS, 0); @@ -4038,10 +4058,15 @@ ahc_shutdown(void *arg) /* * Reset the controller and record some information about it - * that is only available just after a reset. + * that is only available just after a reset. If "reinit" is + * non-zero, this reset occured after initial configuration + * and the caller requests that the chip be fully reinitialized + * to a runable state. Chip interrupts are *not* enabled after + * a reinitialization. The caller must enable interrupts via + * ahc_intr_enable(). */ int -ahc_reset(struct ahc_softc *ahc) +ahc_reset(struct ahc_softc *ahc, int reinit) { u_int sblkctl; u_int sxfrctl1_a, sxfrctl1_b; @@ -4137,7 +4162,7 @@ ahc_reset(struct ahc_softc *ahc) ahc_outb(ahc, SXFRCTL1, sxfrctl1_a); error = 0; - if (ahc->init_level > 0) + if (reinit != 0) /* * If a recovery action has forced a chip reset, * re-initialize the chip to our liking. @@ -4719,14 +4744,12 @@ ahc_chip_init(struct ahc_softc *ahc) * never settle, so don't complain if we * fail here. */ - ahc_pause(ahc); for (wait = 5000; (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait; wait--) ahc_delay(100); - ahc_unpause(ahc); } - + ahc_restart(ahc); return (0); } @@ -5120,7 +5143,7 @@ ahc_suspend(struct ahc_softc *ahc) return (EBUSY); } -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE /* * XXX What about ATIOs that have not yet been serviced? * Perhaps we should just refuse to be suspended if we @@ -5139,7 +5162,9 @@ int ahc_resume(struct ahc_softc *ahc) { - ahc_reset(ahc); + ahc_reset(ahc, /*reinit*/TRUE); + ahc_intr_enable(ahc, TRUE); + ahc_restart(ahc); return (0); } @@ -5221,7 +5246,7 @@ ahc_match_scb(struct ahc_softc *ahc, str if (match != 0) match = ((lun == slun) || (lun == CAM_LUN_WILDCARD)); if (match != 0) { -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE int group; group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code); @@ -5964,7 +5989,7 @@ ahc_reset_channel(struct ahc_softc *ahc, * before the reset occurred. */ ahc_run_qoutfifo(ahc); -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE /* * XXX - In Twin mode, the tqinfifo may have commands * for an unaffected channel in it. However, if @@ -5996,7 +6021,7 @@ ahc_reset_channel(struct ahc_softc *ahc, */ ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB); simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST); -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE /* * Bus resets clear ENSELI, so we cannot * defer re-enabling bus reset interrupts @@ -6015,7 +6040,7 @@ ahc_reset_channel(struct ahc_softc *ahc, } else { /* Case 2: A command from this bus is active or we're idle */ simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST); -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE /* * Bus resets clear ENSELI, so we cannot * defer re-enabling bus reset interrupts @@ -6401,7 +6426,6 @@ ahc_loadseq(struct ahc_softc *ahc) memcpy(ahc->critical_sections, cs_table, cs_count); } ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE); - ahc_restart(ahc); if (bootverbose) { printf(" %d instructions downloaded\n", downloaded); @@ -6962,11 +6986,12 @@ ahc_handle_en_lun(struct ahc_softc *ahc, */ ahc->flags = saved_flags; (void)ahc_loadseq(ahc); - ahc_unpause(ahc); + ahc_restart(ahc); ahc_unlock(ahc, &s); ccb->ccb_h.status = CAM_FUNC_NOTAVAIL; return; } + ahc_restart(ahc); ahc_unlock(ahc, &s); } cel = &ccb->cel; @@ -7201,12 +7226,16 @@ ahc_handle_en_lun(struct ahc_softc *ahc, printf("Configuring Initiator Mode\n"); ahc->flags &= ~AHC_TARGETROLE; ahc->flags |= AHC_INITIATORROLE; - ahc_pause(ahc); /* * Returning to a configuration that * fit previously will always succeed. */ (void)ahc_loadseq(ahc); + ahc_restart(ahc); + /* + * Unpaused. The extra unpause + * that follows is harmless. + */ } } ahc_unpause(ahc); diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_inline.h linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_inline.h --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_inline.h 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_inline.h 2003-06-05 22:45:13.000000000 +0200 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#42 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#43 $ * * $FreeBSD$ */ @@ -455,6 +455,13 @@ ahc_queue_scb(struct ahc_softc *ahc, str scb->hscb->tag, scb->hscb->next); /* + * Setup data "oddness". + */ + scb->hscb->lun &= LID; + if (ahc_get_transfer_length(scb) & 0x1) + scb->hscb->lun |= SCB_XFERLEN_ODD; + + /* * Keep a history of SCBs we've downloaded in the qinfifo. */ ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag; diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_osm.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_osm.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_osm.c 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_osm.c 2003-06-05 22:45:13.000000000 +0200 @@ -1,7 +1,7 @@ /* * Adaptec AIC7xxx device driver for Linux. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#221 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#234 $ * * Copyright (c) 1994 John Aycock * The University of Calgary Department of Computer Science. @@ -141,11 +141,6 @@ #include /* For fetching system memory size */ #include /* For block_size() */ -#define __KERNEL_SYSCALLS__ - -#include -static int errno; - /* * Lock protecting manipulation of the ahc softc list. */ @@ -298,7 +293,7 @@ static adapter_tag_info_t aic7xxx_tag_in #define AIC7XXX_CONFIGED_DV -1 #endif -static uint8_t aic7xxx_dv_settings[] = +static int8_t aic7xxx_dv_settings[] = { AIC7XXX_CONFIGED_DV, AIC7XXX_CONFIGED_DV, @@ -396,12 +391,9 @@ static uint32_t aic7xxx_pci_parity = ~0; * would result in never finding any devices :) */ #ifndef CONFIG_AIC7XXX_PROBE_EISA_VL -#define CONFIG_AIC7XXX_PROBE_EISA_VL n -#endif -#if CONFIG_AIC7XXX_PROBE_EISA_VL == n -static uint32_t aic7xxx_probe_eisa_vl; +uint32_t aic7xxx_probe_eisa_vl; #else -static uint32_t aic7xxx_probe_eisa_vl = ~0; +uint32_t aic7xxx_probe_eisa_vl = ~0; #endif /* @@ -749,56 +741,36 @@ ahc_linux_map_seg(struct ahc_softc *ahc, consumed = 1; sg->addr = ahc_htole32(addr & 0xFFFFFFFF); scb->platform_data->xfer_len += len; - if (sizeof(bus_addr_t) > 4 - && (ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - /* - * Due to DAC restrictions, we can't - * cross a 4GB boundary. - */ - if ((addr ^ (addr + len - 1)) & 0xFFFFFFFF00000000ULL) { - struct ahc_dma_seg *next_sg; - uint32_t first_len; - uint32_t next_len; - - printf("Crossed Seg\n"); - if ((scb->sg_count + 2) > AHC_NSEG) - panic("Too few segs for dma mapping. " - "Increase AHC_NSEG\n"); - - consumed++; - next_sg = sg + 1; - next_sg->addr = 0; - first_len = 0x100000000ULL - (addr & 0xFFFFFFFF); - next_len = len - first_len; - len = first_len; - next_len |= - ((addr >> 8) + 0x1000000) & AHC_SG_HIGH_ADDR_MASK; - next_sg->len = ahc_htole32(next_len); - } + if (sizeof(bus_addr_t) > 4 + && (ahc->flags & AHC_39BIT_ADDRESSING) != 0) len |= (addr >> 8) & AHC_SG_HIGH_ADDR_MASK; - } + sg->len = ahc_htole32(len); return (consumed); } /************************ Host template entry points *************************/ static int ahc_linux_detect(Scsi_Host_Template *); -static int ahc_linux_release(struct Scsi_Host *); static int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); static const char *ahc_linux_info(struct Scsi_Host *); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) static int ahc_linux_slave_alloc(Scsi_Device *); static int ahc_linux_slave_configure(Scsi_Device *); static void ahc_linux_slave_destroy(Scsi_Device *); +#if defined(__i386__) static int ahc_linux_biosparam(struct scsi_device*, struct block_device*, sector_t, int[]); +#endif #else +static int ahc_linux_release(struct Scsi_Host *); static void ahc_linux_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs); +#if defined(__i386__) static int ahc_linux_biosparam(Disk *, kdev_t, int[]); #endif +#endif static int ahc_linux_bus_reset(Scsi_Cmnd *); static int ahc_linux_dev_reset(Scsi_Cmnd *); static int ahc_linux_abort(Scsi_Cmnd *); @@ -923,8 +895,9 @@ ahc_linux_detect(Scsi_Host_Template *tem ahc_linux_pci_init(); #endif - if (aic7xxx_probe_eisa_vl != 0) - aic7770_linux_probe(template); +#ifdef CONFIG_EISA + ahc_linux_eisa_init(); +#endif /* * Register with the SCSI layer all @@ -943,6 +916,7 @@ ahc_linux_detect(Scsi_Host_Template *tem return (found); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* * Free the passed in Scsi_Host memory structures prior to unloading the * module. @@ -974,6 +948,7 @@ ahc_linux_release(struct Scsi_Host * hos ahc_list_unlock(&l); return (0); } +#endif /* * Return a string describing the driver. @@ -1198,6 +1173,7 @@ ahc_linux_select_queue_depth(struct Scsi } #endif +#if defined(__i386__) /* * Return the disk geometry for the given SCSI device. */ @@ -1264,6 +1240,7 @@ ahc_linux_biosparam(Disk *disk, kdev_t d geom[2] = cylinders; return (0); } +#endif /* * Abort the current SCSI command(s). @@ -1748,7 +1725,7 @@ ahc_linux_register_host(struct ahc_softc struct Scsi_Host *host; char *new_name; u_long s; - u_int target; + u_int targ_offset; template->name = ahc->description; host = scsi_register(template, sizeof(struct ahc_softc *)); @@ -1803,14 +1780,19 @@ ahc_linux_register_host(struct ahc_softc * negotiation will occur for the first command, and DV * will comence should that first command be successful. */ - for (target = 0; - target < host->max_id * (host->max_channel + 1); target++) { + for (targ_offset = 0; + targ_offset < host->max_id * (host->max_channel + 1); + targ_offset++) { u_int channel; + u_int target; channel = 0; + target = targ_offset; if (target > 7 - && (ahc->features & AHC_TWIN) != 0) + && (ahc->features & AHC_TWIN) != 0) { channel = 1; + target &= 0x7; + } /* * Skip our own ID. Some Compaq/HP storage devices * have enclosure management devices that respond to @@ -1838,7 +1820,7 @@ ahc_linux_register_host(struct ahc_softc } uint64_t -ahc_linux_get_memsize() +ahc_linux_get_memsize(void) { struct sysinfo si; @@ -1853,7 +1835,7 @@ ahc_linux_get_memsize() * scenario. */ static int -ahc_linux_next_unit() +ahc_linux_next_unit(void) { struct ahc_softc *ahc; int unit; @@ -2444,8 +2426,10 @@ ahc_linux_dv_target(struct ahc_softc *ah ahc_unlock(ahc, &s); return; } - ahc_compile_devinfo(&devinfo, ahc->our_id, targ->target, /*lun*/0, - targ->channel + 'A', ROLE_INITIATOR); + ahc_compile_devinfo(&devinfo, + targ->channel == 0 ? ahc->our_id : ahc->our_id_b, + targ->target, /*lun*/0, targ->channel + 'A', + ROLE_INITIATOR); #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_DV) { ahc_print_devinfo(ahc, &devinfo); @@ -2617,14 +2601,11 @@ ahc_linux_dv_transition(struct ahc_softc struct ahc_devinfo *devinfo, struct ahc_linux_target *targ) { - cam_status cam_status; u_int32_t status; - u_int scsi_status; - - scsi_status = ahc_cmd_get_scsi_status(cmd); - cam_status = ahc_cmd_get_transaction_status(cmd); - status = aic_error_action(cmd, targ->inq_data, cam_status, scsi_status); + status = aic_error_action(cmd, targ->inq_data, + ahc_cmd_get_transaction_status(cmd), + ahc_cmd_get_scsi_status(cmd)); #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_DV) { @@ -3778,7 +3759,7 @@ ahc_linux_run_device_queue(struct ahc_so cur_seg = (struct scatterlist *)cmd->request_buffer; nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg, - scsi_to_pci_dma_dir(cmd ->sc_data_direction)); + scsi_to_pci_dma_dir(cmd->sc_data_direction)); end_seg = cur_seg + nseg; /* Copy the segments into the SG list. */ sg = scb->sg_list; @@ -3882,7 +3863,7 @@ ahc_linux_run_device_queue(struct ahc_so /* * SCSI controller interrupt handler. */ -AIC_LINUX_IRQRETURN_T +irqreturn_t ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs) { struct ahc_softc *ahc; @@ -3896,7 +3877,7 @@ ahc_linux_isr(int irq, void *dev_id, str ahc_schedule_runq(ahc); ahc_linux_run_complete_queue(ahc); ahc_unlock(ahc, &flags); - AIC_LINUX_IRQRETURN(ours); + return IRQ_RETVAL(ours); } void @@ -4090,22 +4071,19 @@ ahc_send_async(struct ahc_softc *ahc, ch } case AC_SENT_BDR: { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + WARN_ON(lun != CAM_LUN_WILDCARD); + scsi_report_device_reset(ahc->platform_data->host, + channel - 'A', target); +#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) Scsi_Device *scsi_dev; /* * Find the SCSI device associated with this * request and indicate that a UA is expected. - * XXX This should really be handled by the mid-layer. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - list_for_each_entry(scsi_dev, - &ahc->platform_data->host->my_devices, - siblings) { -#else for (scsi_dev = ahc->platform_data->host->host_queue; scsi_dev != NULL; scsi_dev = scsi_dev->next) { -#endif if (channel - 'A' == scsi_dev->channel && target == scsi_dev->id && (lun == CAM_LUN_WILDCARD @@ -4914,7 +4892,7 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd * disconnected = FALSE; else if (flag != SCB_ABORT && ahc_inb(ahc, SAVED_SCSIID) == pending_scb->hscb->scsiid - && ahc_inb(ahc, SAVED_LUN) == pending_scb->hscb->lun) + && ahc_inb(ahc, SAVED_LUN) == SCB_GET_LUN(pending_scb)) disconnected = FALSE; } @@ -5130,27 +5108,21 @@ ahc_linux_exit(void) ahc_linux_kill_dv_thread(ahc); } ahc_list_unlock(&l); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - - ahc_linux_pci_exit(); - - /* - * Get rid of the non-pci devices. - * - * XXX(hch): switch over eisa support to new LDM-based API - */ - TAILQ_FOREACH(ahc, &ahc_tailq, links) - ahc_linux_release(ahc->platform_data->host); -#else - scsi_unregister_module(MODULE_SCSI_HA, &aic7xxx_driver_template); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) /* * In 2.4 we have to unregister from the PCI core _after_ * unregistering from the scsi midlayer to avoid dangling * references. */ + scsi_unregister_module(MODULE_SCSI_HA, &aic7xxx_driver_template); +#endif +#ifdef CONFIG_PCI ahc_linux_pci_exit(); #endif +#ifdef CONFIG_EISA + ahc_linux_eisa_exit(); +#endif } module_init(ahc_linux_init); diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_osm.h linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_osm.h --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_osm.h 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_osm.h 2003-06-05 22:45:43.000000000 +0200 @@ -53,7 +53,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#142 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#150 $ * */ #ifndef _AIC7XXX_LINUX_H_ @@ -258,7 +258,7 @@ int ahc_dmamap_unload(struct ahc_softc * typedef struct timer_list ahc_timer_t; /********************************** Includes **********************************/ -#if CONFIG_AIC7XXX_REG_PRETTY_PRINT +#ifdef CONFIG_AIC7XXX_REG_PRETTY_PRINT #define AIC_DEBUG_REGISTERS 1 #else #define AIC_DEBUG_REGISTERS 0 @@ -305,7 +305,7 @@ ahc_scb_timer_reset(struct scb *scb, u_i #define AHC_SCSI_HAS_HOST_LOCK 0 #endif -#define AIC7XXX_DRIVER_VERSION "6.2.33" +#define AIC7XXX_DRIVER_VERSION "6.2.36" /**************************** Front End Queues ********************************/ /* @@ -796,7 +796,7 @@ ahc_done_unlock(struct ahc_softc *ahc, u } static __inline void -ahc_list_lockinit() +ahc_list_lockinit(void) { spin_lock_init(&ahc_list_spinlock); } @@ -862,15 +862,26 @@ typedef enum AHC_POWER_STATE_D3 } ahc_power_state; -void ahc_power_state_change(struct ahc_softc *ahc, - ahc_power_state new_state); /**************************** VL/EISA Routines ********************************/ -int aic7770_linux_probe(Scsi_Host_Template *); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) \ + && (defined(__i386__) || defined(__alpha__)) \ + && (!defined(CONFIG_EISA))) +#define CONFIG_EISA +#endif + +#ifdef CONFIG_EISA +extern uint32_t aic7xxx_probe_eisa_vl; +void ahc_linux_eisa_init(void); +void ahc_linux_eisa_exit(void); int aic7770_map_registers(struct ahc_softc *ahc, u_int port); int aic7770_map_int(struct ahc_softc *ahc, u_int irq); +#endif /******************************* PCI Routines *********************************/ +#ifdef CONFIG_PCI +void ahc_power_state_change(struct ahc_softc *ahc, + ahc_power_state new_state); int ahc_linux_pci_init(void); void ahc_linux_pci_exit(void); int ahc_pci_map_registers(struct ahc_softc *ahc); @@ -952,6 +963,7 @@ ahc_get_pci_bus(ahc_dev_softc_t pci) { return (pci->bus->number); } +#endif static __inline void ahc_flush_device_writes(struct ahc_softc *); static __inline void @@ -981,7 +993,12 @@ ahc_flush_device_writes(struct ahc_softc (((dev_softc)->dma_mask = mask) && 0) #endif /**************************** Proc FS Support *********************************/ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) int ahc_linux_proc_info(char *, char **, off_t, int, int, int); +#else +int ahc_linux_proc_info(struct Scsi_Host *, char *, char **, + off_t, int, int); +#endif /*************************** Domain Validation ********************************/ #define AHC_DV_CMD(cmd) ((cmd)->scsi_done == ahc_linux_dv_complete) @@ -1183,7 +1200,7 @@ void ahc_platform_set_tags(struct ahc_so int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, role_t role, uint32_t status); -AIC_LINUX_IRQRETURN_T +irqreturn_t ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs); void ahc_platform_flushwork(struct ahc_softc *ahc); int ahc_softc_comp(struct ahc_softc *, struct ahc_softc *); diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c 2003-06-05 22:45:13.000000000 +0200 @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#44 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#46 $ */ #include "aic7xxx_osm.h" @@ -110,6 +110,7 @@ static int ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { char buf[80]; + bus_addr_t mask_39bit; struct ahc_softc *ahc; ahc_dev_softc_t pci; struct ahc_pci_identity *entry; @@ -160,12 +161,12 @@ ahc_linux_pci_dev_probe(struct pci_dev * } pci_set_master(pdev); + mask_39bit = (bus_addr_t)0x7FFFFFFFFFULL; if (sizeof(bus_addr_t) > 4 && ahc_linux_get_memsize() > 0x80000000 - && ahc_pci_set_dma_mask(pdev, 0x7FFFFFFFFFULL) == 0) { + && ahc_pci_set_dma_mask(pdev, mask_39bit) == 0) { ahc->flags |= AHC_39BIT_ADDRESSING; - ahc->platform_data->hw_dma_mask = - (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0); + ahc->platform_data->hw_dma_mask = mask_39bit; } else { ahc_pci_set_dma_mask(pdev, 0xFFFFFFFF); ahc->platform_data->hw_dma_mask = 0xFFFFFFFF; diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_pci.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_pci.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_pci.c 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_pci.c 2003-06-05 22:45:13.000000000 +0200 @@ -39,7 +39,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#63 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#69 $ * * $FreeBSD$ */ @@ -76,7 +76,7 @@ ahc_compose_id(u_int device, u_int vendo #define ID_9005_SISL_MASK 0x000FFFFF00000000ull #define ID_9005_SISL_ID 0x0005900500000000ull #define ID_AIC7850 0x5078900400000000ull -#define ID_AHA_2902_04_10_15_20_30C 0x5078900478509004ull +#define ID_AHA_2902_04_10_15_20C_30C 0x5078900478509004ull #define ID_AIC7855 0x5578900400000000ull #define ID_AIC7859 0x3860900400000000ull #define ID_AHA_2930CU 0x3860900438699004ull @@ -245,9 +245,9 @@ struct ahc_pci_identity ahc_pci_ident_ta { /* aic7850 based controllers */ { - ID_AHA_2902_04_10_15_20_30C, + ID_AHA_2902_04_10_15_20C_30C, ID_ALL_MASK, - "Adaptec 2902/04/10/15/20/30C SCSI adapter", + "Adaptec 2902/04/10/15/20C/30C SCSI adapter", ahc_aic785X_setup }, /* aic7860 based controllers */ @@ -834,10 +834,10 @@ ahc_pci_config(struct ahc_softc *ahc, st ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); /* Ensure busmastering is enabled */ - command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1); + command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2); command |= PCIM_CMD_BUSMASTEREN; - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/1); + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/2); /* On all PCI adapters, we allow SCB paging */ ahc->flags |= AHC_PAGESCBS; @@ -854,10 +854,8 @@ ahc_pci_config(struct ahc_softc *ahc, st * error reporting when doing this, so CIO bus, scb ram, and * scratch ram parity errors will be ignored too. */ - if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0) { - ahc->pause |= FAILDIS; - ahc->unpause |= FAILDIS; - } + if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0) + ahc->seqctl |= FAILDIS; ahc->bus_intr = ahc_pci_intr; ahc->bus_chip_init = ahc_pci_chip_init; @@ -879,7 +877,7 @@ ahc_pci_config(struct ahc_softc *ahc, st scsiseq = 0; } - error = ahc_reset(ahc); + error = ahc_reset(ahc, /*reinit*/FALSE); if (error != 0) return (ENXIO); @@ -1291,6 +1289,14 @@ ahc_pci_test_register_access(struct ahc_ ahc_outb(ahc, HCNTRL, hcntrl|PAUSE); while (ahc_is_paused(ahc) == 0) ; + + /* Clear any PCI errors that occurred before our driver attached. */ + status1 = ahc_pci_read_config(ahc->dev_softc, + PCIR_STATUS + 1, /*bytes*/1); + ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1, + status1, /*bytes*/1); + ahc_outb(ahc, CLRINT, CLRPARERR); + ahc_outb(ahc, SEQCTL, PERRORDIS); ahc_outb(ahc, SCBPTR, 0); ahc_outl(ahc, SCB_BASE, 0x5aa555aa); @@ -1963,8 +1969,7 @@ write_brdctl(struct ahc_softc *ahc, uint } static uint8_t -read_brdctl(ahc) - struct ahc_softc *ahc; +read_brdctl(struct ahc_softc *ahc) { uint8_t brdctl; uint8_t value; @@ -2045,8 +2050,8 @@ ahc_pci_intr(struct ahc_softc *ahc) "%s: WARNING WARNING WARNING WARNING\n", ahc_name(ahc), ahc_name(ahc), ahc_name(ahc), ahc_name(ahc), ahc_name(ahc), ahc_name(ahc)); - ahc->pause |= FAILDIS; - ahc->unpause |= FAILDIS; + ahc->seqctl |= FAILDIS; + ahc_outb(ahc, SEQCTL, ahc->seqctl); } ahc_unpause(ahc); } diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_proc.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_proc.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_proc.c 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_proc.c 2003-06-05 22:45:13.000000000 +0200 @@ -37,7 +37,7 @@ * String handling code courtesy of Gerard Roudier's * sym driver. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#27 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#29 $ */ #include "aic7xxx_osm.h" #include "aic7xxx_inline.h" @@ -289,8 +289,13 @@ done: * Return information to handle /proc support for the driver. */ int +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) ahc_linux_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout) + int length, int hostno, int inout) +#else +ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, + off_t offset, int length, int inout) +#endif { struct ahc_softc *ahc; struct info_str info; @@ -302,10 +307,14 @@ ahc_linux_proc_info(char *buffer, char * retval = -EINVAL; ahc_list_lock(&s); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) TAILQ_FOREACH(ahc, &ahc_tailq, links) { if (ahc->platform_data->host->host_no == hostno) break; } +#else + ahc = ahc_find_softc(*(struct ahc_softc **)shost->hostdata); +#endif if (ahc == NULL) goto done; diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_reg.h linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_reg.h --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_reg.h 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_reg.h 2003-06-05 22:45:13.000000000 +0200 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ */ typedef int (ahc_reg_print_t)(u_int, u_int *, u_int); typedef struct ahc_reg_parse_entry { @@ -433,13 +433,6 @@ ahc_reg_print_t ahc_scsiseq_template_pri #endif #if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_data_count_odd_print; -#else -#define ahc_data_count_odd_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "DATA_COUNT_ODD", 0x55, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_ha_274_biosglobal_print; #else #define ahc_ha_274_biosglobal_print(regvalue, cur_col, wrap) \ @@ -1396,8 +1389,6 @@ ahc_reg_print_t ahc_sg_cache_pre_print; #define ENAUTOATNI 0x04 #define ENAUTOATNP 0x02 -#define DATA_COUNT_ODD 0x55 - #define HA_274_BIOSGLOBAL 0x56 #define INITIATOR_TAG 0x56 #define HA_274_EXTENDED_TRANS 0x01 @@ -1655,7 +1646,8 @@ ahc_reg_print_t ahc_sg_cache_pre_print; #define TWIN_CHNLB 0x80 #define SCB_LUN 0xba -#define LID 0xff +#define LID 0x3f +#define SCB_XFERLEN_ODD 0x80 #define SCB_TAG 0xbb @@ -1749,7 +1741,6 @@ ahc_reg_print_t ahc_sg_cache_pre_print; #define SG_CACHE_SHADOW 0xfc #define SG_ADDR_MASK 0xf8 -#define ODD_SEG 0x04 #define LAST_SEG 0x02 #define LAST_SEG_DONE 0x01 diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_reg_print.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_reg_print.c --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_reg_print.c 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_reg_print.c 2003-06-05 22:45:13.000000000 +0200 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ */ #include "aic7xxx_osm.h" @@ -747,13 +747,6 @@ ahc_scsiseq_template_print(u_int regvalu 0x54, regvalue, cur_col, wrap)); } -int -ahc_data_count_odd_print(u_int regvalue, u_int *cur_col, u_int wrap) -{ - return (ahc_print_register(NULL, 0, "DATA_COUNT_ODD", - 0x55, regvalue, cur_col, wrap)); -} - static ahc_reg_parse_entry_t HA_274_BIOSGLOBAL_parse_table[] = { { "HA_274_EXTENDED_TRANS",0x01, 0x01 } }; @@ -1416,13 +1409,14 @@ ahc_scb_scsiid_print(u_int regvalue, u_i } static ahc_reg_parse_entry_t SCB_LUN_parse_table[] = { - { "LID", 0xff, 0xff } + { "SCB_XFERLEN_ODD", 0x80, 0x80 }, + { "LID", 0x3f, 0x3f } }; int ahc_scb_lun_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahc_print_register(SCB_LUN_parse_table, 1, "SCB_LUN", + return (ahc_print_register(SCB_LUN_parse_table, 2, "SCB_LUN", 0xba, regvalue, cur_col, wrap)); } @@ -1662,28 +1656,26 @@ ahc_dff_thrsh_print(u_int regvalue, u_in static ahc_reg_parse_entry_t SG_CACHE_SHADOW_parse_table[] = { { "LAST_SEG_DONE", 0x01, 0x01 }, { "LAST_SEG", 0x02, 0x02 }, - { "ODD_SEG", 0x04, 0x04 }, { "SG_ADDR_MASK", 0xf8, 0xf8 } }; int ahc_sg_cache_shadow_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahc_print_register(SG_CACHE_SHADOW_parse_table, 4, "SG_CACHE_SHADOW", + return (ahc_print_register(SG_CACHE_SHADOW_parse_table, 3, "SG_CACHE_SHADOW", 0xfc, regvalue, cur_col, wrap)); } static ahc_reg_parse_entry_t SG_CACHE_PRE_parse_table[] = { { "LAST_SEG_DONE", 0x01, 0x01 }, { "LAST_SEG", 0x02, 0x02 }, - { "ODD_SEG", 0x04, 0x04 }, { "SG_ADDR_MASK", 0xf8, 0xf8 } }; int ahc_sg_cache_pre_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahc_print_register(SG_CACHE_PRE_parse_table, 4, "SG_CACHE_PRE", + return (ahc_print_register(SG_CACHE_PRE_parse_table, 3, "SG_CACHE_PRE", 0xfc, regvalue, cur_col, wrap)); } diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_seq.h linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_seq.h --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aic7xxx_seq.h 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aic7xxx_seq.h 2003-06-05 22:45:13.000000000 +0200 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ */ static uint8_t seqprog[] = { 0xb2, 0x00, 0x00, 0x08, @@ -21,15 +21,15 @@ static uint8_t seqprog[] = { 0x01, 0x4d, 0xc8, 0x30, 0x00, 0x4c, 0x12, 0x70, 0x01, 0x39, 0xa2, 0x30, - 0x00, 0x6a, 0xd4, 0x5e, + 0x00, 0x6a, 0xc0, 0x5e, 0x01, 0x51, 0x20, 0x31, 0x01, 0x57, 0xae, 0x00, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0x26, 0x5e, + 0x00, 0x51, 0x12, 0x5e, 0x01, 0x51, 0xc8, 0x30, 0x00, 0x39, 0xc8, 0x60, 0x00, 0xbb, 0x30, 0x70, - 0xc1, 0x6a, 0xec, 0x5e, + 0xc1, 0x6a, 0xd8, 0x5e, 0x01, 0xbf, 0x72, 0x30, 0x01, 0x40, 0x7e, 0x31, 0x01, 0x90, 0x80, 0x30, @@ -49,10 +49,10 @@ static uint8_t seqprog[] = { 0x08, 0x6a, 0x78, 0x00, 0x01, 0x50, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x10, 0x5e, + 0x48, 0x6a, 0xfc, 0x5d, 0x01, 0x6a, 0xdc, 0x01, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x10, 0x5e, + 0x48, 0x6a, 0xfc, 0x5d, 0x01, 0x6a, 0x26, 0x01, 0xf0, 0x19, 0x7a, 0x08, 0x0f, 0x18, 0xc8, 0x08, @@ -93,7 +93,7 @@ static uint8_t seqprog[] = { 0x00, 0x65, 0x20, 0x41, 0x02, 0x57, 0xae, 0x00, 0x00, 0x65, 0x9e, 0x40, - 0x61, 0x6a, 0xec, 0x5e, + 0x61, 0x6a, 0xd8, 0x5e, 0x08, 0x51, 0x20, 0x71, 0x02, 0x0b, 0xb2, 0x78, 0x00, 0x65, 0xae, 0x40, @@ -106,7 +106,7 @@ static uint8_t seqprog[] = { 0x80, 0x3d, 0x7a, 0x00, 0x20, 0x6a, 0x16, 0x00, 0x00, 0x65, 0xcc, 0x41, - 0x00, 0x65, 0xc6, 0x5e, + 0x00, 0x65, 0xb2, 0x5e, 0x00, 0x65, 0x12, 0x40, 0x20, 0x11, 0xd2, 0x68, 0x20, 0x6a, 0x18, 0x00, @@ -135,20 +135,20 @@ static uint8_t seqprog[] = { 0x01, 0x40, 0x20, 0x31, 0x01, 0xbf, 0x80, 0x30, 0x01, 0xb9, 0x7a, 0x30, - 0x01, 0xba, 0x7c, 0x30, + 0x3f, 0xba, 0x7c, 0x08, 0x00, 0x65, 0xea, 0x58, 0x80, 0x0b, 0xc4, 0x79, 0x12, 0x01, 0x02, 0x00, 0x01, 0xab, 0xac, 0x30, - 0xe4, 0x6a, 0x82, 0x5d, + 0xe4, 0x6a, 0x6e, 0x5d, 0x40, 0x6a, 0x16, 0x00, - 0x80, 0xba, 0x98, 0x5d, + 0x80, 0x3e, 0x84, 0x5d, 0x20, 0xb8, 0x18, 0x79, - 0x20, 0x6a, 0x98, 0x5d, - 0x00, 0xab, 0x98, 0x5d, + 0x20, 0x6a, 0x84, 0x5d, + 0x00, 0xab, 0x84, 0x5d, 0x01, 0xa9, 0x78, 0x30, 0x10, 0xb8, 0x20, 0x79, - 0xe4, 0x6a, 0x82, 0x5d, + 0xe4, 0x6a, 0x6e, 0x5d, 0x00, 0x65, 0xae, 0x40, 0x10, 0x03, 0x3c, 0x69, 0x08, 0x3c, 0x5a, 0x69, @@ -157,10 +157,10 @@ static uint8_t seqprog[] = { 0x01, 0x3c, 0x44, 0x79, 0xff, 0x6a, 0x70, 0x00, 0x00, 0x65, 0xa4, 0x59, - 0x00, 0x6a, 0xd4, 0x5e, + 0x00, 0x6a, 0xc0, 0x5e, 0xff, 0x38, 0x30, 0x71, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x38, 0x26, 0x5e, + 0x00, 0x38, 0x12, 0x5e, 0x00, 0x65, 0xea, 0x58, 0x12, 0x01, 0x02, 0x00, 0x00, 0x65, 0x18, 0x41, @@ -168,10 +168,10 @@ static uint8_t seqprog[] = { 0x00, 0x65, 0xf2, 0x58, 0xfd, 0x57, 0xae, 0x08, 0x00, 0x65, 0xae, 0x40, - 0xe4, 0x6a, 0x82, 0x5d, + 0xe4, 0x6a, 0x6e, 0x5d, 0x20, 0x3c, 0x4a, 0x79, - 0x02, 0x6a, 0x98, 0x5d, - 0x04, 0x6a, 0x98, 0x5d, + 0x02, 0x6a, 0x84, 0x5d, + 0x04, 0x6a, 0x84, 0x5d, 0x01, 0x03, 0x4c, 0x69, 0xf7, 0x11, 0x22, 0x08, 0xff, 0x6a, 0x24, 0x08, @@ -182,13 +182,13 @@ static uint8_t seqprog[] = { 0x80, 0x86, 0xc8, 0x08, 0x01, 0x4f, 0xc8, 0x30, 0x00, 0x50, 0x6c, 0x61, - 0xc4, 0x6a, 0x82, 0x5d, + 0xc4, 0x6a, 0x6e, 0x5d, 0x40, 0x3c, 0x68, 0x79, - 0x28, 0x6a, 0x98, 0x5d, + 0x28, 0x6a, 0x84, 0x5d, 0x00, 0x65, 0x4c, 0x41, - 0x08, 0x6a, 0x98, 0x5d, + 0x08, 0x6a, 0x84, 0x5d, 0x00, 0x65, 0x4c, 0x41, - 0x84, 0x6a, 0x82, 0x5d, + 0x84, 0x6a, 0x6e, 0x5d, 0x00, 0x65, 0xf2, 0x58, 0x01, 0x66, 0xc8, 0x30, 0x01, 0x64, 0xd8, 0x31, @@ -208,16 +208,16 @@ static uint8_t seqprog[] = { 0xf7, 0x3c, 0x78, 0x08, 0x00, 0x65, 0x20, 0x41, 0x40, 0xaa, 0x7e, 0x10, - 0x04, 0xaa, 0x82, 0x5d, - 0x00, 0x65, 0x5e, 0x42, - 0xc4, 0x6a, 0x82, 0x5d, + 0x04, 0xaa, 0x6e, 0x5d, + 0x00, 0x65, 0x56, 0x42, + 0xc4, 0x6a, 0x6e, 0x5d, 0xc0, 0x6a, 0x7e, 0x00, - 0x00, 0xa8, 0x98, 0x5d, + 0x00, 0xa8, 0x84, 0x5d, 0xe4, 0x6a, 0x06, 0x00, - 0x00, 0x6a, 0x98, 0x5d, + 0x00, 0x6a, 0x84, 0x5d, 0x00, 0x65, 0x4c, 0x41, 0x10, 0x3c, 0xa8, 0x69, - 0x00, 0xbb, 0x9e, 0x44, + 0x00, 0xbb, 0x8a, 0x44, 0x18, 0x6a, 0xda, 0x01, 0x01, 0x69, 0xd8, 0x31, 0x1c, 0x6a, 0xd0, 0x01, @@ -227,23 +227,23 @@ static uint8_t seqprog[] = { 0x01, 0x93, 0x26, 0x01, 0x03, 0x6a, 0x2a, 0x01, 0x01, 0x69, 0x32, 0x31, - 0x1c, 0x6a, 0xf4, 0x5d, + 0x1c, 0x6a, 0xe0, 0x5d, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xbc, 0x5e, + 0x00, 0x65, 0xa8, 0x5e, 0x01, 0x50, 0xa0, 0x18, 0x02, 0x6a, 0x22, 0x05, 0x1a, 0x01, 0x02, 0x00, 0x80, 0x6a, 0x74, 0x00, 0x40, 0x6a, 0x78, 0x00, 0x40, 0x6a, 0x16, 0x00, - 0x00, 0x65, 0xec, 0x5d, + 0x00, 0x65, 0xd8, 0x5d, 0x01, 0x3f, 0xc8, 0x30, - 0xbf, 0x64, 0x5e, 0x7a, - 0x80, 0x64, 0xb2, 0x73, - 0xa0, 0x64, 0x14, 0x74, - 0xc0, 0x64, 0x08, 0x74, - 0xe0, 0x64, 0x44, 0x74, - 0x01, 0x6a, 0xec, 0x5e, + 0xbf, 0x64, 0x56, 0x7a, + 0x80, 0x64, 0x9e, 0x73, + 0xa0, 0x64, 0x00, 0x74, + 0xc0, 0x64, 0xf4, 0x73, + 0xe0, 0x64, 0x30, 0x74, + 0x01, 0x6a, 0xd8, 0x5e, 0x00, 0x65, 0xcc, 0x41, 0xf7, 0x11, 0x22, 0x08, 0x01, 0x06, 0xd4, 0x30, @@ -251,7 +251,7 @@ static uint8_t seqprog[] = { 0xf7, 0x01, 0x02, 0x08, 0x09, 0x0c, 0xe6, 0x79, 0x08, 0x0c, 0x04, 0x68, - 0xb1, 0x6a, 0xec, 0x5e, + 0xb1, 0x6a, 0xd8, 0x5e, 0xff, 0x6a, 0x26, 0x09, 0x12, 0x01, 0x02, 0x00, 0x02, 0x6a, 0x08, 0x30, @@ -264,33 +264,29 @@ static uint8_t seqprog[] = { 0x00, 0xa5, 0x4a, 0x21, 0x00, 0xa6, 0x4c, 0x21, 0x00, 0xa7, 0x4e, 0x25, - 0x08, 0xeb, 0xf0, 0x7e, + 0x08, 0xeb, 0xdc, 0x7e, 0x80, 0xeb, 0x06, 0x7a, 0xff, 0x6a, 0xd6, 0x09, 0x08, 0xeb, 0x0a, 0x6a, 0xff, 0x6a, 0xd4, 0x0c, - 0x80, 0xa3, 0xf0, 0x6e, + 0x80, 0xa3, 0xdc, 0x6e, 0x88, 0xeb, 0x20, 0x72, - 0x08, 0xeb, 0xf0, 0x6e, + 0x08, 0xeb, 0xdc, 0x6e, 0x04, 0xea, 0x24, 0xe2, - 0x08, 0xee, 0xf0, 0x6e, + 0x08, 0xee, 0xdc, 0x6e, 0x04, 0x6a, 0xd0, 0x81, 0x05, 0xa4, 0xc0, 0x89, 0x03, 0xa5, 0xc2, 0x31, 0x09, 0x6a, 0xd6, 0x05, 0x00, 0x65, 0x08, 0x5a, 0x06, 0xa4, 0xd4, 0x89, - 0x80, 0x94, 0xf0, 0x7e, + 0x80, 0x94, 0xdc, 0x7e, 0x07, 0xe9, 0x10, 0x31, - 0x01, 0x8c, 0x2c, 0x7a, - 0x01, 0x55, 0xaa, 0x10, 0x01, 0xe9, 0x46, 0x31, - 0x00, 0xa3, 0xce, 0x5e, + 0x00, 0xa3, 0xba, 0x5e, 0x00, 0x65, 0xfa, 0x59, 0x01, 0xa4, 0xca, 0x30, - 0x01, 0x55, 0x38, 0x7a, - 0x04, 0x65, 0xca, 0x00, - 0x80, 0xa3, 0x3c, 0x7a, + 0x80, 0xa3, 0x34, 0x7a, 0x02, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x80, 0x93, 0x26, 0x01, @@ -298,168 +294,162 @@ static uint8_t seqprog[] = { 0x01, 0x8c, 0xc8, 0x30, 0x00, 0x88, 0xc8, 0x18, 0x02, 0x64, 0xc8, 0x88, - 0xff, 0x64, 0xf0, 0x7e, - 0xff, 0x8d, 0x52, 0x6a, - 0xff, 0x8e, 0x52, 0x6a, + 0xff, 0x64, 0xdc, 0x7e, + 0xff, 0x8d, 0x4a, 0x6a, + 0xff, 0x8e, 0x4a, 0x6a, 0x03, 0x8c, 0xd4, 0x98, - 0x00, 0x65, 0xf0, 0x56, + 0x00, 0x65, 0xdc, 0x56, 0x01, 0x64, 0x70, 0x30, 0xff, 0x64, 0xc8, 0x10, 0x01, 0x64, 0xc8, 0x18, 0x00, 0x8c, 0x18, 0x19, 0xff, 0x8d, 0x1a, 0x21, 0xff, 0x8e, 0x1c, 0x25, - 0xc0, 0x3c, 0x62, 0x7a, - 0x21, 0x6a, 0xec, 0x5e, + 0xc0, 0x3c, 0x5a, 0x7a, + 0x21, 0x6a, 0xd8, 0x5e, 0xa8, 0x6a, 0x76, 0x00, 0x79, 0x6a, 0x76, 0x00, - 0x40, 0x3f, 0x6a, 0x6a, + 0x40, 0x3f, 0x62, 0x6a, 0x04, 0x3b, 0x76, 0x00, 0x04, 0x6a, 0xd4, 0x81, - 0x20, 0x3c, 0x72, 0x7a, - 0x51, 0x6a, 0xec, 0x5e, - 0x00, 0x65, 0x8c, 0x42, + 0x20, 0x3c, 0x6a, 0x7a, + 0x51, 0x6a, 0xd8, 0x5e, + 0x00, 0x65, 0x82, 0x42, 0x20, 0x3c, 0x78, 0x00, - 0x00, 0xb3, 0xce, 0x5e, + 0x00, 0xb3, 0xba, 0x5e, 0x07, 0xac, 0x10, 0x31, 0x05, 0xb3, 0x46, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0x02, 0x5e, + 0xac, 0x6a, 0xee, 0x5d, 0xa3, 0x6a, 0xcc, 0x00, - 0xb3, 0x6a, 0x06, 0x5e, - 0x00, 0x65, 0x42, 0x5a, + 0xb3, 0x6a, 0xf2, 0x5d, + 0x00, 0x65, 0x3a, 0x5a, 0xfd, 0xa4, 0x48, 0x09, - 0x01, 0x8c, 0xaa, 0x08, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xfa, 0x5d, - 0x01, 0xa4, 0x9e, 0x7a, + 0x00, 0x65, 0xe6, 0x5d, + 0x01, 0xa4, 0x94, 0x7a, 0x04, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, 0x80, 0x02, 0x04, 0x00, - 0x10, 0x0c, 0x94, 0x7a, - 0x03, 0x9e, 0x96, 0x6a, + 0x10, 0x0c, 0x8a, 0x7a, + 0x03, 0x9e, 0x8c, 0x6a, 0x7f, 0x02, 0x04, 0x08, - 0x91, 0x6a, 0xec, 0x5e, + 0x91, 0x6a, 0xd8, 0x5e, 0x00, 0x65, 0xcc, 0x41, 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0xa4, 0x7a, + 0x80, 0xa3, 0x9a, 0x7a, 0x02, 0x65, 0xca, 0x00, - 0x01, 0x55, 0xa8, 0x7a, - 0x04, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x01, 0x3b, 0x26, 0x31, 0x00, 0x65, 0x0e, 0x5a, - 0x01, 0xfc, 0xb6, 0x6a, - 0x80, 0x0b, 0xac, 0x6a, - 0x10, 0x0c, 0xac, 0x7a, - 0x20, 0x93, 0xac, 0x6a, + 0x01, 0xfc, 0xa8, 0x6a, + 0x80, 0x0b, 0x9e, 0x6a, + 0x10, 0x0c, 0x9e, 0x7a, + 0x20, 0x93, 0x9e, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x02, 0xfc, 0xc0, 0x7a, - 0x40, 0x0d, 0xda, 0x6a, - 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0xda, 0x42, + 0x02, 0xfc, 0xb2, 0x7a, 0x40, 0x0d, 0xc6, 0x6a, + 0x01, 0xa4, 0x48, 0x01, + 0x00, 0x65, 0xc6, 0x42, + 0x40, 0x0d, 0xb8, 0x6a, 0x00, 0x65, 0x0e, 0x5a, - 0x00, 0x65, 0xb8, 0x42, - 0x80, 0xfc, 0xd0, 0x7a, - 0x80, 0xa4, 0xd0, 0x6a, + 0x00, 0x65, 0xaa, 0x42, + 0x80, 0xfc, 0xc2, 0x7a, + 0x80, 0xa4, 0xc2, 0x6a, 0xff, 0xa5, 0x4a, 0x19, 0xff, 0xa6, 0x4c, 0x21, 0xff, 0xa7, 0x4e, 0x21, 0xf8, 0xfc, 0x48, 0x09, - 0xff, 0x6a, 0xaa, 0x08, - 0x04, 0xfc, 0xd8, 0x7a, - 0x01, 0x55, 0xaa, 0x00, - 0xff, 0x6a, 0x46, 0x09, - 0x04, 0x3b, 0xf2, 0x6a, + 0x7f, 0xa3, 0x46, 0x09, + 0x04, 0x3b, 0xe2, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0xdc, 0x7a, - 0x01, 0x94, 0xdc, 0x7a, - 0x01, 0x94, 0xdc, 0x7a, - 0x01, 0x94, 0xdc, 0x7a, - 0x01, 0x94, 0xdc, 0x7a, - 0x01, 0xa4, 0xf0, 0x7a, - 0x01, 0xfc, 0xea, 0x7a, - 0x01, 0x94, 0xf2, 0x6a, - 0x00, 0x65, 0x8c, 0x42, - 0x01, 0x94, 0xf0, 0x7a, - 0x10, 0x94, 0xf2, 0x6a, + 0x01, 0x94, 0xc8, 0x7a, + 0x01, 0x94, 0xc8, 0x7a, + 0x01, 0x94, 0xc8, 0x7a, + 0x01, 0x94, 0xc8, 0x7a, + 0x01, 0x94, 0xc8, 0x7a, + 0x01, 0xa4, 0xe0, 0x7a, + 0x01, 0xfc, 0xd6, 0x7a, + 0x01, 0x94, 0xe2, 0x6a, + 0x01, 0x94, 0xe2, 0x6a, + 0x01, 0x94, 0xe2, 0x6a, + 0x00, 0x65, 0x82, 0x42, + 0x01, 0x94, 0xe0, 0x7a, + 0x10, 0x94, 0xe2, 0x6a, 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xf6, 0x6a, + 0x28, 0x93, 0xe6, 0x6a, 0x01, 0x85, 0x0a, 0x01, - 0x02, 0xfc, 0xfe, 0x6a, + 0x02, 0xfc, 0xee, 0x6a, 0x01, 0x14, 0x46, 0x31, 0xff, 0x6a, 0x10, 0x09, 0xfe, 0x85, 0x0a, 0x09, - 0xff, 0x38, 0x0c, 0x6b, - 0x80, 0xa3, 0x0c, 0x7b, - 0x80, 0x0b, 0x0a, 0x7b, - 0x04, 0x3b, 0x0c, 0x7b, + 0xff, 0x38, 0xfc, 0x6a, + 0x80, 0xa3, 0xfc, 0x7a, + 0x80, 0x0b, 0xfa, 0x7a, + 0x04, 0x3b, 0xfc, 0x7a, 0xbf, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, 0x00, 0x65, 0x0e, 0x5a, - 0x01, 0x0b, 0x1a, 0x6b, - 0x10, 0x0c, 0x0e, 0x7b, - 0x04, 0x93, 0x18, 0x6b, - 0x01, 0x94, 0x16, 0x7b, - 0x10, 0x94, 0x18, 0x6b, + 0x01, 0x0b, 0x0a, 0x6b, + 0x10, 0x0c, 0xfe, 0x7a, + 0x04, 0x93, 0x08, 0x6b, + 0x01, 0x94, 0x06, 0x7b, + 0x10, 0x94, 0x08, 0x6b, 0xc7, 0x93, 0x26, 0x09, 0x01, 0x99, 0xd4, 0x30, - 0x38, 0x93, 0x1c, 0x6b, - 0xff, 0x08, 0x6e, 0x6b, - 0xff, 0x09, 0x6e, 0x6b, - 0xff, 0x0a, 0x6e, 0x6b, - 0xff, 0x38, 0x38, 0x7b, + 0x38, 0x93, 0x0c, 0x6b, + 0xff, 0x08, 0x5a, 0x6b, + 0xff, 0x09, 0x5a, 0x6b, + 0xff, 0x0a, 0x5a, 0x6b, + 0xff, 0x38, 0x28, 0x7b, 0x04, 0x14, 0x10, 0x31, 0x01, 0x38, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0x08, 0x5e, - 0x00, 0x38, 0xf4, 0x5d, + 0x14, 0x6a, 0xf4, 0x5d, + 0x00, 0x38, 0xe0, 0x5d, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x64, 0x43, - 0x80, 0xa3, 0x3e, 0x7b, + 0x00, 0x65, 0x54, 0x43, + 0x80, 0xa3, 0x2e, 0x7b, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x6e, 0x43, - 0x08, 0xeb, 0x44, 0x7b, + 0x00, 0x65, 0x5a, 0x43, + 0x08, 0xeb, 0x34, 0x7b, 0x00, 0x65, 0x0e, 0x5a, - 0x08, 0xeb, 0x40, 0x6b, + 0x08, 0xeb, 0x30, 0x6b, 0x07, 0xe9, 0x10, 0x31, 0x01, 0xe9, 0xca, 0x30, 0x01, 0x65, 0x46, 0x31, - 0x00, 0x6a, 0xce, 0x5e, + 0x00, 0x6a, 0xba, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0xa4, 0x6a, 0x08, 0x5e, - 0x08, 0x6a, 0xf4, 0x5d, + 0xa4, 0x6a, 0xf4, 0x5d, + 0x08, 0x6a, 0xe0, 0x5d, 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xbc, 0x5e, + 0x00, 0x65, 0xa8, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0x00, 0x65, 0x9e, 0x5e, + 0x00, 0x65, 0x8a, 0x5e, 0x01, 0x99, 0x46, 0x31, - 0x00, 0xa3, 0xce, 0x5e, + 0x00, 0xa3, 0xba, 0x5e, 0x01, 0x88, 0x10, 0x31, - 0x00, 0x65, 0x42, 0x5a, + 0x00, 0x65, 0x3a, 0x5a, 0x00, 0x65, 0xfa, 0x59, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xfa, 0x5d, - 0x01, 0x8c, 0x6c, 0x7b, - 0x01, 0x55, 0xaa, 0x10, - 0x80, 0x0b, 0x8c, 0x6a, - 0x80, 0x0b, 0x76, 0x6b, - 0x01, 0x0c, 0x70, 0x7b, - 0x10, 0x0c, 0x8c, 0x7a, - 0x03, 0x9e, 0x8c, 0x6a, + 0x00, 0x65, 0xe6, 0x5d, + 0x80, 0x0b, 0x82, 0x6a, + 0x80, 0x0b, 0x62, 0x6b, + 0x01, 0x0c, 0x5c, 0x7b, + 0x10, 0x0c, 0x82, 0x7a, + 0x03, 0x9e, 0x82, 0x6a, 0x00, 0x65, 0x04, 0x5a, - 0x00, 0x6a, 0xce, 0x5e, - 0x01, 0xa4, 0x96, 0x6b, - 0xff, 0x38, 0x8c, 0x7b, + 0x00, 0x6a, 0xba, 0x5e, + 0x01, 0xa4, 0x82, 0x6b, + 0xff, 0x38, 0x78, 0x7b, 0x01, 0x38, 0xc8, 0x30, 0x00, 0x08, 0x40, 0x19, 0xff, 0x6a, 0xc8, 0x08, 0x00, 0x09, 0x42, 0x21, 0x00, 0x0a, 0x44, 0x21, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x8e, 0x43, + 0x00, 0x65, 0x7a, 0x43, 0x03, 0x08, 0x40, 0x31, 0x03, 0x08, 0x40, 0x31, 0x01, 0x08, 0x40, 0x31, @@ -471,16 +461,16 @@ static uint8_t seqprog[] = { 0x04, 0x3c, 0xcc, 0x79, 0xfb, 0x3c, 0x78, 0x08, 0x04, 0x93, 0x20, 0x79, - 0x01, 0x0c, 0xa2, 0x6b, - 0x01, 0x55, 0x20, 0x79, + 0x01, 0x0c, 0x8e, 0x6b, + 0x80, 0xba, 0x20, 0x79, 0x80, 0x04, 0x20, 0x79, - 0xe4, 0x6a, 0x82, 0x5d, - 0x23, 0x6a, 0x98, 0x5d, - 0x01, 0x6a, 0x98, 0x5d, + 0xe4, 0x6a, 0x6e, 0x5d, + 0x23, 0x6a, 0x84, 0x5d, + 0x01, 0x6a, 0x84, 0x5d, 0x00, 0x65, 0x20, 0x41, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0x3c, 0xb6, 0x7b, - 0x21, 0x6a, 0xec, 0x5e, + 0x80, 0x3c, 0xa2, 0x7b, + 0x21, 0x6a, 0xd8, 0x5e, 0x01, 0xbc, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x02, 0x6a, 0xf8, 0x01, @@ -490,16 +480,16 @@ static uint8_t seqprog[] = { 0xff, 0x6a, 0x12, 0x08, 0xff, 0x6a, 0x14, 0x08, 0xf3, 0xbc, 0xd4, 0x18, - 0xa0, 0x6a, 0xdc, 0x53, + 0xa0, 0x6a, 0xc8, 0x53, 0x04, 0xa0, 0x10, 0x31, 0xac, 0x6a, 0x26, 0x01, 0x04, 0xa0, 0x10, 0x31, 0x03, 0x08, 0x18, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0x08, 0x5e, - 0x00, 0xbc, 0xf4, 0x5d, + 0xa0, 0x6a, 0xf4, 0x5d, + 0x00, 0xbc, 0xe0, 0x5d, 0x3d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0xf4, 0x43, + 0x00, 0x65, 0xe0, 0x43, 0xff, 0x6a, 0x10, 0x09, 0xa4, 0x6a, 0x26, 0x01, 0x0c, 0xa0, 0x32, 0x31, @@ -509,128 +499,128 @@ static uint8_t seqprog[] = { 0x36, 0x6a, 0x26, 0x01, 0x02, 0x93, 0x26, 0x01, 0x35, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0xb0, 0x5e, - 0x00, 0x65, 0xb0, 0x5e, + 0x00, 0x65, 0x9c, 0x5e, + 0x00, 0x65, 0x9c, 0x5e, 0x02, 0x93, 0x26, 0x01, 0xbf, 0x3c, 0x78, 0x08, - 0x04, 0x0b, 0xfa, 0x6b, - 0x10, 0x0c, 0xf6, 0x7b, - 0x01, 0x03, 0xfa, 0x6b, - 0x20, 0x93, 0xfc, 0x6b, - 0x04, 0x0b, 0x02, 0x6c, + 0x04, 0x0b, 0xe6, 0x6b, + 0x10, 0x0c, 0xe2, 0x7b, + 0x01, 0x03, 0xe6, 0x6b, + 0x20, 0x93, 0xe8, 0x6b, + 0x04, 0x0b, 0xee, 0x6b, 0x40, 0x3c, 0x78, 0x00, 0xc7, 0x93, 0x26, 0x09, - 0x38, 0x93, 0x04, 0x6c, + 0x38, 0x93, 0xf0, 0x6b, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0x3c, 0x6a, 0x6c, + 0x80, 0x3c, 0x56, 0x6c, 0x01, 0x06, 0x50, 0x31, 0x80, 0xb8, 0x70, 0x01, 0x00, 0x65, 0xcc, 0x41, 0x10, 0x3f, 0x06, 0x00, 0x10, 0x6a, 0x06, 0x00, 0x01, 0x3a, 0xca, 0x30, - 0x80, 0x65, 0x30, 0x64, - 0x10, 0xb8, 0x54, 0x6c, - 0xc0, 0xba, 0xca, 0x00, - 0x40, 0xb8, 0x20, 0x6c, + 0x80, 0x65, 0x1c, 0x64, + 0x10, 0xb8, 0x40, 0x6c, + 0xc0, 0x3e, 0xca, 0x00, + 0x40, 0xb8, 0x0c, 0x6c, 0xbf, 0x65, 0xca, 0x08, - 0x20, 0xb8, 0x34, 0x7c, + 0x20, 0xb8, 0x20, 0x7c, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xec, 0x5d, - 0xa0, 0x3f, 0x3c, 0x64, + 0x00, 0x65, 0xd8, 0x5d, + 0xa0, 0x3f, 0x28, 0x64, 0x23, 0xb8, 0x0c, 0x08, - 0x00, 0x65, 0xec, 0x5d, - 0xa0, 0x3f, 0x3c, 0x64, - 0x00, 0xbb, 0x34, 0x44, - 0xff, 0x65, 0x34, 0x64, - 0x00, 0x65, 0x54, 0x44, + 0x00, 0x65, 0xd8, 0x5d, + 0xa0, 0x3f, 0x28, 0x64, + 0x00, 0xbb, 0x20, 0x44, + 0xff, 0x65, 0x20, 0x64, + 0x00, 0x65, 0x40, 0x44, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xec, 0x5d, - 0xa0, 0x3f, 0x10, 0x74, + 0x00, 0x65, 0xd8, 0x5d, + 0xa0, 0x3f, 0xfc, 0x73, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x3a, 0xa6, 0x30, 0x08, 0x6a, 0x74, 0x00, 0x00, 0x65, 0xcc, 0x41, - 0x64, 0x6a, 0x7c, 0x5d, - 0x80, 0x64, 0xec, 0x6c, - 0x04, 0x64, 0xae, 0x74, - 0x02, 0x64, 0xbe, 0x74, - 0x00, 0x6a, 0x74, 0x74, - 0x03, 0x64, 0xdc, 0x74, - 0x23, 0x64, 0x5c, 0x74, - 0x08, 0x64, 0x70, 0x74, - 0x61, 0x6a, 0xec, 0x5e, - 0x00, 0x65, 0xec, 0x5d, + 0x64, 0x6a, 0x68, 0x5d, + 0x80, 0x64, 0xd8, 0x6c, + 0x04, 0x64, 0x9a, 0x74, + 0x02, 0x64, 0xaa, 0x74, + 0x00, 0x6a, 0x60, 0x74, + 0x03, 0x64, 0xc8, 0x74, + 0x23, 0x64, 0x48, 0x74, + 0x08, 0x64, 0x5c, 0x74, + 0x61, 0x6a, 0xd8, 0x5e, + 0x00, 0x65, 0xd8, 0x5d, 0x08, 0x51, 0xce, 0x71, - 0x00, 0x65, 0x54, 0x44, - 0x80, 0x04, 0x6e, 0x7c, - 0x51, 0x6a, 0x72, 0x5d, - 0x01, 0x51, 0x6e, 0x64, - 0x01, 0xa4, 0x66, 0x7c, - 0x01, 0x55, 0x70, 0x7c, - 0x41, 0x6a, 0xec, 0x5e, - 0x00, 0x65, 0x70, 0x44, - 0x21, 0x6a, 0xec, 0x5e, - 0x00, 0x65, 0x70, 0x44, - 0x07, 0x6a, 0x68, 0x5d, + 0x00, 0x65, 0x40, 0x44, + 0x80, 0x04, 0x5a, 0x7c, + 0x51, 0x6a, 0x5e, 0x5d, + 0x01, 0x51, 0x5a, 0x64, + 0x01, 0xa4, 0x52, 0x7c, + 0x80, 0xba, 0x5c, 0x6c, + 0x41, 0x6a, 0xd8, 0x5e, + 0x00, 0x65, 0x5c, 0x44, + 0x21, 0x6a, 0xd8, 0x5e, + 0x00, 0x65, 0x5c, 0x44, + 0x07, 0x6a, 0x54, 0x5d, 0x01, 0x06, 0xd4, 0x30, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0xb8, 0x6a, 0x7c, - 0xc0, 0x3c, 0x7e, 0x7c, - 0x80, 0x3c, 0x6a, 0x6c, - 0xff, 0xa8, 0x7e, 0x6c, - 0x40, 0x3c, 0x6a, 0x6c, - 0x10, 0xb8, 0x82, 0x7c, - 0xa1, 0x6a, 0xec, 0x5e, - 0x01, 0xb4, 0x88, 0x6c, - 0x02, 0xb4, 0x8a, 0x6c, - 0x01, 0xa4, 0x8a, 0x7c, - 0xff, 0xa8, 0x9a, 0x7c, + 0x80, 0xb8, 0x56, 0x7c, + 0xc0, 0x3c, 0x6a, 0x7c, + 0x80, 0x3c, 0x56, 0x6c, + 0xff, 0xa8, 0x6a, 0x6c, + 0x40, 0x3c, 0x56, 0x6c, + 0x10, 0xb8, 0x6e, 0x7c, + 0xa1, 0x6a, 0xd8, 0x5e, + 0x01, 0xb4, 0x74, 0x6c, + 0x02, 0xb4, 0x76, 0x6c, + 0x01, 0xa4, 0x76, 0x7c, + 0xff, 0xa8, 0x86, 0x7c, 0x04, 0xb4, 0x68, 0x01, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0x26, 0x5e, - 0xff, 0xa8, 0x9a, 0x7c, - 0x71, 0x6a, 0xec, 0x5e, - 0x40, 0x51, 0x9a, 0x64, - 0x00, 0x65, 0xc6, 0x5e, + 0x00, 0xbb, 0x12, 0x5e, + 0xff, 0xa8, 0x86, 0x7c, + 0x71, 0x6a, 0xd8, 0x5e, + 0x40, 0x51, 0x86, 0x64, + 0x00, 0x65, 0xb2, 0x5e, 0x00, 0x65, 0xde, 0x41, - 0x00, 0xbb, 0x9e, 0x5c, + 0x00, 0xbb, 0x8a, 0x5c, 0x00, 0x65, 0xde, 0x41, - 0x00, 0x65, 0xc6, 0x5e, + 0x00, 0x65, 0xb2, 0x5e, 0x01, 0x65, 0xa2, 0x30, 0x01, 0xf8, 0xc8, 0x30, 0x01, 0x4e, 0xc8, 0x30, - 0x00, 0x6a, 0xca, 0xdd, - 0x00, 0x51, 0xdc, 0x5d, + 0x00, 0x6a, 0xb6, 0xdd, + 0x00, 0x51, 0xc8, 0x5d, 0x01, 0x4e, 0x9c, 0x18, 0x02, 0x6a, 0x22, 0x05, - 0xc0, 0x3c, 0x6a, 0x6c, + 0xc0, 0x3c, 0x56, 0x6c, 0x04, 0xb8, 0x70, 0x01, - 0x00, 0x65, 0xe8, 0x5e, + 0x00, 0x65, 0xd4, 0x5e, 0x20, 0xb8, 0xde, 0x69, 0x01, 0xbb, 0xa2, 0x30, - 0x01, 0xba, 0x7c, 0x30, - 0x00, 0xb9, 0xe2, 0x5c, + 0x3f, 0xba, 0x7c, 0x08, + 0x00, 0xb9, 0xce, 0x5c, 0x00, 0x65, 0xde, 0x41, 0x01, 0x06, 0xd4, 0x30, 0x20, 0x3c, 0xcc, 0x79, - 0x20, 0x3c, 0x70, 0x7c, - 0x01, 0xa4, 0xcc, 0x7c, + 0x20, 0x3c, 0x5c, 0x7c, + 0x01, 0xa4, 0xb8, 0x7c, 0x01, 0xb4, 0x68, 0x01, 0x00, 0x65, 0xcc, 0x41, - 0x00, 0x65, 0x70, 0x44, + 0x00, 0x65, 0x5c, 0x44, 0x04, 0x14, 0x58, 0x31, 0x01, 0x06, 0xd4, 0x30, 0x08, 0xa0, 0x60, 0x31, 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0x08, 0x5e, + 0x14, 0x6a, 0xf4, 0x5d, 0x01, 0x06, 0xd4, 0x30, - 0xa0, 0x6a, 0x00, 0x5e, + 0xa0, 0x6a, 0xec, 0x5d, 0x00, 0x65, 0xcc, 0x41, 0xdf, 0x3c, 0x78, 0x08, 0x12, 0x01, 0x02, 0x00, - 0x00, 0x65, 0x70, 0x44, + 0x00, 0x65, 0x5c, 0x44, 0x4c, 0x65, 0xcc, 0x28, 0x01, 0x3e, 0x20, 0x31, 0xd0, 0x66, 0xcc, 0x18, @@ -641,102 +631,102 @@ static uint8_t seqprog[] = { 0xd0, 0x65, 0xca, 0x18, 0x01, 0x3e, 0x20, 0x31, 0x30, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xfa, 0x4c, + 0x00, 0x65, 0xe6, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0x02, 0x55, + 0x00, 0x65, 0xee, 0x54, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xca, 0x18, 0xe0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0x0c, 0x4d, + 0x00, 0x65, 0xf8, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0xd0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0x14, 0x55, + 0x00, 0x65, 0x00, 0x55, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x01, 0x6c, 0xa2, 0x30, - 0xff, 0x51, 0x26, 0x75, - 0x00, 0x51, 0xa2, 0x5d, + 0xff, 0x51, 0x12, 0x75, + 0x00, 0x51, 0x8e, 0x5d, 0x01, 0x51, 0x20, 0x31, - 0x00, 0x65, 0x48, 0x45, - 0x01, 0xba, 0xc8, 0x30, - 0x00, 0x3e, 0x48, 0x75, - 0x00, 0x65, 0xc4, 0x5e, + 0x00, 0x65, 0x34, 0x45, + 0x3f, 0xba, 0xc8, 0x08, + 0x00, 0x3e, 0x34, 0x75, + 0x00, 0x65, 0xb0, 0x5e, 0x80, 0x3c, 0x78, 0x00, 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xec, 0x5d, + 0x00, 0x65, 0xd8, 0x5d, 0x01, 0x3c, 0x78, 0x00, - 0xe0, 0x3f, 0x64, 0x65, + 0xe0, 0x3f, 0x50, 0x65, 0x02, 0x3c, 0x78, 0x00, - 0x20, 0x12, 0x64, 0x65, - 0x51, 0x6a, 0x72, 0x5d, - 0x00, 0x51, 0xa2, 0x5d, - 0x51, 0x6a, 0x72, 0x5d, + 0x20, 0x12, 0x50, 0x65, + 0x51, 0x6a, 0x5e, 0x5d, + 0x00, 0x51, 0x8e, 0x5d, + 0x51, 0x6a, 0x5e, 0x5d, 0x01, 0x51, 0x20, 0x31, 0x04, 0x3c, 0x78, 0x00, 0x01, 0xb9, 0xc8, 0x30, - 0x00, 0x3d, 0x62, 0x65, + 0x00, 0x3d, 0x4e, 0x65, 0x08, 0x3c, 0x78, 0x00, - 0x01, 0xba, 0xc8, 0x30, - 0x00, 0x3e, 0x62, 0x65, + 0x3f, 0xba, 0xc8, 0x08, + 0x00, 0x3e, 0x4e, 0x65, 0x10, 0x3c, 0x78, 0x00, - 0x04, 0xb8, 0x62, 0x7d, + 0x04, 0xb8, 0x4e, 0x7d, 0xfb, 0xb8, 0x70, 0x09, - 0x20, 0xb8, 0x58, 0x6d, + 0x20, 0xb8, 0x44, 0x6d, 0x01, 0x90, 0xc8, 0x30, 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3d, 0xe2, 0x5c, + 0x00, 0x3d, 0xce, 0x5c, 0x01, 0x64, 0x20, 0x31, 0xff, 0x6a, 0x78, 0x08, 0x00, 0x65, 0xea, 0x58, - 0x10, 0xb8, 0x70, 0x7c, - 0xff, 0x6a, 0x68, 0x5d, - 0x00, 0x65, 0x70, 0x44, - 0x00, 0x65, 0xc4, 0x5e, - 0x31, 0x6a, 0xec, 0x5e, - 0x00, 0x65, 0x70, 0x44, + 0x10, 0xb8, 0x5c, 0x7c, + 0xff, 0x6a, 0x54, 0x5d, + 0x00, 0x65, 0x5c, 0x44, + 0x00, 0x65, 0xb0, 0x5e, + 0x31, 0x6a, 0xd8, 0x5e, + 0x00, 0x65, 0x5c, 0x44, 0x10, 0x3f, 0x06, 0x00, 0x10, 0x6a, 0x06, 0x00, 0x01, 0x65, 0x74, 0x34, - 0x81, 0x6a, 0xec, 0x5e, - 0x00, 0x65, 0x74, 0x45, + 0x81, 0x6a, 0xd8, 0x5e, + 0x00, 0x65, 0x60, 0x45, 0x01, 0x06, 0xd4, 0x30, - 0x01, 0x0c, 0x74, 0x7d, - 0x04, 0x0c, 0x6e, 0x6d, + 0x01, 0x0c, 0x60, 0x7d, + 0x04, 0x0c, 0x5a, 0x6d, 0xe0, 0x03, 0x7e, 0x08, 0xe0, 0x3f, 0xcc, 0x61, 0x01, 0x65, 0xcc, 0x30, 0x01, 0x12, 0xda, 0x34, 0x01, 0x06, 0xd4, 0x34, - 0x01, 0x03, 0x82, 0x6d, + 0x01, 0x03, 0x6e, 0x6d, 0x40, 0x03, 0xcc, 0x08, 0x01, 0x65, 0x06, 0x30, 0x40, 0x65, 0xc8, 0x08, - 0x00, 0x66, 0x90, 0x75, - 0x40, 0x65, 0x90, 0x7d, - 0x00, 0x65, 0x90, 0x5d, + 0x00, 0x66, 0x7c, 0x75, + 0x40, 0x65, 0x7c, 0x7d, + 0x00, 0x65, 0x7c, 0x5d, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x0c, 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x9a, 0x7d, + 0x02, 0x0b, 0x86, 0x7d, 0x01, 0x65, 0x0c, 0x30, - 0x02, 0x0b, 0x9e, 0x7d, + 0x02, 0x0b, 0x8a, 0x7d, 0xf7, 0x01, 0x02, 0x0c, 0x01, 0x65, 0xc8, 0x30, - 0xff, 0x41, 0xc2, 0x75, + 0xff, 0x41, 0xae, 0x75, 0x01, 0x41, 0x20, 0x31, 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0xb2, 0x45, - 0xff, 0xbf, 0xc2, 0x75, + 0x00, 0x65, 0x9e, 0x45, + 0xff, 0xbf, 0xae, 0x75, 0x01, 0x90, 0xa4, 0x30, 0x01, 0xbf, 0x20, 0x31, - 0x00, 0xbb, 0xac, 0x65, - 0xff, 0x52, 0xc0, 0x75, + 0x00, 0xbb, 0x98, 0x65, + 0xff, 0x52, 0xac, 0x75, 0x01, 0xbf, 0xcc, 0x30, 0x01, 0x90, 0xca, 0x30, 0x01, 0x52, 0x20, 0x31, @@ -744,28 +734,28 @@ static uint8_t seqprog[] = { 0x01, 0x65, 0x20, 0x35, 0x01, 0xbf, 0x82, 0x34, 0x01, 0x64, 0xa2, 0x30, - 0x00, 0x6a, 0xd4, 0x5e, + 0x00, 0x6a, 0xc0, 0x5e, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0x26, 0x46, + 0x00, 0x51, 0x12, 0x46, 0x01, 0x65, 0xa4, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x1a, 0x5e, + 0x48, 0x6a, 0x06, 0x5e, 0x01, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x05, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x1a, 0x5e, - 0x01, 0x6a, 0xf4, 0x5d, + 0x48, 0x6a, 0x06, 0x5e, + 0x01, 0x6a, 0xe0, 0x5d, 0x01, 0x6a, 0x26, 0x05, 0x01, 0x65, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xe0, 0x7d, + 0x80, 0xee, 0xcc, 0x7d, 0xff, 0x6a, 0xdc, 0x0d, 0x01, 0x65, 0x32, 0x31, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xbc, 0x46, - 0x81, 0x6a, 0xec, 0x5e, - 0x01, 0x0c, 0xec, 0x7d, - 0x04, 0x0c, 0xea, 0x6d, + 0x00, 0x65, 0xa8, 0x46, + 0x81, 0x6a, 0xd8, 0x5e, + 0x01, 0x0c, 0xd8, 0x7d, + 0x04, 0x0c, 0xd6, 0x6d, 0xe0, 0x03, 0x06, 0x08, 0xe0, 0x03, 0x7e, 0x0c, 0x01, 0x65, 0x18, 0x31, @@ -784,7 +774,7 @@ static uint8_t seqprog[] = { 0x01, 0x6c, 0xda, 0x34, 0x3d, 0x64, 0xa4, 0x28, 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0x1a, 0x46, + 0x00, 0x65, 0x06, 0x46, 0x2e, 0x64, 0xa4, 0x28, 0x66, 0x64, 0xc8, 0x28, 0x00, 0x6c, 0xda, 0x18, @@ -795,63 +785,63 @@ static uint8_t seqprog[] = { 0x00, 0x6c, 0xda, 0x24, 0x01, 0x65, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0x16, 0x5e, + 0x44, 0x6a, 0x02, 0x5e, 0x01, 0x90, 0xe2, 0x31, - 0x04, 0x3b, 0x3a, 0x7e, + 0x04, 0x3b, 0x26, 0x7e, 0x30, 0x6a, 0xd0, 0x01, 0x20, 0x6a, 0xd0, 0x01, 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0x36, 0x66, - 0x00, 0x65, 0x52, 0x46, + 0xdc, 0xee, 0x22, 0x66, + 0x00, 0x65, 0x3e, 0x46, 0x20, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x01, 0x20, 0xa0, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x42, 0x7e, + 0x80, 0xee, 0x2e, 0x7e, 0x11, 0x6a, 0xdc, 0x01, - 0x50, 0xee, 0x46, 0x66, + 0x50, 0xee, 0x32, 0x66, 0x20, 0x6a, 0xd0, 0x01, 0x09, 0x6a, 0xdc, 0x01, - 0x88, 0xee, 0x4c, 0x66, + 0x88, 0xee, 0x38, 0x66, 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0x50, 0x66, + 0xd8, 0xee, 0x3c, 0x66, 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0x54, 0x6e, + 0x18, 0xee, 0x40, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, 0x88, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0x16, 0x5e, - 0x20, 0x6a, 0xf4, 0x5d, + 0x44, 0x6a, 0x02, 0x5e, + 0x20, 0x6a, 0xe0, 0x5d, 0x01, 0x3b, 0x26, 0x31, - 0x04, 0x3b, 0x6e, 0x6e, + 0x04, 0x3b, 0x5a, 0x6e, 0xa0, 0x6a, 0xca, 0x00, 0x20, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0xac, 0x5e, - 0x00, 0x65, 0x66, 0x66, + 0x00, 0x65, 0x98, 0x5e, + 0x00, 0x65, 0x52, 0x66, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xbc, 0x46, + 0x00, 0x65, 0xa8, 0x46, 0xa0, 0x6a, 0xcc, 0x00, 0xff, 0x6a, 0xc8, 0x08, - 0x20, 0x94, 0x72, 0x6e, - 0x10, 0x94, 0x74, 0x6e, - 0x08, 0x94, 0x8e, 0x6e, - 0x08, 0x94, 0x8e, 0x6e, - 0x08, 0x94, 0x8e, 0x6e, + 0x20, 0x94, 0x5e, 0x6e, + 0x10, 0x94, 0x60, 0x6e, + 0x08, 0x94, 0x7a, 0x6e, + 0x08, 0x94, 0x7a, 0x6e, + 0x08, 0x94, 0x7a, 0x6e, 0xff, 0x8c, 0xc8, 0x10, 0xc1, 0x64, 0xc8, 0x18, 0xf8, 0x64, 0xc8, 0x08, 0x01, 0x99, 0xda, 0x30, - 0x00, 0x66, 0x82, 0x66, - 0xc0, 0x66, 0xbe, 0x76, + 0x00, 0x66, 0x6e, 0x66, + 0xc0, 0x66, 0xaa, 0x76, 0x60, 0x66, 0xc8, 0x18, 0x3d, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0x72, 0x46, + 0x00, 0x65, 0x5e, 0x46, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x90, 0x6e, + 0x08, 0x93, 0x7c, 0x6e, 0x00, 0x62, 0xc4, 0x18, - 0x00, 0x65, 0xbc, 0x5e, - 0x00, 0x65, 0x9c, 0x5e, - 0x00, 0x65, 0x9c, 0x5e, - 0x00, 0x65, 0x9c, 0x5e, + 0x00, 0x65, 0xa8, 0x5e, + 0x00, 0x65, 0x88, 0x5e, + 0x00, 0x65, 0x88, 0x5e, + 0x00, 0x65, 0x88, 0x5e, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, @@ -868,11 +858,11 @@ static uint8_t seqprog[] = { 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x35, - 0x08, 0x94, 0xbc, 0x7e, + 0x08, 0x94, 0xa8, 0x7e, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0xc0, 0x6e, + 0x08, 0x93, 0xac, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, - 0x04, 0xb8, 0xe8, 0x6e, + 0x04, 0xb8, 0xd4, 0x6e, 0x01, 0x42, 0x7e, 0x31, 0xff, 0x6a, 0x76, 0x01, 0x01, 0x90, 0x84, 0x34, @@ -880,14 +870,14 @@ static uint8_t seqprog[] = { 0x01, 0x85, 0x0a, 0x01, 0x7f, 0x65, 0x10, 0x09, 0xfe, 0x85, 0x0a, 0x0d, - 0xff, 0x42, 0xe4, 0x66, - 0xff, 0x41, 0xdc, 0x66, - 0xd1, 0x6a, 0xec, 0x5e, + 0xff, 0x42, 0xd0, 0x66, + 0xff, 0x41, 0xc8, 0x66, + 0xd1, 0x6a, 0xd8, 0x5e, 0xff, 0x6a, 0xca, 0x04, 0x01, 0x41, 0x20, 0x31, 0x01, 0xbf, 0x82, 0x30, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0x26, 0x46, + 0x00, 0xbb, 0x12, 0x46, 0x01, 0x42, 0x20, 0x31, 0x01, 0xbf, 0x84, 0x34, 0x01, 0x41, 0x7e, 0x31, @@ -1157,147 +1147,147 @@ static struct patch { { ahc_patch1_func, 248, 1, 2 }, { ahc_patch0_func, 249, 2, 2 }, { ahc_patch11_func, 250, 1, 1 }, - { ahc_patch9_func, 258, 31, 3 }, - { ahc_patch1_func, 274, 14, 2 }, - { ahc_patch13_func, 279, 1, 1 }, - { ahc_patch14_func, 289, 14, 1 }, - { ahc_patch1_func, 305, 1, 2 }, - { ahc_patch0_func, 306, 1, 1 }, - { ahc_patch9_func, 309, 1, 1 }, - { ahc_patch13_func, 314, 1, 1 }, - { ahc_patch9_func, 315, 2, 2 }, - { ahc_patch0_func, 317, 4, 1 }, - { ahc_patch14_func, 321, 1, 1 }, - { ahc_patch15_func, 324, 2, 3 }, - { ahc_patch9_func, 324, 1, 2 }, - { ahc_patch0_func, 325, 1, 1 }, - { ahc_patch6_func, 330, 1, 2 }, - { ahc_patch0_func, 331, 1, 1 }, - { ahc_patch1_func, 335, 50, 11 }, - { ahc_patch6_func, 344, 2, 4 }, - { ahc_patch7_func, 344, 1, 1 }, - { ahc_patch8_func, 345, 1, 1 }, - { ahc_patch0_func, 346, 1, 1 }, - { ahc_patch16_func, 347, 1, 1 }, - { ahc_patch6_func, 366, 6, 3 }, - { ahc_patch16_func, 366, 5, 1 }, - { ahc_patch0_func, 372, 5, 1 }, - { ahc_patch13_func, 380, 5, 1 }, - { ahc_patch0_func, 385, 54, 17 }, - { ahc_patch14_func, 385, 1, 1 }, - { ahc_patch7_func, 387, 2, 2 }, - { ahc_patch17_func, 388, 1, 1 }, - { ahc_patch9_func, 391, 1, 1 }, - { ahc_patch18_func, 398, 1, 1 }, - { ahc_patch14_func, 403, 9, 3 }, - { ahc_patch9_func, 404, 3, 2 }, - { ahc_patch0_func, 407, 3, 1 }, - { ahc_patch9_func, 415, 6, 2 }, - { ahc_patch0_func, 421, 9, 2 }, - { ahc_patch13_func, 421, 1, 1 }, - { ahc_patch13_func, 430, 2, 1 }, - { ahc_patch14_func, 432, 1, 1 }, - { ahc_patch9_func, 434, 1, 2 }, - { ahc_patch0_func, 435, 1, 1 }, - { ahc_patch7_func, 438, 1, 1 }, - { ahc_patch7_func, 439, 1, 1 }, - { ahc_patch8_func, 440, 3, 3 }, - { ahc_patch6_func, 441, 1, 2 }, - { ahc_patch0_func, 442, 1, 1 }, - { ahc_patch9_func, 443, 1, 1 }, - { ahc_patch15_func, 444, 1, 2 }, - { ahc_patch13_func, 444, 1, 1 }, - { ahc_patch14_func, 446, 9, 4 }, - { ahc_patch9_func, 446, 1, 1 }, - { ahc_patch9_func, 453, 2, 1 }, - { ahc_patch0_func, 455, 4, 3 }, - { ahc_patch9_func, 455, 1, 2 }, - { ahc_patch0_func, 456, 3, 1 }, - { ahc_patch1_func, 460, 2, 1 }, - { ahc_patch7_func, 462, 10, 2 }, - { ahc_patch0_func, 472, 1, 1 }, - { ahc_patch8_func, 473, 118, 22 }, - { ahc_patch1_func, 475, 3, 2 }, - { ahc_patch0_func, 478, 5, 3 }, - { ahc_patch9_func, 478, 2, 2 }, - { ahc_patch0_func, 480, 3, 1 }, + { ahc_patch9_func, 258, 27, 3 }, + { ahc_patch1_func, 274, 10, 2 }, + { ahc_patch13_func, 277, 1, 1 }, + { ahc_patch14_func, 285, 14, 1 }, + { ahc_patch1_func, 301, 1, 2 }, + { ahc_patch0_func, 302, 1, 1 }, + { ahc_patch9_func, 305, 1, 1 }, + { ahc_patch13_func, 310, 1, 1 }, + { ahc_patch9_func, 311, 2, 2 }, + { ahc_patch0_func, 313, 4, 1 }, + { ahc_patch14_func, 317, 1, 1 }, + { ahc_patch15_func, 319, 2, 3 }, + { ahc_patch9_func, 319, 1, 2 }, + { ahc_patch0_func, 320, 1, 1 }, + { ahc_patch6_func, 325, 1, 2 }, + { ahc_patch0_func, 326, 1, 1 }, + { ahc_patch1_func, 330, 47, 11 }, + { ahc_patch6_func, 337, 2, 4 }, + { ahc_patch7_func, 337, 1, 1 }, + { ahc_patch8_func, 338, 1, 1 }, + { ahc_patch0_func, 339, 1, 1 }, + { ahc_patch16_func, 340, 1, 1 }, + { ahc_patch6_func, 356, 6, 3 }, + { ahc_patch16_func, 356, 5, 1 }, + { ahc_patch0_func, 362, 7, 1 }, + { ahc_patch13_func, 372, 5, 1 }, + { ahc_patch0_func, 377, 52, 17 }, + { ahc_patch14_func, 377, 1, 1 }, + { ahc_patch7_func, 379, 2, 2 }, + { ahc_patch17_func, 380, 1, 1 }, + { ahc_patch9_func, 383, 1, 1 }, + { ahc_patch18_func, 390, 1, 1 }, + { ahc_patch14_func, 395, 9, 3 }, + { ahc_patch9_func, 396, 3, 2 }, + { ahc_patch0_func, 399, 3, 1 }, + { ahc_patch9_func, 407, 6, 2 }, + { ahc_patch0_func, 413, 9, 2 }, + { ahc_patch13_func, 413, 1, 1 }, + { ahc_patch13_func, 422, 2, 1 }, + { ahc_patch14_func, 424, 1, 1 }, + { ahc_patch9_func, 426, 1, 2 }, + { ahc_patch0_func, 427, 1, 1 }, + { ahc_patch7_func, 428, 1, 1 }, + { ahc_patch7_func, 429, 1, 1 }, + { ahc_patch8_func, 430, 3, 3 }, + { ahc_patch6_func, 431, 1, 2 }, + { ahc_patch0_func, 432, 1, 1 }, + { ahc_patch9_func, 433, 1, 1 }, + { ahc_patch15_func, 434, 1, 2 }, + { ahc_patch13_func, 434, 1, 1 }, + { ahc_patch14_func, 436, 9, 4 }, + { ahc_patch9_func, 436, 1, 1 }, + { ahc_patch9_func, 443, 2, 1 }, + { ahc_patch0_func, 445, 4, 3 }, + { ahc_patch9_func, 445, 1, 2 }, + { ahc_patch0_func, 446, 3, 1 }, + { ahc_patch1_func, 450, 2, 1 }, + { ahc_patch7_func, 452, 10, 2 }, + { ahc_patch0_func, 462, 1, 1 }, + { ahc_patch8_func, 463, 118, 22 }, + { ahc_patch1_func, 465, 3, 2 }, + { ahc_patch0_func, 468, 5, 3 }, + { ahc_patch9_func, 468, 2, 2 }, + { ahc_patch0_func, 470, 3, 1 }, + { ahc_patch1_func, 475, 2, 2 }, + { ahc_patch0_func, 477, 6, 3 }, + { ahc_patch9_func, 477, 2, 2 }, + { ahc_patch0_func, 479, 3, 1 }, { ahc_patch1_func, 485, 2, 2 }, - { ahc_patch0_func, 487, 6, 3 }, - { ahc_patch9_func, 487, 2, 2 }, - { ahc_patch0_func, 489, 3, 1 }, - { ahc_patch1_func, 495, 2, 2 }, - { ahc_patch0_func, 497, 9, 7 }, - { ahc_patch9_func, 497, 5, 6 }, - { ahc_patch19_func, 497, 1, 2 }, - { ahc_patch0_func, 498, 1, 1 }, - { ahc_patch19_func, 500, 1, 2 }, - { ahc_patch0_func, 501, 1, 1 }, - { ahc_patch0_func, 502, 4, 1 }, - { ahc_patch6_func, 507, 3, 2 }, - { ahc_patch0_func, 510, 1, 1 }, - { ahc_patch6_func, 520, 1, 2 }, - { ahc_patch0_func, 521, 1, 1 }, - { ahc_patch20_func, 558, 7, 1 }, - { ahc_patch3_func, 593, 1, 2 }, - { ahc_patch0_func, 594, 1, 1 }, - { ahc_patch21_func, 597, 1, 1 }, - { ahc_patch8_func, 599, 106, 33 }, - { ahc_patch4_func, 601, 1, 1 }, - { ahc_patch1_func, 607, 2, 2 }, - { ahc_patch0_func, 609, 1, 1 }, - { ahc_patch1_func, 612, 1, 2 }, - { ahc_patch0_func, 613, 1, 1 }, - { ahc_patch9_func, 614, 3, 3 }, - { ahc_patch15_func, 615, 1, 1 }, - { ahc_patch0_func, 617, 4, 1 }, - { ahc_patch19_func, 626, 2, 2 }, - { ahc_patch0_func, 628, 1, 1 }, - { ahc_patch19_func, 632, 10, 3 }, - { ahc_patch5_func, 634, 8, 1 }, - { ahc_patch0_func, 642, 9, 2 }, - { ahc_patch5_func, 643, 8, 1 }, - { ahc_patch4_func, 653, 1, 2 }, - { ahc_patch0_func, 654, 1, 1 }, - { ahc_patch19_func, 655, 1, 2 }, - { ahc_patch0_func, 656, 3, 2 }, - { ahc_patch4_func, 658, 1, 1 }, - { ahc_patch5_func, 659, 1, 1 }, - { ahc_patch5_func, 662, 1, 1 }, - { ahc_patch5_func, 664, 1, 1 }, - { ahc_patch4_func, 666, 2, 2 }, - { ahc_patch0_func, 668, 2, 1 }, - { ahc_patch5_func, 670, 1, 1 }, - { ahc_patch5_func, 673, 1, 1 }, - { ahc_patch5_func, 676, 1, 1 }, - { ahc_patch19_func, 680, 1, 1 }, - { ahc_patch19_func, 683, 1, 1 }, - { ahc_patch4_func, 689, 1, 1 }, - { ahc_patch6_func, 692, 1, 2 }, - { ahc_patch0_func, 693, 1, 1 }, - { ahc_patch7_func, 705, 16, 1 }, - { ahc_patch4_func, 721, 20, 1 }, - { ahc_patch9_func, 742, 4, 2 }, - { ahc_patch0_func, 746, 4, 1 }, - { ahc_patch9_func, 750, 4, 2 }, - { ahc_patch0_func, 754, 3, 1 }, - { ahc_patch6_func, 760, 1, 1 }, - { ahc_patch22_func, 762, 14, 1 }, - { ahc_patch7_func, 776, 3, 1 }, - { ahc_patch9_func, 788, 24, 8 }, - { ahc_patch19_func, 792, 1, 2 }, - { ahc_patch0_func, 793, 1, 1 }, - { ahc_patch15_func, 798, 4, 2 }, - { ahc_patch0_func, 802, 7, 3 }, - { ahc_patch23_func, 802, 5, 2 }, - { ahc_patch0_func, 807, 2, 1 }, - { ahc_patch0_func, 812, 42, 3 }, - { ahc_patch18_func, 824, 18, 2 }, - { ahc_patch0_func, 842, 1, 1 }, - { ahc_patch4_func, 866, 1, 1 }, - { ahc_patch4_func, 867, 3, 2 }, - { ahc_patch0_func, 870, 1, 1 }, - { ahc_patch13_func, 871, 3, 1 }, - { ahc_patch4_func, 874, 12, 1 } + { ahc_patch0_func, 487, 9, 7 }, + { ahc_patch9_func, 487, 5, 6 }, + { ahc_patch19_func, 487, 1, 2 }, + { ahc_patch0_func, 488, 1, 1 }, + { ahc_patch19_func, 490, 1, 2 }, + { ahc_patch0_func, 491, 1, 1 }, + { ahc_patch0_func, 492, 4, 1 }, + { ahc_patch6_func, 497, 3, 2 }, + { ahc_patch0_func, 500, 1, 1 }, + { ahc_patch6_func, 510, 1, 2 }, + { ahc_patch0_func, 511, 1, 1 }, + { ahc_patch20_func, 548, 7, 1 }, + { ahc_patch3_func, 583, 1, 2 }, + { ahc_patch0_func, 584, 1, 1 }, + { ahc_patch21_func, 587, 1, 1 }, + { ahc_patch8_func, 589, 106, 33 }, + { ahc_patch4_func, 591, 1, 1 }, + { ahc_patch1_func, 597, 2, 2 }, + { ahc_patch0_func, 599, 1, 1 }, + { ahc_patch1_func, 602, 1, 2 }, + { ahc_patch0_func, 603, 1, 1 }, + { ahc_patch9_func, 604, 3, 3 }, + { ahc_patch15_func, 605, 1, 1 }, + { ahc_patch0_func, 607, 4, 1 }, + { ahc_patch19_func, 616, 2, 2 }, + { ahc_patch0_func, 618, 1, 1 }, + { ahc_patch19_func, 622, 10, 3 }, + { ahc_patch5_func, 624, 8, 1 }, + { ahc_patch0_func, 632, 9, 2 }, + { ahc_patch5_func, 633, 8, 1 }, + { ahc_patch4_func, 643, 1, 2 }, + { ahc_patch0_func, 644, 1, 1 }, + { ahc_patch19_func, 645, 1, 2 }, + { ahc_patch0_func, 646, 3, 2 }, + { ahc_patch4_func, 648, 1, 1 }, + { ahc_patch5_func, 649, 1, 1 }, + { ahc_patch5_func, 652, 1, 1 }, + { ahc_patch5_func, 654, 1, 1 }, + { ahc_patch4_func, 656, 2, 2 }, + { ahc_patch0_func, 658, 2, 1 }, + { ahc_patch5_func, 660, 1, 1 }, + { ahc_patch5_func, 663, 1, 1 }, + { ahc_patch5_func, 666, 1, 1 }, + { ahc_patch19_func, 670, 1, 1 }, + { ahc_patch19_func, 673, 1, 1 }, + { ahc_patch4_func, 679, 1, 1 }, + { ahc_patch6_func, 682, 1, 2 }, + { ahc_patch0_func, 683, 1, 1 }, + { ahc_patch7_func, 695, 16, 1 }, + { ahc_patch4_func, 711, 20, 1 }, + { ahc_patch9_func, 732, 4, 2 }, + { ahc_patch0_func, 736, 4, 1 }, + { ahc_patch9_func, 740, 4, 2 }, + { ahc_patch0_func, 744, 3, 1 }, + { ahc_patch6_func, 750, 1, 1 }, + { ahc_patch22_func, 752, 14, 1 }, + { ahc_patch7_func, 766, 3, 1 }, + { ahc_patch9_func, 778, 24, 8 }, + { ahc_patch19_func, 782, 1, 2 }, + { ahc_patch0_func, 783, 1, 1 }, + { ahc_patch15_func, 788, 4, 2 }, + { ahc_patch0_func, 792, 7, 3 }, + { ahc_patch23_func, 792, 5, 2 }, + { ahc_patch0_func, 797, 2, 1 }, + { ahc_patch0_func, 802, 42, 3 }, + { ahc_patch18_func, 814, 18, 2 }, + { ahc_patch0_func, 832, 1, 1 }, + { ahc_patch4_func, 856, 1, 1 }, + { ahc_patch4_func, 857, 3, 2 }, + { ahc_patch0_func, 860, 1, 1 }, + { ahc_patch13_func, 861, 3, 1 }, + { ahc_patch4_func, 864, 12, 1 } }; static struct cs { @@ -1306,11 +1296,11 @@ static struct cs { } critical_sections[] = { { 11, 18 }, { 21, 30 }, - { 721, 737 }, - { 867, 870 }, - { 874, 880 }, - { 882, 884 }, - { 884, 886 } + { 711, 727 }, + { 857, 860 }, + { 864, 870 }, + { 872, 874 }, + { 874, 876 } }; static const int num_critical_sections = sizeof(critical_sections) diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aiclib.h linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aiclib.h --- linux-2.4.20-wolk4.1s/drivers/scsi/aic7xxx/aiclib.h 2003-05-15 21:52:32.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/aic7xxx/aiclib.h 2003-06-05 22:45:13.000000000 +0200 @@ -60,12 +60,9 @@ /* * Linux Interrupt Support. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -#define AIC_LINUX_IRQRETURN_T irqreturn_t -#define AIC_LINUX_IRQRETURN(ours) return (IRQ_RETVAL(ours)) -#else -#define AIC_LINUX_IRQRETURN_T void -#define AIC_LINUX_IRQRETURN(ours) return +#ifndef IRQ_RETVAL +typedef void irqreturn_t; +#define IRQ_RETVAL(x) #endif /* diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/epsa2.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/epsa2.c --- linux-2.4.20-wolk4.1s/drivers/scsi/epsa2.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/epsa2.c 2003-06-02 17:23:43.000000000 +0200 @@ -0,0 +1,506 @@ +/* + epsa2.c (c) 1996-1999 Grant Guenther + + This is the ppSCSI protocol module for the Shuttle + Technologies EPSA2 parallel port SCSI adapter. EPSA2 is + a predecessor to the EPST. It uses slightly different + command encoding and has a less elaborate internal register + model. + +*/ + +#define EPSA2_VERSION "0.91" + +#define PPSC_BASE +#define PPSC_HA_MODULE + +#include "ppscsi.h" + +#define EPSA2_VER_CODE 0xb1 + +#define j44(a,b) (((a>>4)&0x0f)+(b&0xf0)) +#define j53(a,b) (((a>>3)&0x1f)+((b<<4)&0xe0)) + +static char epsa2_map[256]; /* status bits permutation */ + +static void epsa2_init( PHA *pha) +{ + +/* { REQ, BSY, MSG, CD, IO} */ + + char key[5] = {0x20,0x40,0x04,0x02,0x01}; + + ppsc_make_map(epsa2_map,key,0); + sprintf(pha->ident,"epsa2 %s (%s), Shuttle EPSA2", + EPSA2_VERSION,PPSC_H_VERSION); +} + +static void epsa2_write_regr (PHA *pha, int regr, int value) +{ + switch (pha->mode) { + + case 0: + case 1: + case 2: w0(0x70+regr); w2(1); w0(value); w2(4); + break; + + case 3: + case 4: + case 5: w3(0x40+regr); w4(value); w2(4); + break; + + } +} + +static int epsa2_read_regr (PHA *pha, int regr) +{ + int a, b; + + switch (pha->mode) { + + case 0: w0(0x40+regr); w2(1); w2(3); + a = r1(); w2(4); b = r1(); + return j44(a,b); + + case 1: w0(0x60+regr); w2(1); w2(4); + a = r1(); b = r2(); w0(0xff); + return j53(a,b); + + case 2: w0(0x50+regr); w2(1); w2(0x25); + a = r0(); w2(4); + return a; + + case 3: + case 4: + case 5: w3(regr); w2(0x24); a = r4(); w2(4); + return a; + + } + + return -1; +} + +/* for performance reasons, these block transfer functions make + some assumptions about the behaviour of the SCSI devices. In + particular, DMA transfers are assumed not to stall within the + last few bytes of a block ... +*/ + +static int epsa2_read_block (PHA *pha, char *buf, int len) +{ + int t, k, p, a, b; + + k = 0; + + switch (pha->mode) { + + case 0: w0(7); w2(1); w2(3); w0(0xff); + p = 1; + while (k < len) { + w2(6+p); a = r1(); + if (a & 8) b = a; else { w2(4+p); b = r1(); } + buf[k++] = j44(a,b); + p = 1 - p; + if (!(k % 16)) { + w0(0xfe); t = r1(); w0(0xff); + if (t & 8) break; + } + } + w0(0); w2(4); + break; + + case 1: w0(0x27); w2(1); w2(5); w0(0xff); + p = 0; + while (k < len) { + a = r1(); b = r2(); + buf[k++] = j53(a,b); + w2(4+p); + p = 1 - p; + if (!(k % 16)) { + w0(0xfe); t = r1(); w0(0xff); + if (t & 8) break; + } + } + w0(0); w2(4); + break; + + case 2: w0(0x17); w2(1); + p = 1; + while (k < len) { + w2(0x24+p); + buf[k++] = r0(); + p = 1 - p; + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(6); w2(4); + break; + + case 3: w3(6); w2(0x24); + while (k < len) { + buf[k++] = r4(); + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(4); + break; + + case 4: w3(6); w2(0x24); + while (k < len) { + if ((len - k) > 1) { + *((u16 *)(&buf[k])) = r4w(); + k += 2; + } else { + buf[k++] = r4(); + } + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(4); + break; + + case 5: w3(6); w2(0x24); + while (k < len) { + if ((len - k) > 3) { + *((u32 *)(&buf[k])) = r4l(); + k += 4; + } else { + buf[k++] = r4(); + } + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(4); + break; + } + + return k; +} + +static int epsa2_write_block (PHA *pha, char *buf, int len) +{ + int p, k; + + k = 0; + + switch (pha->mode) { + + case 0: + case 1: + case 2: w0(0x37); w2(1); + p = 1; + while (k < len) { + w2(4+p); + w0(buf[k++]); + p = 1 - p; + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(5); w2(7); w2(4); + break; + + case 3: w3(0x46); + while (k < len) { + w4(buf[k++]); + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(4); + break; + + case 4: w3(0x46); + while (k < len) { + if ((len - k) > 1) { + w4w(*((u16 *)(&buf[k]))); + k += 2; + } else { + w4(buf[k++]); + } + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(4); + break; + + case 5: w3(0x46); + while (k < len) { + if ((len - k) > 3) { + w4l(*((u32 *)(&buf[k]))); + k += 4; + } else { + w4(buf[k++]); + } + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(4); + break; + } + + return k; +} + +#define WR(r,v) epsa2_write_regr(pha,r,v) +#define RR(r) (epsa2_read_regr(pha,r)) + +#define CPP(x) w2(4);w0(0x22);w0(0xaa);w0(0x55);w0(0);w0(0xff);\ + w0(0x87);w0(0x78);w0(x);w2(5);w2(4);w0(0xff); + +static void epsa2_connect (PHA *pha) +{ + CPP(0x40); CPP(0xe0); + + w0(0x73); w2(1); w0(0); w2(4); + w0(0x72); w2(1); w0(0x40); w2(4); + + w0(0); w2(1); w2(4); + + CPP(0x50); CPP(0x48); + + switch (pha->mode) { + + case 0: WR(7,0x82); + break; + + case 1: + case 2: WR(7,0xa2); + break; + + case 3: + case 4: + case 5: CPP(0x30); CPP(0x20); + WR(7,0xa3); + break; + } + + w2(4); +} + +static void epsa2_disconnect (PHA *pha) +{ + switch (pha->mode) { + + case 0: WR(7,2); WR(2,0); + break; + + case 1: + case 2: WR(7,0x22); WR(2,0); + break; + + case 3: + case 4: + case 5: WR(7,0x23); w2(4); + w0(0x72); w2(1); w0(0); w2(4); + break; + } + + CPP(0x30); CPP(0x40); +} + +static int epsa2_test_proto (PHA *pha) +{ + int i, j, e; + char wb[16], rb[16]; + + e = 0; + + epsa2_connect(pha); + i = RR(7); + if (V_PROBE) printk("%s: version code reads: 0x%x\n",pha->device,i); + epsa2_disconnect(pha); + + if (i != EPSA2_VER_CODE) return 1; + + epsa2_connect(pha); + + for (j=0;j<200;j++) { + for (i=0;i<16;i++) { wb[i] = i+j; rb[i] = i+j+6; } + WR(5,1); + epsa2_write_block(pha,wb,16); + udelay(100); + WR(5,0x11); + epsa2_read_block(pha,rb,16); + for (i=0;i<16;i++) if (wb[i] != rb[i]) e++; + } + + epsa2_disconnect(pha); + + if (V_FULL) + printk("%s: test port 0x%x mode %d errors %d\n", + pha->device,pha->port,pha->mode,e); + + return e; +} + +/* The EPSA2 contains a core SCSI controller that is very + similar to the NCR 5380. Some bits have been shuffled + around, but the basic structure is the same. +*/ + +static int epsa2_select (PHA *pha, int initiator, int target) +{ + WR(4,(1< + + This is the ppSCSI protocol module for the Shuttle + Technologies EPST parallel port SCSI adapter. + +*/ + +#define EPST_VERSION "0.92" + +#define PPSC_BASE +#define PPSC_HA_MODULE + +#include "ppscsi.h" + +#define EPST_VER_CODE 0xb2 + +#define j44(a,b) (((a>>4)&0x0f)+(b&0xf0)) +#define j53(a,b) (((a>>3)&0x1f)+((b<<4)&0xe0)) + +static char epst_map[256]; /* status bits permutation */ + +static void epst_init (PHA *pha) +{ + +/* { REQ, BSY, MSG, CD, IO} */ + + char key[5] = {0x20,0x40,0x04,0x02,0x01}; + + ppsc_make_map(epst_map,key,0); + sprintf(pha->ident,"epst %s (%s), Shuttle EPST", + EPST_VERSION,PPSC_H_VERSION); +} + +static void epst_write_regr (PHA *pha, int regr, int value) +{ + switch (pha->mode) { + + case 0: + case 1: + case 2: w0(0x60+regr); w2(1); w0(value); w2(4); + break; + + case 3: + case 4: + case 5: w3(0x40+regr); w4(value); + break; + + } +} + +static int epst_read_regr (PHA *pha, int regr) +{ + int a, b; + + switch (pha->mode) { + + case 0: w0(regr); w2(1); w2(3); + a = r1(); w2(4); b = r1(); + return j44(a,b); + + case 1: w0(0x40+regr); w2(1); w2(4); + a = r1(); b = r2(); w0(0xff); + return j53(a,b); + + case 2: w0(0x20+regr); w2(1); w2(0x25); + a = r0(); w2(4); + return a; + + case 3: + case 4: + case 5: w3(regr); w2(0x24); a = r4(); + return a; + + } + + return -1; +} + +/* for performance reasons, these block transfer functions make + some assumptions about the behaviour of the SCSI devices. In + particular, DMA transfers are assumed not to stall within the + last few bytes of a block ... +*/ + +static int epst_read_block (PHA *pha, char *buf, int len) +{ + int t, k, p, a, b; + + k = 0; + + switch (pha->mode) { + + case 0: w0(7); w2(1); w2(3); w0(0xff); + p = 1; + while (k < len) { + w2(6+p); a = r1(); + if (a & 8) b = a; else { w2(4+p); b = r1(); } + buf[k++] = j44(a,b); + p = 1 - p; + if (!(k % 16)) { + w0(0xfe); t = r1(); w0(0xff); + if (t & 8) break; + } + } + w0(0); w2(4); + break; + + case 1: w0(0x47); w2(1); w2(5); w0(0xff); + p = 0; + while (k < len) { + a = r1(); b = r2(); + buf[k++] = j53(a,b); + w2(4+p); + p = 1 - p; + if (!(k % 16)) { + w0(0xfe); t = r1(); w0(0xff); + if (t & 8) break; + } + } + w0(0); w2(4); + break; + + case 2: w0(0x27); w2(1); + p = 1; + while (k < len) { + w2(0x24+p); + buf[k++] = r0(); + p = 1 - p; + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(6); w2(4); + break; + + case 3: w3(0x80); w2(0x24); + while (k < len) { + buf[k++] = r4(); + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(4); + break; + + case 4: w3(0x80); w2(0x24); + while (k < len) { + if ((len - k) > 1) { + *((u16 *)(&buf[k])) = r4w(); + k += 2; + } else { + buf[k++] = r4(); + } + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(4); + break; + + case 5: w3(0x80); w2(0x24); + while (k < len) { + if ((len - k) > 3) { + *((u32 *)(&buf[k])) = r4l(); + k += 4; + } else { + buf[k++] = r4(); + } + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(4); + break; + } + + return k; +} + +static int epst_write_block (PHA *pha, char *buf, int len) +{ + int p, k; + + k = 0; + + switch (pha->mode) { + + case 0: + case 1: + case 2: w0(0x67); w2(1); + p = 1; + while (k < len) { + w2(4+p); + w0(buf[k++]); + p = 1 - p; + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(5); w2(7); w2(4); + break; + + case 3: w3(0xc0); + while (k < len) { + w4(buf[k++]); + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(4); + break; + + case 4: w3(0xc0); + while (k < len) { + if ((len - k) > 1) { + w4w(*((u16 *)(&buf[k]))); + k += 2; + } else { + w4(buf[k++]); + } + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(4); + break; + + case 5: w3(0xc0); + while (k < len) { + if ((len - k) > 3) { + w4l(*((u32 *)(&buf[k]))); + k += 4; + } else { + w4(buf[k++]); + } + if ((!(k % 16)) && (r1() & 8)) break; + } + w2(4); + break; + } + + return k; +} + +#define WR(r,v) epst_write_regr(pha,r,v) +#define RR(r) (epst_read_regr(pha,r)) + +#define CPP(x) w2(4);w0(0x22);w0(0xaa);w0(0x55);w0(0);w0(0xff);\ + w0(0x87);w0(0x78);w0(x);w2(5);w2(4);w0(0xff); + +static void epst_connect (PHA *pha) +{ + w2(4); + CPP(0x40); CPP(0xe0); + w0(0); w2(1); w2(3); w2(4); + + if (pha->mode >= 3) { + w0(0); w2(1); w2(3); w2(4); w2(0xc); + w0(0x40); w2(6); w2(7); w2(4); + } + + WR(0x1d,0x20); WR(0x1d,0); /* clear the ring buffer */ + WR(0xa,0x1e); /* set up PDMA */ + WR(0xc,4); /* enable status bits */ + WR(8,2); /* deglitch timing */ +} + +static void epst_disconnect (PHA *pha) +{ + CPP(0x30); w2(4); + CPP(0x40); w2(4); +} + +#define Wsr(r,v) WR(0x18+r,v) +#define Rsr(r) (RR(0x18+r)) + +static int epst_test_proto (PHA *pha) +{ + int i, j, e; + char wb[16], rb[16]; + + e = 0; + + epst_connect(pha); + i = RR(0xb); + if (V_PROBE) printk("%s: version code reads: 0x%x\n",pha->device,i); + epst_disconnect(pha); + + if (i != EPST_VER_CODE) return 1; + + epst_connect(pha); + + for (j=0;j<200;j++) { + for (i=0;i<16;i++) { wb[i] = i+j; rb[i] = i+j+6; } + Wsr(5,1); + epst_write_block(pha,wb,16); + Wsr(5,0x11); + epst_read_block(pha,rb,16); + for (i=0;i<16;i++) if (wb[i] != rb[i]) e++; + } + + epst_disconnect(pha); + + if (V_FULL) + printk("%s: test port 0x%x mode %d errors %d\n", + pha->device,pha->port,pha->mode,e); + + return e; +} + +/* The EPST contains a core SCSI controller that is very + similar to the NCR 5380. Some bits have been shuffled + around, but the basic structure is the same. +*/ + +static int epst_select (PHA *pha, int initiator, int target) +{ + Wsr(4,(1< + + This is the ppSCSI protocol module for the OnSpec 90c26 + in its SCSI adapter mode. +*/ + +#define ONSCSI_VERSION "0.91" + +#define PPSC_BASE +#define PPSC_HA_MODULE + +#include "ppscsi.h" + +#define ONSCSI_REP_COUNT 256 + +#define TOGL pha->private[0] + +static char onscsi_map[256]; /* status bits permutation */ + +static void onscsi_init (PHA *pha) +{ + +/* { REQ, BSY, MSG, CD, IO} */ + + char key[5] = {0x10,0x01,0x20,0x40,0x80}; + + ppsc_make_map(onscsi_map,key,0); + sprintf(pha->ident,"onscsi %s (%s), OnSpec 90c26", + ONSCSI_VERSION,PPSC_H_VERSION); +} + +#define j44(a,b) ((b&0xf0)|((a>>4)&0x0f)) + +#define CMD(x) w0(x);w2(5);w2(0xd);w2(5);w2(0xd);w2(5);w2(4); +#define VAL(v) w0(v);w2(5);w2(7);w2(5);w2(4); + +static inline void onscsi_opcode (PHA *pha, int x ) +{ + if (pha->mode < 2) { + CMD(x); + } else { + w3(x); + } +} + +#define OP(x) onscsi_opcode(pha,x) +#define FULLBYTE (pha->mode > 0) + +static void onscsi_write_regr (PHA *pha, int r, int v) +{ + onscsi_opcode(pha,r); + + if (pha->mode < 2) { + VAL(v); + } else { + w2(5); w4(v); w2(4); + } +} + +static inline int onscsi_read_nybble (PHA *pha) +{ + int a, b; + + w2(6); a = r1(); w2(4); + w2(6); b = r1(); w2(4); + + return j44(a,b); +} + +static int onscsi_read_regr (PHA *pha, int r) +{ + int v = -1; + + onscsi_opcode(pha,r); + + switch (pha->mode) { + + case 0: v = onscsi_read_nybble(pha); + break; + + case 1: w2(0x26); v = r0(); w2(4); + break; + + case 2: + case 3: + case 4: w2(0x24); v = r4(); w2(4); + break; + + } + + return v; +} + +#define RR(r) onscsi_read_regr(pha,r) +#define WR(r,v) onscsi_write_regr(pha,r,v) + +static void onscsi_write_block (PHA *pha, char *buf, int n) +{ + int i; + + w2(5+TOGL); + + switch (pha->mode) { + + case 0: + case 1: for (i=0;imode) { + + case 0: w2(4); + for (i=0;isaved_r0 = r0(); + pha->saved_r2 = r2(); + + CPP(0x20,4); + + CMD(2); VAL(0); + CMD(2); VAL(FULLBYTE); + + WR(2,FULLBYTE); +} + +static void onscsi_disconnect (PHA *pha) +{ + WR(3,0); WR(7,0x48); + OP(4); + CPP(0x30,pha->saved_r2); + + w0(pha->saved_r0); + w2(pha->saved_r2); +} + +static int onscsi_test_proto (PHA *pha) +{ + int i, k, j; + char wbuf[16], rbuf[16]; + int e = 0; + + pha->saved_r0 = r0(); + pha->saved_r2 = r2(); + + CPP(0x30,pha->saved_r2); + CPP(0x0,pha->saved_r2); + + w0(0xfe);w0(0xaa);w0(0x55);w0(0);w0(0xff); + i = ((r1() & 0xf0) << 4); w0(0x87); + i |= (r1() & 0xf0); w0(0x78); + w0(0x20);w2(5); + i |= ((r1() & 0xf0) >> 4); + w2(4);w0(0xff); + + if (V_PROBE) printk("%s: signature 0x%x\n",pha->device,i); + + if (i == 0xb5f) { + + CMD(2); VAL(FULLBYTE); + + w2(4); w2(0xc); udelay(100); w2(4); udelay(100); + + CMD(2); VAL(0); + CMD(2); VAL(FULLBYTE); + + WR(2,FULLBYTE); + + k = RR(4); + + if (V_PROBE) + printk("%s: OnSpec 90c26 version %x\n",pha->device,k); + + } + + CPP(0x30,pha->saved_r2); + + w0(pha->saved_r0); + w2(pha->saved_r2); + + if (i != 0xb5f) return 1; + + onscsi_connect(pha); + + for (k=0;kmode == 0) WR(2,0x30); + if (pha->mode == 1) WR(2,0x10); + + WR(3,0); WR(7,0x48); + + WR(3,1); WR(7,0x48); OP(5); + TOGL = 0; + onscsi_write_block(pha,wbuf,16); + w2(4); + + if (pha->mode == 0) WR(2,0); + if (pha->mode == 1) WR(2,0x11); + + WR(3,5); WR(7,0x48); OP(5); + TOGL = 0; + onscsi_read_block(pha,rbuf,16); + w2(4); + + for (j=0;j<16;j++) + if (rbuf[j] != wbuf[j]) e++; + + } + + onscsi_disconnect(pha); + +#ifdef EXPERIMENT + + /* enable this to see how the buffer status bits work */ + + if (pha->mode == 2) { + + onscsi_connect(pha); + + WR(3,0); WR(7,0x48); + WR(3,1); WR(7,0x48); OP(5); + w2(5); + + for (k=0;k<16;k++) { + j = r1(); w4(k); + printk("%2x:%d ",j,k); + } + printk("\n"); + + w2(4); WR(3,5); WR(7,0x48); OP(5); + w2(0x24); + + for (k=0;k<16;k++) { + j = r1(); + printk("%2x:%d ",j,r4()); + } + printk("\n"); + + w2(4); + + onscsi_disconnect(pha); + } + + if (pha->mode == 1) { + + onscsi_connect(pha); + + WR(2,0x11); + WR(3,0); WR(7,0x48); + WR(3,1); WR(7,0x48); OP(5); + w2(5); i = 0; + + for (k=0;k<16;k++) { + j = r1(); w0(k); i = 2 - i; w2(5+i); + printk("%2x:%d ",j,k); + } + printk("%2x.\n",r1()); + + w2(4); + + WR(2,0x11); + WR(3,0); WR(7,0x48); + WR(3,5); WR(7,0x48); OP(5); + w2(0x24); i = 0; + + printk("%2x ",r1()); + for (k=0;k<16;k++) { + i = 2 - i; w2(0x24+i); j = r1(); + printk("%2x:%d ",j,r0()); + } + printk("\n"); + + w2(4); + + onscsi_disconnect(pha); + } + +#endif + + if (V_FULL) + printk("%s: test port 0x%x mode %d errors %d\n", + pha->device,pha->port,pha->mode,e); + + return e; +} + +static int onscsi_select (PHA *pha, int initiator, int target) +{ + WR(1,0); + WR(2,0x80+FULLBYTE); + if (RR(1) != 0) return -1; + WR(0,((1 << initiator) | (1 << target))); + WR(1,2); + return 0; +} + +static int onscsi_test_select (PHA *pha) +{ + return ((RR(1) & 3) == 3); +} + +static void onscsi_select_finish (PHA *pha) +{ + WR(1,0); +} + +static void onscsi_deselect (PHA *pha) +{ + WR(1,0); + /* WR(2,0x20+FULLBYTE); */ + WR(2,FULLBYTE); + WR(3,0); WR(7,0x48); +} + +static int onscsi_get_bus_status (PHA *pha) +{ + WR(2,0x20+FULLBYTE); + return onscsi_map[RR(1)]; +} + +static void onscsi_slow_start (PHA *pha, char *val) +{ + pha->priv_flag = (RR(1) & 0x80); + pha->priv_ptr = val; + + if (pha->priv_flag) WR(2,0x20); else WR(2,0x21); + + OP(0); + + if (pha->priv_flag) { + w2(6); + } else { + w0(*val); w2(5); w2(7); + } +} + +static int onscsi_slow_done (PHA *pha) +{ + return (!(r1() & 8)); +} + +static void onscsi_slow_end (PHA *pha) +{ + if (pha->priv_flag) { + *pha->priv_ptr = onscsi_read_nybble(pha); + } else { + w2(5); w2(4); + } +} + +static void onscsi_start_block (PHA *pha, int rd) +{ + pha->priv_flag = rd; + + if (rd) { + WR(3,5); WR(7,0x48); + if (pha->mode == 1) WR(2,0x31); + OP(5); + w2(5); w0(0xff); w2(4); + } else { + WR(3,1); WR(7,0x48); + if (pha->mode == 1) WR(2,0x31); + OP(5); + } + TOGL = 0; +} + +static int onscsi_transfer_done (PHA *pha) +{ + int x; + + if (pha->priv_flag) return 1; + + if (pha->mode == 0) { WR(2,0x20); OP(5); } + x = r1(); x = r1(); + if (pha->mode == 0) { WR(2,0x30); OP(5); } + + if ((x & 0xf0) == 0x80) return 16; + return 0; +} + +static int onscsi_transfer_ready (PHA *pha) +{ + int x; + + if (pha->priv_flag) { + x = r1(); x = r1(); + if ((x & 0xf0) == 0xf0) return 16; + if ((x & 0xf0) == 0xb0) return 8; + if ((x & 0xf0) == 0x90) return 1; + if ((x & 0xf8) == 0x88) return -1; + if ((x & 0xf8) == 0x08) return -1; + if ((x & 0xf8) == 0x0) return 1; + + if ((x & 0xf8) != 0x80) printk("DEBUG: %x\n",x); + + return 0; + } + + return onscsi_transfer_done(pha); +} + + +static int onscsi_transfer_block (PHA *pha, char * buf, int buflen, int rd) +{ + int k, b; + + k = 0; + while ( k < buflen) { + + if ((b=onscsi_transfer_ready(pha)) <= 0) break; + if (b > (buflen-k)) b = buflen-k; + + if (rd) onscsi_read_block(pha,buf,b); + else onscsi_write_block(pha,buf,b); + + k += b; buf += b; + } + + return k; +} + +static void onscsi_end_block (PHA *pha, int rd) +{ + w2(4); WR(3,0); WR(7,0x48); +} + +static void onscsi_reset_bus (PHA *pha) +{ + WR(2,2); + udelay(500); + WR(2,0); + WR(2,FULLBYTE); +} + +static char *(mode_strings[5]) = {"Nybble","PS/2","EPP","EPP-16","EPP-32"}; + +static struct ppsc_protocol onscsi_psp = { + + {&host0,&host1,&host2,&host3}, /* params */ + &host_structs, /* hosts */ + 5, /* num_modes */ + 2, /* epp_first */ + 1, /* default_delay */ + 1, /* can_message */ + 16, /* sg_tablesize */ + mode_strings, + onscsi_init, + NULL, /* release */ + onscsi_connect, + onscsi_disconnect, + onscsi_test_proto, + onscsi_select, + onscsi_test_select, + onscsi_select_finish, + onscsi_deselect, + onscsi_get_bus_status, + onscsi_slow_start, + onscsi_slow_done, + onscsi_slow_end, + onscsi_start_block, + onscsi_transfer_block, + onscsi_transfer_ready, + onscsi_transfer_done, + onscsi_end_block, + onscsi_reset_bus +}; + +int onscsi_detect (Scsi_Host_Template *tpnt ) +{ + return ppsc_detect( &onscsi_psp, tpnt, verbose); +} + +#ifdef MODULE + +Scsi_Host_Template driver_template = PPSC_TEMPLATE(onscsi); + +#include "scsi_module.c" + +#else + +void onscsi_setup (char *str, int *ints) +{ + ppsc_gen_setup(stt,4,str); +} + +#endif + +/* end of onscsi.c */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/ppscsi.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/ppscsi.c --- linux-2.4.20-wolk4.1s/drivers/scsi/ppscsi.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/ppscsi.c 2003-06-02 17:23:43.000000000 +0200 @@ -0,0 +1,1286 @@ +/* + ppscsi.c (C) 1999 Grant Guenther + (C) 2000 Tim Waugh + Under the terms of the GNU general public license. + + This is the common code shared by the PPSCSI family of + low-level drivers for parallel port SCSI host adapters. + + + To use one of the ppSCSI drivers, you must first have this module + built-in to your kernel, or loaded. Then, you can load the + appropriate protocol module. All protocol modules accept the + same parameters: + + verbose=N determines the logging level where N= + 0 only serious errors are logged + 1 report progress messages while probing adapters + 2 log the scsi commands sent to adapters + 3 basic debugging information + 4 full debugging (generates lots of output) + + hostN=,,,,, + + sets per-host-adapter parameters where + + N is between 0 and 3, each protocol can + support up to four separate adapters. + + The parport for this adapter, eg: + 0 for parport0. + + Protocol dependent mode number. Usually + probed to determine the fastest available + mode. + + microseconds of delay per port access. + Default is protocol dependent. + + Determines this host's ability to load + the system. Default 0. Set to 1 or 2 + to reduce load at the expense of device + performance. + + scatter-gather table size. + + bit mask of targets on which to force + all commands to use explicit REQ/ACK + handshaking, rather than adapter buffers. + +*/ + +#define PPSC_VERSION "0.92" + +#define PPSC_BASE +#include "ppscsi.h" +#include +#include +#include +#include + +#include + +#define PPSC_GEN_TMO 40*HZ +#define PPSC_SELECT_TMO HZ/10 +#define PPSC_PROBE_TMO HZ/2 +#define PPSC_RESET_TMO 4*HZ +#define PPSC_SLOW_LOOPS 30 +#define PPSC_BUSY_SNOOZE HZ; + +#define PPSC_DEF_NICE 0 +#define PPSC_INITIATOR 7 + +spinlock_t ppsc_spinlock = SPIN_LOCK_UNLOCKED; + +static char ppsc_bulk_map[256]; + +struct ppsc_port_list_struct { + struct parport *port; + struct ppsc_port_list_struct *next; +}; +static struct ppsc_port_list_struct *ppsc_port_list; + +/* ppsc_attach and ppsc_detach are for keeping a list of currently + * available ports, held under a mutex. We do this rather than + * using parport_enumerate because it stops a load of races. + */ + +static void ppsc_attach (struct parport *port) +{ + struct ppsc_port_list_struct *add; + + add = kmalloc (sizeof (struct ppsc_port_list_struct), GFP_KERNEL); + if (!add) { + printk (KERN_WARNING "ppscsi: memory squeeze\n"); + return; + } + + add->port = parport_get_port (port); + add->next = ppsc_port_list; + wmb (); + ppsc_port_list = add; +} + +static void ppsc_detach (struct parport *port) +{ + /* Do nothing. We have a reference to the port already, so + * it won't go away. We'll clean up the port list when we + * unload. */ +} + +static struct parport_driver ppsc_driver = { + name: "ppscsi", + attach: ppsc_attach, + detach: ppsc_detach +}; + +void ppsc_make_map (char map[256], char key[5], int inv) +{ + int i, j; + + for (i=0;i<256;i++) { + map[i] = 0; + for (j=0;j<5;j++) + map[i] = (map[i] << 1) | ((i & key[j]) != inv*key[j]); + } +} + +void ppsc_gen_setup (STT t[], int n, char *ss) +{ + int j, k, sgn; + + k = 0; + for (j=0;jcontinuation = continuation; + pha->ready = ready; + if (timeout) + pha->timeout = jiffies + timeout; + else pha->timeout = pha->then + pha->tmo; + + if (!pha->nice && !pha->tq_active) { +#ifdef HAVE_DISABLE_HLT + disable_hlt(); +#endif + pha->tq_active = 1; + schedule_task (&pha->tq); + } + + if (!pha->timer_active) { + pha->timer_active = 1; + pha->timer.expires = jiffies + ((pha->nice>0)?(pha->nice-1):0); + add_timer(&pha->timer); + } + + spin_unlock_irqrestore(&ppsc_spinlock,flags); +} + +static void ppsc_tq_int (void *data) +{ + void (*con)(PHA *); + long flags; + PHA *pha = (PHA *)data; + + spin_lock_irqsave(&ppsc_spinlock,flags); + + con = pha->continuation; + +#ifdef HAVE_DISABLE_HLT + enable_hlt(); +#endif + + pha->tq_active = 0; + + if (!con) { + spin_unlock_irqrestore(&ppsc_spinlock,flags); + return; + } + pha->timedout = time_after_eq (jiffies, pha->timeout); + if (!pha->ready || pha->ready(pha) || pha->timedout) { + pha->continuation = NULL; + spin_unlock_irqrestore(&ppsc_spinlock,flags); + con(pha); + return; + } + +#ifdef HAVE_DISABLE_HLT + disable_hlt(); +#endif + + pha->tq_active = 1; + schedule_task (&pha->tq); + spin_unlock_irqrestore(&ppsc_spinlock,flags); +} + +static void ppsc_timer_int (unsigned long data) +{ + void (*con)(PHA *); + long flags; + PHA *pha = (PHA *)data; + + spin_lock_irqsave(&ppsc_spinlock,flags); + + con = pha->continuation; + pha->timer_active = 0; + if (!con) { + spin_unlock_irqrestore(&ppsc_spinlock,flags); + return; + } + pha->timedout = time_after_eq (jiffies, pha->timeout); + if (!pha->ready || pha->ready(pha) || pha->timedout) { + pha->continuation = NULL; + spin_unlock_irqrestore(&ppsc_spinlock,flags); + con(pha); + return; + } + pha->timer_active = 1; + pha->timer.expires = jiffies + ((pha->nice>0)?(pha->nice-1):0); + add_timer(&pha->timer); + spin_unlock_irqrestore(&ppsc_spinlock,flags); +} + +static void ppsc_wake_up( void *p) +{ + PHA *pha = (PHA *) p; + long flags; + void (*cont)(PHA *) = NULL; + + spin_lock_irqsave(&ppsc_spinlock,flags); + + if (pha->claim_cont && + !parport_claim(pha->pardev)) { + cont = pha->claim_cont; + pha->claim_cont = NULL; + pha->claimed = 1; + } + + spin_unlock_irqrestore(&ppsc_spinlock,flags); + + wake_up(&(pha->parq)); + + if (cont) cont(pha); +} + +void ppsc_do_claimed (PHA *pha, void(*cont)(PHA *)) +{ + long flags; + + spin_lock_irqsave(&ppsc_spinlock,flags); + + if (!parport_claim(pha->pardev)) { + pha->claimed = 1; + spin_unlock_irqrestore(&ppsc_spinlock,flags); + cont(pha); + } else { + pha->claim_cont = cont; + spin_unlock_irqrestore(&ppsc_spinlock,flags); + } +} + +static void ppsc_claim (PHA *pha) +{ + if (pha->claimed) return; + pha->claimed = 1; + + wait_event (pha->parq, !parport_claim (pha->pardev)); +} + +static void ppsc_unclaim (PHA *pha) +{ + pha->claimed = 0; + parport_release(pha->pardev); +} + +static void ppsc_unregister_parport (PHA *pha) +{ + parport_unregister_device(pha->pardev); + pha->pardev = NULL; +} + +static int ppsc_register_parport (PHA *pha, int verbose) +{ + struct ppsc_port_list_struct *ports; + struct parport *port = NULL; + + ports = ppsc_port_list; + while((ports)&&(ports->port->number != pha->port)) + ports = ports->next; + if (ports) { + port = ports->port; + pha->pardev = parport_register_device(port, pha->device, + NULL, ppsc_wake_up, NULL, + 0, (void *)pha); + } else { + printk (KERN_DEBUG "%s: no such device: parport%d\n", + pha->device, pha->port); + return 1; + } + + if (!pha->pardev) { + printk (KERN_DEBUG "%s: couldn't register device\n", + pha->device); + return 1; + } + + init_waitqueue_head (&pha->parq); + + /* For now, cache the port base address. Won't need this + after transition to parport_xxx_yyy. */ + pha->port = port->base; + + if (verbose) + printk("%s: 0x%x is %s\n",pha->device,pha->port, + port->name); + pha->parname = port->name; + return 0; +} + +/* Here's the actual core SCSI stuff ... */ + +#define PPSC_FAIL(err,msg) { ppsc_fail_command(pha,err,msg); return; } + +static void ppsc_start (PHA *pha); +static void ppsc_select_intr (PHA *pha); +static void ppsc_engine (PHA *pha); +static void ppsc_transfer (PHA *pha); +static void ppsc_transfer_done (PHA *pha); +static int ppsc_slow (PHA *pha, char *val); +static void ppsc_slow_done (PHA *pha); +static void ppsc_cleanup (PHA *pha); +static void ppsc_fail_command (PHA *pha, int err_code, char *msg); +static int ppsc_ready (PHA *pha); + +/* synchronous interface is deprecated, but we maintain it for + internal use. It just starts an asynchronous command and waits + for it to complete. +*/ + +int ppsc_command (Scsi_Cmnd *cmd) +{ + PHA *pha = (PHA *) cmd->host->hostdata[0]; + + pha->cur_cmd = cmd; + pha->done = NULL; + pha->then = jiffies; + + ppsc_do_claimed(pha,ppsc_start); + + while (pha->cur_cmd) scsi_sleep(1); + + return cmd->result; +} + +int ppsc_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) +{ + PHA *pha = (PHA *) cmd->host->hostdata[0]; + + if (pha->cur_cmd) { + printk("%s: Driver is busy\n",pha->device); + return 0; + } + + pha->cur_cmd = cmd; + pha->done = done; + pha->then = jiffies; + + ppsc_do_claimed(pha,ppsc_start); + + return 0; +} + +static void ppsc_arb_fail (PHA *pha) +{ + PPSC_FAIL(DID_BUS_BUSY,"Arbitration failure"); +} + +static void ppsc_start (PHA *pha) +{ + int k, r, b, bf; + struct scatterlist *p; + + pha->last_phase = PPSC_PH_NONE; + pha->return_code = (DID_OK << 16); + pha->overflow = 0; + pha->protocol_error = 0; + pha->cmd_count = 0; + + k = pha->cur_cmd->cmnd[0]; + bf = ppsc_bulk_map[k]; + + bf &= (!((1<cur_cmd->target) & pha->slow_targets)); + + r = pha->cur_cmd->use_sg; + if (r) { + b = 0; + p = (struct scatterlist *)pha->cur_cmd->request_buffer; + for (k=0;klength; + p++; + } + } else { + b = pha->cur_cmd->request_bufflen; + } + + bf &= (b > 127); + + if (V_DEBUG) + printk("%s: Target %d, bl=%d us=%d bf=%d cm=%x\n", + pha->device,pha->cur_cmd->target,b,r,bf,k); + + pha->bulk = bf; + pha->tlen = b; + + pha->proto->connect(pha); + + r = 0; + while (r++ < 5) { + k = pha->proto->select(pha,PPSC_INITIATOR,pha->cur_cmd->target); + if (k != -1) break; + udelay(200); + } + + if (k == -1) { + ppsc_set_intr(pha,ppsc_arb_fail,NULL,1); + return; + } + + ppsc_set_intr(pha,ppsc_select_intr,pha->proto->test_select, + PPSC_SELECT_TMO); +} + +static void ppsc_select_intr (PHA *pha) +{ + if (!pha->proto->test_select(pha)) { + pha->return_code = DID_NO_CONNECT << 16; + ppsc_cleanup(pha); + return; + } + if (pha->proto->select_finish) + pha->proto->select_finish(pha); + + if (V_FULL) + printk("%s: selected target\n",pha->device); + + pha->timedout = 0; + ppsc_engine(pha); +} + +static void ppsc_update_sg (PHA *pha) +{ + if ((!pha->cur_len) && pha->sg_count) { + pha->sg_count--; + pha->sg_list++; + pha->cur_buf = pha->sg_list->address; + pha->cur_len = pha->sg_list->length; + } +} + +static void ppsc_engine (PHA *pha) +{ + int phase, i; + char *sb; + + while (1) { + if ((pha->last_phase == PPSC_PH_MSGIN) || + ((pha->last_phase == PPSC_PH_STAT) + && (!pha->proto->can_message))) { + pha->return_code |= (pha->status_byte & STATUS_MASK) + | (pha->message_byte << 8); + ppsc_cleanup(pha); + return; + } + + phase = pha->proto->get_bus_status(pha); + + if (pha->abort_flag) + PPSC_FAIL(DID_ABORT,"Command aborted"); + + if (pha->protocol_error) + PPSC_FAIL(DID_ERROR,"Adapter protocol failure"); + + if (!(phase & PPSC_BSY)) { + if (pha->last_phase == PPSC_PH_STAT) { + if (V_DEBUG) printk("%s: No msg phase ?\n", pha->device); + pha->return_code |= (pha->status_byte & STATUS_MASK); + ppsc_cleanup(pha); + return; + } + PPSC_FAIL(DID_ERROR,"Unexpected bus free"); + } + + if (!(phase & PPSC_REQ)) { + if (pha->timedout) + PPSC_FAIL(DID_TIME_OUT,"Pseudo-interrupt timeout"); + ppsc_set_intr(pha,ppsc_engine,ppsc_ready,0); + return; + } + + switch (phase) { + + case PPSC_PH_CMD: + + if (phase != pha->last_phase) { + if (pha->last_phase != PPSC_PH_NONE) + PPSC_FAIL(DID_ERROR,"Phase sequence error 1"); + pha->cmd_count = 0; + if (V_TRACE) { + printk("%s: Command to %d (%d): ", + pha->device, pha->cur_cmd->target, + pha->cur_cmd->cmd_len); + for (i=0;icur_cmd->cmd_len;i++) + printk("%2x ",pha->cur_cmd->cmnd[i]); + printk("\n"); + } + } + + pha->last_phase = phase; + + if (pha->cmd_count >= pha->cur_cmd->cmd_len) + PPSC_FAIL(DID_ERROR,"Command buffer overrun"); + + if (!ppsc_slow(pha,&(pha->cur_cmd->cmnd[pha->cmd_count++]))) + return; + + break; + + case PPSC_PH_READ: + case PPSC_PH_WRITE: + + if (phase != pha->last_phase) { + if (pha->last_phase != PPSC_PH_CMD) + PPSC_FAIL(DID_ERROR,"Phase sequence error 2"); + pha->data_dir = phase & PPSC_IO; + pha->data_count = 0; + + pha->sg_count = pha->cur_cmd->use_sg; + if (pha->sg_count) { + pha->sg_count--; + pha->sg_list = + (struct scatterlist *)pha->cur_cmd->request_buffer; + pha->cur_buf = pha->sg_list->address; + pha->cur_len = pha->sg_list->length; + } else { + pha->cur_buf = pha->cur_cmd->request_buffer; + pha->cur_len = pha->cur_cmd->request_bufflen; + } + + pha->last_phase = phase; + + } + + if ((pha->bulk) && (pha->cur_len > 0 )) { + pha->proto->start_block(pha,pha->data_dir); + ppsc_transfer(pha); + return; + } + + ppsc_update_sg(pha); + + if (!pha->cur_len) { + pha->cur_len = 1; + pha->cur_buf = (char *)&i; + i = 0x5a; + pha->overflow++; + } + + pha->cur_len--; + pha->data_count++; + + if (!ppsc_slow(pha,pha->cur_buf++)) return; + + break; + + case PPSC_PH_STAT: + + if ((pha->last_phase != PPSC_PH_CMD) && + (pha->last_phase != PPSC_PH_READ) && + (pha->last_phase != PPSC_PH_WRITE)) + PPSC_FAIL(DID_ERROR,"Phase sequence error 3"); + + if ((pha->last_phase != PPSC_PH_CMD) && + (V_DEBUG)) { + printk("%s: %s%s %d bytes\n", + pha->device, + pha->bulk?"":"slow ", + pha->data_dir?"read":"write", + pha->data_count); + + if (pha->cur_cmd->cmnd[0] == REQUEST_SENSE) { + + sb = (char *)pha->cur_cmd->request_buffer; + printk("%s: Sense key: %x ASC: %x ASCQ: %x\n", + pha->device, sb[2] & 0xff, + sb[12] & 0xff, sb[13] & 0xff); + } + } + + if (pha->overflow) + printk("%s: WARNING: data %s overran by %d/%d bytes\n", + pha->device,pha->data_dir?"read":"write", + pha->overflow,pha->data_count); + + pha->last_phase = phase; + + if (!ppsc_slow(pha,&pha->status_byte)) return; + + break; + + case PPSC_PH_MSGIN: + + if (pha->last_phase != PPSC_PH_STAT) + PPSC_FAIL(DID_ERROR,"Phase sequence error 4"); + + pha->last_phase = phase; + + if (V_FULL) + printk("%s: status = %x\n",pha->device,pha->status_byte); + + if (!ppsc_slow(pha,&pha->message_byte)) return; + + break; + + default: + + PPSC_FAIL(DID_ERROR,"Unexpected bus phase"); + + } + } +} + +static void ppsc_transfer (PHA *pha) +{ + int i, j; + + if (pha->timedout) PPSC_FAIL(DID_TIME_OUT,"PDMA timeout"); + + while(1) { + + if (!(j=pha->proto->transfer_ready(pha))) { + ppsc_set_intr(pha,ppsc_transfer, + pha->proto->transfer_ready,0); + return; + } + + if (j < 0) { + if (V_DEBUG) + printk("%s: short transfer\n",pha->device); + ppsc_set_intr(pha,ppsc_transfer_done, + pha->proto->transfer_done,0); + return; + } + + i = pha->proto->transfer_block(pha,pha->cur_buf, + pha->cur_len,pha->data_dir); + + if (V_FULL) printk("%s: Fragment %d\n",pha->device,i); + + if ((i < 0) || (i > pha->cur_len)) + PPSC_FAIL(DID_ERROR,"Block transfer error"); + + pha->cur_len -= i; + pha->cur_buf += i; + pha->data_count += i; + + ppsc_update_sg(pha); + + if (pha->cur_len == 0 ) { + ppsc_set_intr(pha,ppsc_transfer_done, + pha->proto->transfer_done,0); + return; + } + } +} + +static void ppsc_transfer_done (PHA *pha) +{ + if (pha->timedout) PPSC_FAIL(DID_TIME_OUT,"PDMA done timeout"); + + pha->proto->end_block(pha,pha->data_dir); + ppsc_engine(pha); +} + +static int ppsc_slow (PHA *pha, char *val) +{ + int k; + + pha->proto->slow_start(pha,val); + + k = 0; + while (k++ < PPSC_SLOW_LOOPS) + if (pha->proto->slow_done(pha)) { + pha->proto->slow_end(pha); + return 1; + } + + ppsc_set_intr(pha,ppsc_slow_done,pha->proto->slow_done,0); + return 0; +} + +static void ppsc_slow_done (PHA *pha) +{ + int k; + + if (pha->timedout) PPSC_FAIL(DID_TIME_OUT,"PIO timeout"); + + pha->proto->slow_end(pha); + + k = 0; + while (k++ < PPSC_SLOW_LOOPS) + if (ppsc_ready(pha)) break; + + ppsc_engine(pha); +} + +static void ppsc_try_again (unsigned long data ) +{ + PHA *pha = (PHA *)data; + + ppsc_do_claimed(pha,ppsc_start); +} + +static void ppsc_cleanup (PHA *pha) +{ + Scsi_Cmnd *cmd; + void (*done)(Scsi_Cmnd *); + long saved_flags; + + pha->tot_bytes += pha->data_count; + + cmd = pha->cur_cmd; + done = pha->done; + cmd->result = pha->return_code; + pha->cur_cmd = 0; + + pha->proto->deselect(pha); + pha->proto->disconnect(pha); + + if (V_FULL) printk("%s: releasing parport\n",pha->device); + + ppsc_unclaim(pha); + + if (pha->abort_flag) { + + if (V_DEBUG) printk("%s: command aborted !\n",pha->device); + + return; /* kill the thread */ + } + + if (V_DEBUG) + printk("%s: Command status %08x last phase %o\n", + pha->device,cmd->result,pha->last_phase); + + if (status_byte(pha->return_code) == BUSY) { + + pha->cur_cmd = cmd; + + if (V_FULL) + printk("%s: BUSY, sleeping before retry ...\n", + pha->device); + + init_timer (&pha->sleeper); + pha->sleeper.data = (unsigned long) pha; + pha->sleeper.function = ppsc_try_again; + pha->sleeper.expires = jiffies + PPSC_BUSY_SNOOZE; + add_timer(&pha->sleeper); + + return; + + } + + pha->tot_cmds++; + + if ((cmd->cmnd[0] != REQUEST_SENSE) && + (status_byte(pha->return_code) == CHECK_CONDITION)) { + + if (V_FULL) + printk("%s: Requesting sense data\n",pha->device); + + cmd->cmnd[0] = REQUEST_SENSE; + cmd->cmnd[1] &= 0xe0; + cmd->cmnd[2] = 0; + cmd->cmnd[3] = 0; + cmd->cmnd[4] = sizeof(cmd->sense_buffer); + cmd->cmnd[5] = 0; + cmd->cmd_len = 6; + cmd->use_sg = 0; + cmd->request_buffer = (char *) cmd->sense_buffer; + cmd->request_bufflen = sizeof(cmd->sense_buffer); + + pha->cur_cmd = cmd; + ppsc_do_claimed(pha,ppsc_start); + + return; + } + + if (done) { + + spin_lock_irqsave(&io_request_lock,saved_flags); + done(cmd); + spin_unlock_irqrestore(&io_request_lock,saved_flags); + + } + +} + +static void ppsc_fail_command (PHA *pha, int err_code, char *msg) +{ + int bs; + + pha->tot_errs++; + + bs = pha->proto->get_bus_status(pha); + + pha->return_code = err_code << 16; + if (!pha->quiet) + printk("%s: %s, bs=%o cb=%d db=%d bu=%d sg=%d " + "rd=%d lp=%o pe=%d cc=%d\n", + pha->device, msg, bs, + pha->cmd_count, pha->data_count, + pha->bulk, pha->sg_count, pha->data_dir, + pha->last_phase, pha->protocol_error, pha->tot_cmds); + + ppsc_cleanup(pha); +} + +static int ppsc_ready (PHA *pha) +{ + int bs; + + if (pha->abort_flag || pha->protocol_error) return 1; + bs = pha->proto->get_bus_status(pha); + + if ( (bs & (PPSC_REQ|PPSC_BSY)) != PPSC_BSY) return 1; + + return 0; +} + +int ppsc_abort (Scsi_Cmnd * cmd) +{ + PHA *pha = (PHA *)cmd->host->hostdata[0]; + + printk("%s: Command abort not supported\n",pha->device); + return FAILED; +} + +static void ppsc_reset_pha (PHA *pha) +{ + if (!pha->proto->reset_bus) { + printk("%s: No reset method available\n",pha->device); + return; + } + + ppsc_claim(pha); + pha->proto->connect(pha); + pha->proto->reset_bus(pha); + scsi_sleep(4*HZ); + pha->proto->disconnect(pha); + ppsc_unclaim(pha); + + if (!pha->quiet) printk("%s: Bus reset\n",pha->device); +} + +int ppsc_reset (Scsi_Cmnd * cmd) +{ + PHA *pha = (PHA *)cmd->host->hostdata[0]; + int k = 0; + + if (!pha->proto->reset_bus) + return FAILED; + + if (pha->cur_cmd) + pha->abort_flag = PPSC_DO_RESET; + + while (pha->cur_cmd && (k < PPSC_RESET_TMO)) { + scsi_sleep(HZ/10); + k += HZ/10; + } + + if (pha->cur_cmd) { + printk("%s: Driver won't give up for reset\n",pha->device); + return FAILED; + } + + ppsc_reset_pha(pha); + + return SUCCESS; +} + +#define PROCIN(n,var) \ + if ((length>n+1)&&(strncmp(buffer,#var"=",n+1)==0)) { \ + pha->var = simple_strtoul(buffer+n+1,NULL,0); \ + return length; \ + } + +#define PROCOUT(fmt,val) len+=sprintf(buffer+len,fmt"\n",val); + +int ppsc_proc_info(char *buffer, char **start, off_t offset, + int length, int hostno, int inout) +{ + int len = 0; + struct Scsi_Host *p = scsi_hostlist; + PHA *pha; + + /* first, lets find the host struct */ + + while (p && (p->host_no != hostno)) p = p->next; + if (!p) return 0; /* should never happen */ + pha = (PHA *)p->hostdata[0]; + + if (inout) { + + PROCIN(4,mode); + PROCIN(5,delay); + PROCIN(7,verbose); + PROCIN(10,abort_flag); + PROCIN(4,nice); + + return (-EINVAL); + } + + PROCOUT("ident: %s",pha->ident); + PROCOUT("base port: 0x%03x",pha->port); + PROCOUT("mode: %d",pha->mode); + if (pha->proto->mode_names) + PROCOUT("mode name: %s",pha->proto->mode_names[pha->mode]); + PROCOUT("delay: %d",pha->delay); + PROCOUT("nice: %d",pha->nice); + PROCOUT("verbose: %d",pha->verbose); + PROCOUT("quiet: %d",pha->quiet); + PROCOUT("tot_cmds: %d",pha->tot_cmds); + PROCOUT("tot_bytes: %ld",pha->tot_bytes); + PROCOUT("tot_errs: %d",pha->tot_errs); + + if (pha->pardev) { + PROCOUT("parport device: %s",pha->parname); + PROCOUT("claimed: %d",pha->claimed); + } + if (V_DEBUG) { + PROCOUT("then: %ld",pha->then); + PROCOUT("timeout: %ld",pha->timeout); + PROCOUT("now: %ld",jiffies); + PROCOUT("timer active: %d",pha->timer_active); + PROCOUT("tq_active: %d",pha->tq_active); + PROCOUT("abort_flag: %d",pha->abort_flag); + PROCOUT("return_code: %08x",pha->return_code); + PROCOUT("last_phase: %o",pha->last_phase); + PROCOUT("cmd_count: %d",pha->cmd_count); + PROCOUT("data_count: %d",pha->data_count); + PROCOUT("data_dir: %d",pha->data_dir); + PROCOUT("bulk: %d",pha->bulk); + PROCOUT("tlen: %d",pha->tlen); + PROCOUT("overflow: %d",pha->overflow); + } + + if (offset > len) return 0; + + *start = buffer+offset; len -= offset; + if (len > length) len = length; + return len; +} + +int ppsc_biosparam (Disk * disk, kdev_t dev, int ip[]) +{ + ip[0] = 0x40; + ip[1] = 0x20; + ip[2] = (disk->capacity +1) / (ip[0] * ip[1]); + if (ip[2] > 1024) { + ip[0] = 0xff; + ip[1] = 0x3f; + ip[2] = (disk->capacity +1) / (ip[0] * ip[1]); + if (ip[2] > 1023) + ip[2] = 1023; + } + return 0; +} + +static int ppsc_inquire (PHA *pha, int target, char *buf) +{ + char inq[6] = {0x12,0,0,0,36,0}; + int i; + Scsi_Cmnd cmd; + + cmd.host = pha->host_ptr; + cmd.target = target; + cmd.cmd_len = 6; + for (i=0;i<6;i++) cmd.cmnd[i] = inq[i]; + cmd.use_sg = 0; + cmd.request_buffer = buf; + cmd.request_bufflen = 36; + + return ppsc_command(&cmd); + +} + +static void ppsc_test_mode (PHA *pha, int mode) +{ + int i, t, s, e, f, g, ok, old_mode; + char ibuf[38]; + + if ((mode >= pha->proto->epp_first) && + !(pha->pardev->port->modes & PARPORT_MODE_EPP)) + return; + + old_mode = pha->mode; + pha->mode = mode; + + e = -1; f = -1; g = 0; + + if (pha->proto->test_proto) { + ppsc_claim(pha); + e = pha->proto->test_proto(pha); + ppsc_unclaim(pha); + } + + if (e <= 0) { + f = 0; + for (t=0;t<8;t++) { + s = ppsc_inquire(pha,t,ibuf); + if (s == DID_NO_CONNECT << 16) continue; + if (s) { f++; + break; + } + if (V_FULL) { + for (i=0;i<36;i++) + if ((ibuf[i] < ' ') || (ibuf[i] >= '~')) ibuf[i] = '.'; + ibuf[36] = 0; + printk("%s: port 0x%x mode %d targ %d: %s\n", + pha->device,pha->port,mode,t,ibuf); + } + g++; + } + if (f) ppsc_reset_pha(pha); + } + + ok = (e<=0) && (f == 0); + + if (!ok) pha->mode = old_mode; + + if (V_PROBE) printk("%s: port 0x%3x mode %d test %s (%d,%d,%d)\n", + pha->device,pha->port,mode,ok?"passed":"failed",e,f,g); +} + + +int ppsc_release_pha (PHA *pha) +{ + if (pha->proto->release) pha->proto->release(pha); + + ppsc_unregister_parport(pha); + + MOD_DEC_USE_COUNT; + + return 0; +} + + +int ppsc_detect (PSP *proto, Scsi_Host_Template *tpnt, int verbose) +{ + int i, m, p, d, n, s, z; + struct ppsc_port_list_struct *next_port = NULL; /* shut gcc up */ + int user_specified = 1; + PHA *pha; + int host_count = 0; + struct Scsi_Host *hreg; + + m = 0; + for (i=0;i<4;i++) if ((*proto->params[i])[PPSC_PARM_PORT] != -1) m++; + + if (!m) { + /* Just take parports from the list as they come. */ + next_port = ppsc_port_list; + user_specified = 0; + } + + tpnt->this_id = PPSC_INITIATOR; + + for (i=0;i<4;i++) { + if (!user_specified) { + if (!next_port) + break; + + p = next_port->port->number; + next_port = next_port->next; + } + else { + p = (*proto->params[i])[PPSC_PARM_PORT]; + if (p < 0) + continue; + } + + m = (*proto->params[i])[PPSC_PARM_MODE]; + n = (*proto->params[i])[PPSC_PARM_NICE]; + if (n == -1) n = PPSC_DEF_NICE; + d = (*proto->params[i])[PPSC_PARM_DLY]; + if (d == -1) d = proto->default_delay; + s = (*proto->params[i])[PPSC_PARM_SGTS]; + if (s == -1) s = proto->default_sg_tablesize; + z = (*proto->params[i])[PPSC_PARM_SLOW]; + if (z == -1) z = 0; + + MOD_INC_USE_COUNT; + + pha = &(((*proto->hosts)[i])); + + pha->proto = proto; + + pha->port = p; + pha->delay = d; + pha->nice = n; + + d = sizeof(pha->device)-3; + p = strlen(tpnt->name); + if (p > d) p = d; + for (n=0;ndevice[n] = tpnt->name[n]; + pha->device[p] = '.'; + pha->device[p+1] = '0' + i; + pha->device[p+2] = 0; + + INIT_LIST_HEAD (&pha->tq.list); + pha->tq.sync = 0; + pha->tq.routine = ppsc_tq_int; + pha->tq.data = (void *) pha; + + init_timer (&pha->timer); + pha->timer.data = (unsigned long) pha; + pha->timer.function = ppsc_timer_int; + + init_waitqueue_head (&pha->parq); + pha->pardev = NULL; + pha->claimed = 0; + pha->claim_cont = NULL; + pha->timer_active = 0; + pha->tq_active = 0; + pha->timedout = 0; + + pha->cur_cmd = NULL; + pha->done = NULL; + pha->abort_flag = 0; + pha->protocol_error = 0; + pha->tot_errs = 0; + pha->tot_cmds = 0; + pha->tot_bytes = 0; + + for (n=0;n<8;n++) pha->private[n] = 0; + + pha->slow_targets = z; + + if (ppsc_register_parport(pha,verbose)) { + MOD_DEC_USE_COUNT; + continue; + } + + pha->proto->init(pha); + + pha->verbose = verbose; + pha->quiet = 1; /* no errors until probe over */ + if (V_FULL) pha->quiet = 0; /* unless we want them ... */ + + pha->tmo = PPSC_PROBE_TMO; + + hreg = scsi_register(tpnt,sizeof(PHA*)); + hreg->dma_channel = -1; + hreg->n_io_port = 0; + hreg->unique_id = (int) pha; /* What should we put in here??? */ + hreg->sg_tablesize = s; + hreg->hostdata[0]=(unsigned long)pha; /* Will be our pointer */ + + pha->host_ptr = hreg; + + pha->mode = -1; + + if (m == -1) for (m=0;mnum_modes;m++) + ppsc_test_mode(pha,m); + else ppsc_test_mode(pha,m); + + if (pha->mode != -1) { + + pha->quiet = 0; /* enable PPSC_FAIL msgs */ + pha->tmo = PPSC_GEN_TMO; + host_count++; + + printk("%s: %s at 0x%3x mode %d (%s) dly %d nice %d sg %d\n", + pha->device, + pha->ident, + pha->port, + pha->mode, + (pha->proto->mode_names)? + pha->proto->mode_names[pha->mode]:"", + pha->delay, + pha->nice, + hreg->sg_tablesize); + + } else { + + scsi_unregister(hreg); + ppsc_release_pha(pha); + + } + } + return host_count; +} + +int ppsc_release (struct Scsi_Host *host) +{ + PHA *pha = (PHA *) host->hostdata[0]; + + return ppsc_release_pha(pha); +} + +int ppsc_initialise (void) +{ + int i; + + for (i=0;i<256;i++) ppsc_bulk_map[i] = 0; + +/* commands marked in this map will use pseudo-DMA transfers, while + the rest will use the slow handshaking. +*/ + + ppsc_bulk_map[READ_6] = 1; + ppsc_bulk_map[READ_10] = 1; + ppsc_bulk_map[READ_BUFFER] = 1; + ppsc_bulk_map[WRITE_6] = 1; + ppsc_bulk_map[WRITE_10] = 1; + ppsc_bulk_map[WRITE_BUFFER] = 1; + + if (parport_register_driver (&ppsc_driver)) { + printk (KERN_WARNING "ppscsi: couldn't register driver\n"); + return -EIO; + } + + printk("ppSCSI %s (%s) installed\n",PPSC_VERSION,PPSC_H_VERSION); + return 0; +} + +#ifdef MODULE + +int init_module (void) +{ + return ppsc_initialise(); +} + +void cleanup_module (void) +{ + struct ppsc_port_list_struct *ports, *next; + parport_unregister_driver (&ppsc_driver); + for (ports = ppsc_port_list; ports; ports = next) { + next = ports->next; + parport_put_port (ports->port); + kfree (ports); + } +} + +#endif + +/* end of ppscsi.c */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/ppscsi.h linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/ppscsi.h --- linux-2.4.20-wolk4.1s/drivers/scsi/ppscsi.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/ppscsi.h 2003-06-02 17:23:43.000000000 +0200 @@ -0,0 +1,355 @@ +#ifndef _PPSC_H +#define _PPSC_H + +/* + ppscsi.h (c) 1999 Grant Guenther + Under the terms of the GNU public license. + + This header file defines a common interface for constructing + low-level SCSI drivers for parallel port SCSI adapters. + +*/ + +#define PPSC_H_VERSION "0.92" + +#include +#include +#include +#include +#include +#include +#include "sd.h" +#include "hosts.h" + +/* ppscsi global functions */ + +extern void ppsc_make_map( char map[256], char key[5], int inv); + +extern int ppsc_proc_info(char *,char **,off_t,int,int,int); +extern int ppsc_command(Scsi_Cmnd *); +extern int ppsc_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); +extern int ppsc_abort(Scsi_Cmnd *); +extern int ppsc_reset(Scsi_Cmnd *); +extern int ppsc_biosparam(Disk *, kdev_t, int[]); +extern int ppsc_release(struct Scsi_Host *); + +#ifndef PPSC_BASE + +/* imports for hosts.c */ + +#ifdef CONFIG_PPSCSI_T348 +extern int t348_detect( Scsi_Host_Template *); +#endif + +#ifdef CONFIG_PPSCSI_T358 +extern int t358_detect( Scsi_Host_Template *); +#endif + +#ifdef CONFIG_PPSCSI_ONSCSI +extern int onscsi_detect( Scsi_Host_Template *); +#endif + +#ifdef CONFIG_PPSCSI_EPST +extern int epst_detect( Scsi_Host_Template *); +#endif + +#ifdef CONFIG_PPSCSI_EPSA2 +extern int epsa2_detect( Scsi_Host_Template *); +#endif + +#ifdef CONFIG_PPSCSI_VPI0 +extern int vpi0_detect( Scsi_Host_Template *); +#endif + +#ifdef CONFIG_PPSCSI_SPARCSI +extern int sparcsi_detect( Scsi_Host_Template *); +#endif + +#endif + +#define PPSC_TEMPLATE(proto) { \ + name: #proto, \ + detect: proto##_detect, \ + release: ppsc_release, \ + proc_name: #proto, \ + proc_info: ppsc_proc_info, \ + queuecommand: ppsc_queuecommand, \ + eh_abort_handler: ppsc_abort, \ + eh_bus_reset_handler: ppsc_reset, \ + eh_host_reset_handler: ppsc_reset, \ + bios_param: ppsc_biosparam, \ + can_queue: 1, \ + sg_tablesize: 0, \ + cmd_per_lun: 1, \ + use_clustering: DISABLE_CLUSTERING,\ + use_new_eh_code: 1 \ +} + +/* types used by the actual driver modules */ + +#ifdef PPSC_BASE + +#include +#include +#include +#include +#include +#include + + +struct setup_tab_t { + + char *tag; /* variable name */ + int size; /* number of elements in array */ + int *iv; /* pointer to variable */ +}; + +typedef struct setup_tab_t STT; + +extern void ppsc_gen_setup( STT t[], int n, char *ss ); + +typedef struct ppsc_host_adapter PHA; + +struct ppsc_host_adapter { + + char ident[80]; /* Adapter name and version info */ + + char device[12]; /* device name for messages */ + + struct Scsi_Host *host_ptr; /* SCSI host structure */ + struct ppsc_protocol *proto; /* adapter protocol */ + + int port; /* parallel port base address */ + int mode; /* transfer mode in use */ + int delay; /* parallel port settling delay */ + int saved_r0; /* saved port state */ + int saved_r2; /* saved port state */ + + int reserved; /* number of ports reserved */ + int tmo; /* default command timeout */ + int verbose; /* logging level */ + int quiet; /* do not log PPSC_FAIL msgs */ + + int slow_targets; /* bit mask for disabling block mode */ + + wait_queue_head_t parq; /* semaphore for parport sharing */ + struct pardevice *pardev; /* pointer to pardevice */ + const char *parname; /* parport name */ + int claimed; /* parport has been claimed */ + void (*claim_cont)(PHA *); /* continuation for parport wait */ + + void (*continuation)(PHA *); /* next "interrupt" handler */ + int (*ready)(PHA *); /* current ready test */ + long then; /* jiffies at start of last wait */ + long timeout; /* when to timeout this wait */ + int timedout; /* timeout was seen */ + int timer_active; /* we're using a timer */ + int tq_active; /* we have a task queued */ + int nice; /* tune the CPU load */ + struct timer_list timer; /* timer queue element */ + struct tq_struct tq; /* task queue element */ + + int private[8]; /* for the protocol layer, if needed */ + char *priv_ptr; + int priv_flag; + + Scsi_Cmnd *cur_cmd; /* current command on this host */ + void (*done)(Scsi_Cmnd *); /* current "done" function */ + + int overflow; /* excess bytes transferred */ + int bulk; /* should we use block mode ? */ + int tlen; /* total transfer length */ + int abort_flag; /* abort=1 reset=2 requested */ + int return_code; /* build return value here */ + + struct scatterlist *sg_list; /* current fragment, if any */ + int sg_count; /* remaining fragments */ + char *cur_buf; /* current buffer pointer */ + int cur_len; /* remaining bytes in buffer */ + + struct timer_list sleeper; /* for BUSY handling */ + + int last_phase; /* to detect phase changes */ + char message_byte; + char status_byte; + + int cmd_count; /* bytes of command transfered */ + int data_count; /* bytes of data transferred */ + int data_dir; /* direction of transfer */ + + int tot_cmds; /* number of commands processed */ + long tot_bytes; /* total bytes transferred */ + int tot_errs; /* number of failed commands */ + + int protocol_error; /* Some protocols can set this + != zero to signal a fatal error + we report it and expect to die + */ +}; + +/* constants for 'verbose' */ + +#define PPSC_VERB_NORMAL 0 +#define PPSC_VERB_PROBE 1 +#define PPSC_VERB_TRACE 2 +#define PPSC_VERB_DEBUG 3 +#define PPSC_VERB_FULL 4 + +#define V_PROBE (pha->verbose >= PPSC_VERB_PROBE) +#define V_TRACE (pha->verbose >= PPSC_VERB_TRACE) +#define V_DEBUG (pha->verbose >= PPSC_VERB_DEBUG) +#define V_FULL (pha->verbose >= PPSC_VERB_FULL) + +/* constants for abort_flag */ + +#define PPSC_DO_ABORT 1 +#define PPSC_DO_RESET 2 + + +struct ppsc_protocol { + + int (*params[4])[8]; /* hostN tuning parameters */ + + PHA (*hosts)[4]; /* actual PHA structs */ + + int num_modes; /* number of modes*/ + int epp_first; /* modes >= this use 8 ports */ + int default_delay; /* delay parameter if not specified */ + + int can_message; /* adapter can send/rcv SCSI msgs */ + int default_sg_tablesize; /* sg_tablesize if not specified */ + + char **mode_names; /* printable names of comm. modes */ + +/* first two functions are NOT called with the port claimed. */ + + void (*init)(PHA *); /* (pha) + protocol initialisation + should fill in pha->ident */ + void (*release)(PHA *); /* (pha) optional + protocol no longer in use */ + void (*connect)(PHA *); /* (pha) + connect to adapter */ + void (*disconnect)(PHA *); /* (pha) + release adapter */ + int (*test_proto)(PHA *); /* (pha) optional + test protocol in current settings, + returns error count */ + int (*select)(PHA *,int,int); /* (pha,initiator,target) + start artibration and selection + 0 = OK, -1 = arb. failed */ + int (*test_select)(PHA *); /* (pha) + test for selection to complete + 1 = OK, 0 try again */ + void (*select_finish)(PHA *); /* (pha) optional + called after successful select */ + void (*deselect)(PHA *); /* (pha) + release SCSI bus */ + int (*get_bus_status)(PHA *); /* (pha) + return (REQ,BSY,MSG,C/D,I/O) */ + void (*slow_start)(PHA *,char *); /* (pha,byte) + start transfer of one byte using + explicit handshaking */ + int (*slow_done)(PHA *); /* (pha) + has the device acked the byte ? */ + void (*slow_end)(PHA *); /* (pha) + shut down the slow transfer */ + void (*start_block)(PHA *,int); /* (pha,read) + start data transfer */ + int (*transfer_block)(PHA *,char *,int,int); + /* (pha,buf,len,read) + transfer as much as possible and + return count of bytes + can return -1 if error detected */ + int (*transfer_ready)(PHA *pha);/* (pha) + can we go again yet ? + >0 = yes, 0 = try again, -1 = done */ + int (*transfer_done)(PHA *pha); /* (pha) + has all data been flushed ? + 1 = yes, 0 = try again */ + void (*end_block)(PHA *,int); /* (pha,read) + shut down block transfer */ + void (*reset_bus)(PHA *); /* (pha) optional + reset SCSI bus if possible */ + +}; + +/* constants for the params array */ + +#define PPSC_PARM_PORT 0 +#define PPSC_PARM_MODE 1 +#define PPSC_PARM_DLY 2 +#define PPSC_PARM_NICE 3 +#define PPSC_PARM_SGTS 4 +#define PPSC_PARM_SLOW 5 + +/* constants for get_bus_status */ + +#define PPSC_REQ 16 +#define PPSC_BSY 8 +#define PPSC_MSG 4 +#define PPSC_CD 2 +#define PPSC_IO 1 + +/* phases */ + +#define PPSC_PH_NONE 0 +#define PPSC_PH_WRITE (PPSC_REQ|PPSC_BSY) +#define PPSC_PH_READ (PPSC_PH_WRITE|PPSC_IO) +#define PPSC_PH_CMD (PPSC_PH_WRITE|PPSC_CD) +#define PPSC_PH_STAT (PPSC_PH_READ|PPSC_CD) +#define PPSC_PH_MSGIN (PPSC_PH_STAT|PPSC_MSG) + +typedef struct ppsc_protocol PSP; + +extern int ppsc_detect( PSP *, Scsi_Host_Template *, int); + +#ifdef PPSC_HA_MODULE + +static int verbose = PPSC_VERB_NORMAL; + +static int host0[8] = {-1,-1,-1,-1,-1,-1,-1,-1}; +static int host1[8] = {-1,-1,-1,-1,-1,-1,-1,-1}; +static int host2[8] = {-1,-1,-1,-1,-1,-1,-1,-1}; +static int host3[8] = {-1,-1,-1,-1,-1,-1,-1,-1}; + +#ifndef MODULE + +static STT stt[4] = { {"host0",8,host0}, + {"host1",8,host1}, + {"host2",8,host2}, + {"host3",8,host3} }; +#endif + +MODULE_PARM(host0,"1-8i"); +MODULE_PARM(host1,"1-8i"); +MODULE_PARM(host2,"1-8i"); +MODULE_PARM(host3,"1-8i"); +MODULE_PARM(verbose,"i"); + +static struct ppsc_host_adapter host_structs[4]; + +#define delay_p (pha->delay?udelay(pha->delay):0) +#define out_p(offs,byte) outb(byte,pha->port+offs); delay_p; +#define in_p(offs) (delay_p,inb(pha->port+offs)) + +#define w0(byte) do {out_p(0,byte);} while (0) +#define r0() (in_p(0) & 0xff) +#define w1(byte) do {out_p(1,byte);} while (0) +#define r1() (in_p(1) & 0xff) +#define w2(byte) do {out_p(2,byte);} while (0) +#define r2() (in_p(2) & 0xff) +#define w3(byte) do {out_p(3,byte);} while (0) +#define w4(byte) do {out_p(4,byte);} while (0) +#define r4() (in_p(4) & 0xff) +#define w4w(data) do {outw(data,pha->port+4); delay_p;} while (0) +#define w4l(data) do {outl(data,pha->port+4); delay_p;} while (0) +#define r4w() (delay_p,inw(pha->port+4)&0xffff) +#define r4l() (delay_p,inl(pha->port+4)&0xffffffff) + +#endif /* PPSC_HA_MODULE */ +#endif /* PPSC_BASE */ +#endif /* _PPSC_H */ + +/* end of ppscsi.h */ + diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/scsi.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/scsi.c --- linux-2.4.20-wolk4.1s/drivers/scsi/scsi.c 2003-05-15 21:52:34.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/scsi.c 2003-06-02 17:23:43.000000000 +0200 @@ -1899,6 +1899,26 @@ static int proc_scsi_gen_write(struct fi err=scsi_remove_single_device(HBA_ptr, channel, id, lun); goto out; } + /* + * Usage: echo "scsi scan-new-devices" >/proc/scsi/scsi + * + * Scans all host adapters again to see if there are any + * new devices. + */ +#define SCAN_DEVICES_RATE 18000UL + else if(!strncmp("scan-new-devices", buffer + 5, 16)) { + static unsigned long last = 0; + + if (last != 0 && jiffies < (last + SCAN_DEVICES_RATE)){ + err=-EINVAL; + goto out; + } + last = jiffies; + err = length; + printk("scsi scan-new-devices\n"); + scsi_scan_new_devices(); + goto out; + } out: free_page((unsigned long) buffer); @@ -2446,10 +2466,16 @@ int scsi_register_module(int module_type /* Load upper level device handler of some kind */ case MODULE_SCSI_DEV: + /* Don't request scsi_hostadapter module when scsi_mod is */ + /* a module because that claimed an error at initrd */ + /* That is obselete when it is compiled as module because */ + /* scsi_mod is loaded before hostadapter via dependence */ +#ifndef MODULE #ifdef CONFIG_KMOD if (scsi_hosts == NULL) request_module("scsi_hostadapter"); #endif +#endif return scsi_register_device_module((struct Scsi_Device_Template *) ptr); /* The rest of these are not yet implemented */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/scsi.h linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/scsi.h --- linux-2.4.20-wolk4.1s/drivers/scsi/scsi.h 2003-05-15 21:52:34.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/scsi.h 2003-06-03 11:48:33.000000000 +0200 @@ -576,6 +576,7 @@ struct scsi_device { char type; char scsi_level; char vendor[8], model[16], rev[4]; + int bflags; /* store the device flags for later use */ unsigned char current_tag; /* current tag */ unsigned char sync_min_period; /* Not less than this period */ unsigned char sync_max_offset; /* Not greater than this offset */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/scsi_obsolete.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/scsi_obsolete.c --- linux-2.4.20-wolk4.1s/drivers/scsi/scsi_obsolete.c 2003-05-15 21:52:34.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/scsi_obsolete.c 2003-06-05 10:03:46.000000000 +0200 @@ -106,21 +106,14 @@ static unsigned char generic_sense[6] = static void scsi_dump_status(void); #endif - -#ifdef DEBUG -#define SCSI_TIMEOUT (5*HZ) -#else -#define SCSI_TIMEOUT (2*HZ) -#endif - #ifdef DEBUG #define SENSE_TIMEOUT SCSI_TIMEOUT #define ABORT_TIMEOUT SCSI_TIMEOUT #define RESET_TIMEOUT SCSI_TIMEOUT #else -#define SENSE_TIMEOUT (5*HZ/10) -#define RESET_TIMEOUT (5*HZ/10) -#define ABORT_TIMEOUT (5*HZ/10) +#define SENSE_TIMEOUT (10*HZ/10) +#define RESET_TIMEOUT (2*HZ/10) +#define ABORT_TIMEOUT (15*HZ/10) #endif diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/scsi_scan.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/scsi_scan.c --- linux-2.4.20-wolk4.1s/drivers/scsi/scsi_scan.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/scsi_scan.c 2003-06-05 10:03:46.000000000 +0200 @@ -598,7 +598,7 @@ static int scan_scsis_single(unsigned in scsi_wait_req (SRpnt, (void *) scsi_cmd, (void *) scsi_result, - scsi_cmd[4], SCSI_TIMEOUT+4*HZ, 3); + scsi_cmd[4], SCSI_TIMEOUT+15*HZ, 3); SCSI_LOG_SCAN_BUS(3, printk("scsi: INQUIRY %s with code 0x%x\n", SRpnt->sr_result ? "failed" : "successful", SRpnt->sr_result)); @@ -645,7 +645,7 @@ static int scan_scsis_single(unsigned in /* * Get any flags for this device. */ - bflags = get_device_flags (scsi_result); + SDpnt->bflags = bflags = get_device_flags (scsi_result); if (bflags & BLIST_SPARSELUN) { *sparse_lun = 1; @@ -948,3 +948,56 @@ static int find_lun0_scsi_level(unsigned /* haven't found lun0, should send INQUIRY but take easy route */ return res; } + +/* scan the hosts for new devices using the explicit hardcoded call to + * scan_scsis. + */ +void scsi_scan_new_devices(void) +{ + struct Scsi_Host *shpnt; + int channel,dev, order_dev; + + for (shpnt = scsi_hostlist; shpnt != NULL; shpnt = shpnt->next) { + for (channel = 0; channel <= shpnt->max_channel; channel++){ + for (dev = 0; dev < shpnt->max_id; ++dev) { + if( shpnt->reverse_ordering) + /* Shift to scanning 15,14,13... or 7,6,5,4, */ + order_dev = shpnt->max_id-dev-1; + else + order_dev = dev; + if (shpnt->this_id != order_dev) { + Scsi_Device *sdev; + /* first check to see if we've already seen this device */ + for(sdev = shpnt->host_queue; sdev; sdev = sdev->next) { + if(sdev->channel == channel + && sdev->id == order_dev + && sdev->lun == 0) { + break; + } + } + if (sdev) continue; + scan_scsis(shpnt, 1, channel, order_dev, 0); + /* now check to see if we found lun 0 */ + for(sdev = shpnt->host_queue; sdev; sdev = sdev->next) { + if(sdev->channel == channel + && sdev->id == order_dev + && sdev->lun == 0) { + break; + } + } + if(sdev && sdev->type == TYPE_DISK && + !(sdev->bflags & BLIST_NOLUN)) { + int lun, max_lun; + if(sdev->scsi_level == SCSI_3 || + sdev->bflags & BLIST_FORCELUN) + max_lun = shpnt->max_lun; + else + max_lun = min_t(unsigned, 8, shpnt->max_lun); + for(lun = 1; lun < max_lun; lun++) + scan_scsis(shpnt, 1, channel, order_dev, lun); + } + } /* this_id != dev */ + } /* for dev */ + } /* for channel */ + } /* for host */ +} diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/scsi_syms.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/scsi_syms.c --- linux-2.4.20-wolk4.1s/drivers/scsi/scsi_syms.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/scsi_syms.c 2003-06-02 17:04:01.000000000 +0200 @@ -82,6 +82,7 @@ EXPORT_SYMBOL(scsi_end_request); EXPORT_SYMBOL(scsi_register_blocked_host); EXPORT_SYMBOL(scsi_deregister_blocked_host); +EXPORT_SYMBOL(scsi_scan_new_devices); /* * This symbol is for the highlevel drivers (e.g. sg) only. diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/scsimon.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/scsimon.c --- linux-2.4.20-wolk4.1s/drivers/scsi/scsimon.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/scsimon.c 2003-06-02 17:23:43.000000000 +0200 @@ -0,0 +1,890 @@ +/* + SCSI upper level driver that permits user applications to monitor + the state of SCSI devices and hosts. The original purpose of this + driver is to support hotplugging notification. + + * Copyright (C) 2001 Douglas Gilbert + * + * 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, or (at your option) + * any later version. + * + */ +#include +/* static char * scsimon_version_str = "Version: 0.0.92 (20010313)"; */ + static int scsimon_version_num = 92; /* 2 digits for each component */ + +/* + * For more information contact: + * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au) + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include "scsi.h" +#include "hosts.h" +#include +#include + +#ifndef LINUX_VERSION_CODE +#include +#endif /* LINUX_VERSION_CODE */ + + +static int scsimon_init(void); +static int scsimon_attach(Scsi_Device *); +static void scsimon_finish(void); +static int scsimon_detect(Scsi_Device *); +static void scsimon_detach(Scsi_Device *); + +static struct Scsi_Device_Template scsimon_template = +{ + name:"scsimon", + tag:"scsimon", + scsi_type:0xff, + major:MISC_MAJOR, + detect:scsimon_detect, + init:scsimon_init, + finish:scsimon_finish, + attach:scsimon_attach, + detach:scsimon_detach +}; + + +static int scsimon_open(struct inode * inode, struct file * filp); +static int scsimon_release(struct inode * inode, struct file * filp); +static ssize_t scsimon_read(struct file * filp, char * buf, + size_t count, loff_t *ppos); +static int scsimon_ioctl(struct inode * inode, struct file * filp, + unsigned int cmd_in, unsigned long arg); +static unsigned int scsimon_poll(struct file * filp, poll_table * wait); +static int scsimon_fasync(int fd, struct file * filp, int mode); + +static struct file_operations scsimon_fops = { + owner: THIS_MODULE, + read: scsimon_read, + poll: scsimon_poll, + ioctl: scsimon_ioctl, + open: scsimon_open, + release: scsimon_release, + fasync: scsimon_fasync, +}; + +static struct miscdevice scsimon_miscdev = { + SCSIMON_MINOR, + "scsimon", + &scsimon_fops +}; + + +typedef struct scsimon_fd /* holds the state of a file descriptor */ +{ + struct scsimon_fd * nextfp; /* NULL when last opened fd */ + struct fasync_struct * async_qp; /* for asynchronous notification */ +} Sm_fd; + +typedef struct scsimon_attached +{ + struct scsimon_attached * next_att; /* NULL if last */ + Scsi_Device * device; + unsigned int host; + unsigned int bus; + unsigned int target; + unsigned int lun; + unsigned long time_attached; /* jiffy count when attached */ + unsigned long event_count; +} Sm_attached; + +typedef struct scsimon_detached +{ + struct scsimon_detached * next_det; /* NULL if last */ + unsigned int host; + unsigned int bus; + unsigned int target; + unsigned int lun; + char vendor[8]; + char model[16]; + char rev[4]; + char host_name[16]; + char host_info[80]; + char scsi_type; + char scsi_level; /* as in SCSI field in INQ */ + char removable; + char emulated; + unsigned long time_detached; /* jiffy count when detached */ + unsigned long event_count; /* event count when detached */ + unsigned long event_attached; /* event count when attached */ +} Sm_detached; + +typedef struct scsimon_hotinfo +{ + int action; /* 0 -> attach, 1 -> detach */ + unsigned int host; + unsigned int bus; + unsigned int target; + unsigned int lun; + unsigned long event_attached; + unsigned long event_detached; + char vendor[8]; + char model[16]; + char rev[4]; + char scsi_type; + char removable; + char emulated; +} Sm_hotinfo; + +static rwlock_t scsimon_lock = RW_LOCK_UNLOCKED; + +/* static Sm_fd * sm_fd_rootp; */ +static Sm_attached * sm_att_rootp; +static Sm_detached * sm_det_rootp; +static int sm_locked_down; /* hack to keep module loaded */ +static unsigned long sm_event_count; /* bumped on each change */ +static unsigned long sm_init_time; +static int sm_max_detached_elems = 10; /* forgets oldest */ +static int sm_flag_attached; +static int sm_flag_detached; + +static void sm_trunc_alist(int fromPos); +static void sm_trunc_dlist(int fromPos); +static Sm_fd * sm_add_sfp(void); +static void sm_remove_sfp(Sm_fd *); +static void sm_read_state(struct scsimon_state *); +static void sm_read_att_list(struct scsimon_att_list *); +static void sm_read_det_list(struct scsimon_det_list *); +static void sm_read_host_list(struct scsimon_host_list *); +static void sm_call_policy (Sm_hotinfo *); + + +static int scsimon_open(struct inode * inode, struct file * filp) +{ + Sm_fd * sfp; + + SCSI_LOG_TIMEOUT(3, printk("scsimon_open: flags=0x%x\n", + filp->f_flags)); + if ((sfp = sm_add_sfp())) + filp->private_data = sfp; + else + return -ENOMEM; + return 0; +} + +static int scsimon_release(struct inode * inode, struct file * filp) +{ + Sm_fd * sfp; + + lock_kernel(); + if (! (sfp = (Sm_fd *)filp->private_data)) { + unlock_kernel(); + return -ENXIO; + } + SCSI_LOG_TIMEOUT(3, printk("scsimon_release:\n")); + scsimon_fasync(-1, filp, 0); /* remove from async notify list */ + filp->private_data = NULL; + sm_remove_sfp(sfp); + unlock_kernel(); + return 0; +} + +static ssize_t scsimon_read(struct file * filp, char * buf, + size_t count, loff_t *ppos) +{ + Sm_fd * sfp; + unsigned long iflags; + + SCSI_LOG_TIMEOUT(3, printk("scsimon_read: count=%d\n", (int)count)); + if (! (sfp = (Sm_fd *)filp->private_data)) + return -ENXIO; + write_lock_irqsave(&scsimon_lock, iflags); + sm_flag_attached = 0; + sm_flag_detached = 0; + write_unlock_irqrestore(&scsimon_lock, iflags); + return count; +} + +static int scsimon_ioctl(struct inode * inode, struct file * filp, + unsigned int cmd_in, unsigned long arg) +{ + int val, result, read_only; + Sm_fd * sfp; + + if (! (sfp = (Sm_fd *)filp->private_data)) + return -ENXIO; + SCSI_LOG_TIMEOUT(3, printk("scsimon_ioctl: cmd=0x%x\n", (int)cmd_in)); + read_only = (O_RDWR != (filp->f_flags & O_ACCMODE)); + + switch(cmd_in) + { + case SCSIMON_LOCK_MOD: + if (0 == sm_locked_down) { + sm_locked_down++; + MOD_INC_USE_COUNT; + } + return 0; + case SCSIMON_UNLOCK_MOD: + if (sm_locked_down > 0) { + sm_locked_down--; + MOD_DEC_USE_COUNT; + } + return 0; + case SCSIMON_GET_VERSION_NUM: + return put_user(scsimon_version_num, (int *)arg); + case SCSIMON_SET_MX_DLIST_LEN: + result = get_user(val, (int *)arg); + if (result) return result; + sm_max_detached_elems = val; + return 0; + case SCSIMON_GET_MX_DLIST_LEN: + return put_user(sm_max_detached_elems, (int *)arg); + case SCSIMON_GET_STATE: + result = verify_area(VERIFY_WRITE, (void *)arg, + sizeof(struct scsimon_state)); + if (result) return result; + else { + struct scsimon_state ss; + + sm_read_state(&ss); + __copy_to_user((void *)arg, &ss, + sizeof(struct scsimon_state)); + return 0; + } + case SCSIMON_GET_ATT_LIST: + { + struct scsimon_att_list * sm_alp = + (struct scsimon_att_list *)arg; + struct scsimon_att_list * sm_alop; + size_t sz = sizeof(struct scsimon_att_list); + + result = verify_area(VERIFY_WRITE, (void *)arg, sz); + if (result) return result; + __get_user(val, &sm_alp->max_num); + if (val > 1) { + sz += ((val - 1) * + sizeof(struct scsimon_att_dev)); + result = verify_area(VERIFY_WRITE, + (void *)arg, sz); + if (result) return result; + } + sm_alop = (struct scsimon_att_list *) + kmalloc(sz, GFP_ATOMIC); + if (NULL == sm_alop) + return -ENOMEM; + memset(sm_alop, 0, sz); + sm_alop->max_num = val; + __get_user(sm_alop->match_event, &sm_alp->match_event); + __get_user(sm_alop->flags, &sm_alp->flags); + sm_read_att_list(sm_alop); + __copy_to_user((void *)arg, sm_alop, sz); + kfree((char *)sm_alop); + return 0; + } + case SCSIMON_GET_DET_LIST: + { + struct scsimon_det_list * sm_dlp = + (struct scsimon_det_list *)arg; + struct scsimon_det_list * sm_dlop; + size_t sz = sizeof(struct scsimon_det_list); + + result = verify_area(VERIFY_WRITE, (void *)arg, sz); + if (result) return result; + __get_user(val, &sm_dlp->max_num); + if (val > 1) { + sz += ((val - 1) * + sizeof(struct scsimon_det_dev)); + result = verify_area(VERIFY_WRITE, + (void *)arg, sz); + if (result) return result; + } + sm_dlop = (struct scsimon_det_list *) + kmalloc(sz, GFP_ATOMIC); + if (NULL == sm_dlop) + return -ENOMEM; + memset(sm_dlop, 0, sz); + sm_dlop->max_num = val; + __get_user(sm_dlop->match_event, &sm_dlp->match_event); + __get_user(sm_dlop->flags, &sm_dlp->flags); + sm_read_det_list(sm_dlop); + __copy_to_user((void *)arg, sm_dlop, sz); + kfree((char *)sm_dlop); + return 0; + } + case SCSIMON_GET_HOST_LIST: + { + struct scsimon_host_list * sm_hlp = + (struct scsimon_host_list *)arg; + struct scsimon_host_list * sm_hlop; + size_t sz = sizeof(struct scsimon_host_list); + + result = verify_area(VERIFY_WRITE, (void *)arg, sz); + if (result) return result; + __get_user(val, &sm_hlp->max_num); + if (val > 1) { + sz += ((val - 1) * + sizeof(struct scsimon_host)); + result = verify_area(VERIFY_WRITE, + (void *)arg, sz); + if (result) return result; + } + sm_hlop = (struct scsimon_host_list *) + kmalloc(sz, GFP_ATOMIC); + if (NULL == sm_hlop) + return -ENOMEM; + memset(sm_hlop, 0, sz); + sm_hlop->max_num = val; + __get_user(sm_hlop->host, &sm_hlp->host); + __get_user(sm_hlop->flags, &sm_hlp->flags); + sm_read_host_list(sm_hlop); + __copy_to_user((void *)arg, sm_hlop, sz); + kfree((char *)sm_hlop); + return 0; + } + default: + return -EINVAL; + } +} + +/* Use POLLIN for attach, POLLHUP for detach and a read() clears flags */ +static unsigned int scsimon_poll(struct file * filp, poll_table * wait) +{ + unsigned int res = 0; + Sm_fd * sfp; + + if (! (sfp = (Sm_fd *)filp->private_data)) + return POLLERR; + if (sm_flag_attached) + res = POLLIN | POLLRDNORM; + if (sm_flag_detached) + res |= POLLHUP; + SCSI_LOG_TIMEOUT(3, printk("scsimon_poll: res=0x%x\n", (int)res)); + return res; +} + +static int scsimon_fasync(int fd, struct file * filp, int mode) +{ + int retval; + Sm_fd * sfp; + + SCSI_LOG_TIMEOUT(3, printk("scsimon_fasync: mode=%d\n", mode)); + if (! (sfp = (Sm_fd *)filp->private_data)) + return -ENXIO; + retval = fasync_helper(fd, filp, mode, &sfp->async_qp); + return (retval < 0) ? retval : 0; +} + +static int scsimon_detect(Scsi_Device * scsidp) +{ + return 1; +} + +/* Driver initialization */ +static int scsimon_init() +{ + SCSI_LOG_TIMEOUT(3, printk("scsimon_init\n")); + return 0; +} + +static int scsimon_attach(Scsi_Device * scsidp) +{ + unsigned long iflags; + Sm_attached * sap; + Sm_hotinfo shi; + Scsi_Device * sdp; + + SCSI_LOG_TIMEOUT(3, printk("scsimon_attach: scsidp=%p\n", scsidp)); + write_lock_irqsave(&scsimon_lock, iflags); + sap = (Sm_attached *)kmalloc(sizeof(Sm_attached), GFP_ATOMIC); + if (NULL == sap) { + scsidp->attached--; + write_unlock_irqrestore(&scsimon_lock, iflags); + printk(KERN_WARNING "scsimon_attach: no kernel memory\n"); + return 1; + } + memset(sap, 0, sizeof(Sm_attached)); + memset(&shi, 0, sizeof(Sm_hotinfo)); + sm_event_count++; + sap->event_count = sm_event_count; + shi.action = 0; /* attach */ + shi.event_attached = sap->event_count; + sap->time_attached = jiffies; + sap->device = scsidp; + sap->host = scsidp->host->host_no; + shi.host = sap->host; + sap->bus = scsidp->channel; + shi.bus = sap->bus; + sap->target = scsidp->id; + shi.target = sap->target; + sap->lun = scsidp->lun; + shi.lun = sap->lun; + sdp = sap->device; + if (sdp->vendor) + memcpy(shi.vendor, sdp->vendor, sizeof(shi.vendor)); + if (sdp->model) + memcpy(shi.model, sdp->model, sizeof(shi.model)); + if (sdp->rev) + memcpy(shi.rev, sdp->rev, sizeof(shi.rev)); + shi.scsi_type = sdp->type; + shi.removable = sdp->removable; + shi.emulated = sdp->host->hostt->emulated; + + sap->next_att = sm_att_rootp; + sm_att_rootp = sap; /* prepend to attached list */ + + sm_flag_attached = 1; + scsimon_template.nr_dev++; /* currently attached devices */ + scsimon_template.dev_noticed++;/* total attachment count */ + write_unlock_irqrestore(&scsimon_lock, iflags); + sm_call_policy(&shi); + return 0; +} + +static void scsimon_finish(void) +{ + SCSI_LOG_TIMEOUT(3, printk("scsimon_finish\n")); +} + +static void scsimon_detach(Scsi_Device * scsidp) +{ + unsigned long iflags; + Sm_attached * sap; + Sm_attached * psap = NULL; + Sm_detached * sep; + Scsi_Device * sdp; + Sm_hotinfo shi; + + SCSI_LOG_TIMEOUT(3, printk("scsimon_detach: scsidp=%p\n", scsidp)); + write_lock_irqsave(&scsimon_lock, iflags); + for (sap = sm_att_rootp; sap; sap = sap->next_att) { + if (scsidp == sap->device) + break; + psap = sap; + } + sep = (Sm_detached *)kmalloc(sizeof(Sm_detached), GFP_ATOMIC); + if ((NULL == sap) || (NULL == sep)) { + write_unlock_irqrestore(&scsimon_lock, iflags); + printk(KERN_WARNING "scsimon_detach: missing attach or " + "no kernel memory\n"); + return; + } + memset(sep, 0, sizeof(Sm_detached)); + memset(&shi, 0, sizeof(Sm_hotinfo)); + shi.action = 1; /* flags detach */ + sm_event_count++; + /* xfer from alist element to new dlist element */ + sep->host = sap->host; + shi.host = sep->host; + sep->bus = sap->bus; + shi.bus = sep->bus; + sep->target = sap->target; + shi.target = sep->target; + sep->lun = sap->lun; + shi.lun = sep->lun; + sdp = sap->device; + if (sdp->vendor) + memcpy(sep->vendor, sdp->vendor, sizeof(sep->vendor)); + memcpy(shi.vendor, sep->vendor, sizeof(shi.vendor)); + if (sdp->model) + memcpy(sep->model, sdp->model, sizeof(sep->model)); + memcpy(shi.model, sep->model, sizeof(shi.model)); + if (sdp->rev) + memcpy(sep->rev, sdp->rev, sizeof(sep->rev)); + memcpy(shi.rev, sep->rev, sizeof(shi.rev)); + if (sdp->host->hostt->name) + strncpy(sep->host_name, sdp->host->hostt->name, + sizeof(sep->host_name)); + if (sdp->host->hostt->info) + strncpy(sep->host_info, sdp->host->hostt->info(sdp->host), + sizeof(sep->host_info)); + sep->scsi_type = sdp->type; + shi.scsi_type = sep->scsi_type; + sep->scsi_level = sdp->scsi_level; + if (sep->scsi_level > 1) + --sep->scsi_level; + sep->removable = sdp->removable; + shi.removable = sep->removable; + sep->emulated = sdp->host->hostt->emulated; + shi.emulated = sep->emulated; + sep->event_count = sm_event_count; + shi.event_detached = sep->event_count; + sep->event_attached = sap->event_count; + shi.event_attached = sep->event_attached; + sep->time_detached = jiffies; + + if (NULL == psap) + sm_att_rootp = sap->next_att; + else + psap->next_att = sap->next_att; + kfree((char *)sap); + sep->next_det = sm_det_rootp; + sm_det_rootp = sep; /* prepend to detached list */ + + sm_flag_detached = 1; + scsidp->attached--; + scsimon_template.nr_dev--; /* currently attached devices */ + scsimon_template.dev_max++; /* total detachment count */ + + sm_trunc_dlist(sm_max_detached_elems); + write_unlock_irqrestore(&scsimon_lock, iflags); + sm_call_policy(&shi); + return; +} + +static void sm_trunc_alist(int fromPos) +{ + Sm_attached * sap = sm_att_rootp; + Sm_attached * psap = NULL; + Sm_attached * nsap; + int k; + + for (k = 0; ((k < fromPos) && sap); ++k, sap = sap->next_att) + psap = sap; + if (sap) { + while (sap) { + nsap = sap->next_att; + kfree((char *)sap); + sap = nsap; + } + if (NULL == psap) + sm_att_rootp = NULL; + else + psap->next_att = NULL; + } +} + +static void sm_trunc_dlist(int fromPos) +{ + Sm_detached * sep = sm_det_rootp; + Sm_detached * psep = NULL; + Sm_detached * nsep; + int k; + + for (k = 0; ((k < fromPos) && sep); ++k, sep = sep->next_det) + psep = sep; + if (sep) { + while (sep) { + nsep = sep->next_det; + kfree((char *)sep); + sep = nsep; + } + if (NULL == psep) + sm_det_rootp = NULL; + else + psep->next_det = NULL; + } +} + +static Sm_fd * sm_add_sfp() +{ + Sm_fd * sfp; + + if ((sfp = (Sm_fd *)kmalloc(sizeof(Sm_fd), GFP_ATOMIC))) + memset(sfp, 0, sizeof(Sm_fd)); + return sfp; +} + +static void sm_remove_sfp(Sm_fd * sfp) +{ + kfree((char *)sfp); +} + +static void sm_read_state(struct scsimon_state * ssp) +{ + Sm_detached * sep; + struct Scsi_Host * shp; + int k; + unsigned int high_host = 0; + unsigned long iflags; + + read_lock_irqsave(&scsimon_lock, iflags); + jiffies_to_timespec(sm_init_time, &ssp->init_time); + ssp->devices_attached = scsimon_template.nr_dev; + ssp->total_attachs = scsimon_template.dev_noticed; + ssp->total_detachs = scsimon_template.dev_max; + for (k = 0, sep = sm_det_rootp; sep; k++, sep = sep->next_det) + ; + ssp->detach_list_len = (unsigned int)k; + ssp->event_count = sm_event_count; + ssp->lock_mod_state = sm_locked_down; + for (k = 0, shp = scsi_hostlist; shp; shp = shp->next, ++k) { + if (shp->host_no > high_host) + high_host = shp->host_no; + } + ssp->count_hosts = k; + ssp->high_host = high_host; + read_unlock_irqrestore(&scsimon_lock, iflags); +} + +static void sm_read_att_elem(struct scsimon_att_dev * sm_ap, + Sm_attached * sap) +{ + Scsi_Device * sdp = sap->device; + + sm_ap->att_event = sap->event_count; + jiffies_to_timespec(sap->time_attached, &sm_ap->att_time); + sm_ap->d.host = sap->host; + sm_ap->d.bus = sap->bus; + sm_ap->d.target = sap->target; + sm_ap->d.lun = sap->lun; + memcpy(sm_ap->d.vendor, sdp->vendor, sizeof(sm_ap->d.vendor)); + memcpy(sm_ap->d.model, sdp->model, sizeof(sm_ap->d.model)); + memcpy(sm_ap->d.rev, sdp->rev, sizeof(sm_ap->d.rev)); + sm_ap->d.scsi_type = sdp->type; + sm_ap->d.scsi_level = sdp->scsi_level; + if (sm_ap->d.scsi_level > 1) + --sm_ap->d.scsi_level; + sm_ap->d.removable = sdp->removable; + sm_ap->d.emulated = sdp->host->hostt->emulated; +} + +static void sm_read_att_list(struct scsimon_att_list * alp) +{ + Sm_attached * sap; + int k; + unsigned long iflags; + + read_lock_irqsave(&scsimon_lock, iflags); + alp->curr_event = sm_event_count; + for (k = 0, sap = sm_att_rootp; (k < alp->max_num) && sap; + sap = sap->next_att) { + if (alp->match_event > 0) { + if (alp->match_event == sap->event_count) { + k = 1; + sm_read_att_elem(&alp->arr[0], sap); + break; + } + continue; + } + sm_read_att_elem(&alp->arr[k], sap); + k++; + } + alp->num_out = k; + read_unlock_irqrestore(&scsimon_lock, iflags); +} + +static void sm_read_det_elem(struct scsimon_det_dev * sm_dp, + Sm_detached * sep) +{ + sm_dp->att_event = sep->event_attached; + sm_dp->det_event = sep->event_count; + jiffies_to_timespec(sep->time_detached, &sm_dp->det_time); + memcpy(sm_dp->host_name, sep->host_name, sizeof(sm_dp->host_name)); + memcpy(sm_dp->host_info, sep->host_info, sizeof(sm_dp->host_info)); + sm_dp->d.host = sep->host; + sm_dp->d.bus = sep->bus; + sm_dp->d.target = sep->target; + sm_dp->d.lun = sep->lun; + memcpy(sm_dp->d.vendor, sep->vendor, sizeof(sm_dp->d.vendor)); + memcpy(sm_dp->d.model, sep->model, sizeof(sm_dp->d.model)); + memcpy(sm_dp->d.rev, sep->rev, sizeof(sm_dp->d.rev)); + sm_dp->d.scsi_type = sep->scsi_type; + sm_dp->d.scsi_level = sep->scsi_level; + sm_dp->d.removable = sep->removable; + sm_dp->d.emulated = sep->emulated; +} + +static void sm_read_det_list(struct scsimon_det_list * dlp) +{ + Sm_detached * sep; + int k; + unsigned long iflags; + + read_lock_irqsave(&scsimon_lock, iflags); + dlp->curr_event = sm_event_count; + for (k = 0, sep = sm_det_rootp; (k < dlp->max_num) && sep; + sep = sep->next_det) { + if (dlp->match_event > 0) { + if (dlp->match_event == sep->event_attached) { + k = 1; + sm_read_det_elem(&dlp->arr[0], sep); + break; + } + continue; + } + sm_read_det_elem(&dlp->arr[k], sep); + k++; + } + dlp->num_out = k; + read_unlock_irqrestore(&scsimon_lock, iflags); +} + +static void sm_read_host_elem(struct scsimon_host * sm_hp, + struct Scsi_Host * shp) +{ + sm_hp->host = shp->host_no; + sm_hp->host_scsi_id = shp->this_id; + sm_hp->emulated = shp->hostt->emulated; + sm_hp->is_module = shp->loaded_as_module; + if (shp->hostt->name) + strncpy(sm_hp->host_name, shp->hostt->name, + sizeof(sm_hp->host_name)); + if (shp->hostt->info) + strncpy(sm_hp->host_info, shp->hostt->info(shp), + sizeof(sm_hp->host_info)); +} + +static void sm_read_host_list(struct scsimon_host_list * hlp) +{ + struct Scsi_Host * shp; + int k; + unsigned long iflags; + int match; + + match = (SCSIMON_HOST_FLAG_MATCH & hlp->flags) ? 1 : 0; + read_lock_irqsave(&scsimon_lock, iflags); + hlp->curr_event = sm_event_count; + for (k = 0, shp = scsi_hostlist; shp && (k < hlp->max_num); + shp = shp->next) { + if (match) { + if (shp->host_no == hlp->host) { + sm_read_host_elem(&hlp->arr[0], shp); + k = 1; + break; + } + continue; + } + sm_read_host_elem(&hlp->arr[k], shp); + k++; + } + hlp->num_out = k; + read_unlock_irqrestore(&scsimon_lock, iflags); +} + +#ifdef CONFIG_HOTPLUG + +static void sm_call_policy(Sm_hotinfo * hip) +{ + char *argv [3], **envp, *buf, *scratch; + int k = 0, value; + + if (!hotplug_path [0]) + return; + if (in_interrupt ()) { + SCSI_LOG_TIMEOUT(1, printk("sm_call_policy: in_interrupt\n")); + return; + } + if (! current->fs->root) { + SCSI_LOG_TIMEOUT(1, printk("sm_call_policy: no root fs\n")); + return; + } + if (!(envp = (char **) kmalloc (20 * sizeof (char *), GFP_KERNEL))) { + SCSI_LOG_TIMEOUT(1, printk("sm_call_policy: ENOMEM\n")); + return; + } + if (!(buf = kmalloc (512, GFP_KERNEL))) { + kfree (envp); + SCSI_LOG_TIMEOUT(1, printk("sm_call_policy: ENOMEM\n")); + return; + } + + /* only one standardized param to hotplug command: type */ + argv [0] = hotplug_path; + argv [1] = "scsi"; + argv [2] = 0; + + /* minimal command environment */ + envp [k++] = "HOME=/"; + envp [k++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + + /* extensible set of named bus-specific parameters, + * supporting multiple driver selection algorithms. + */ + scratch = buf; + + /* action: add, remove */ + envp [k++] = scratch; + scratch += sprintf (scratch, "ACTION=%s", + hip->action ? "remove" : "add") + 1; + + /* per-device configuration hacks are common */ + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_HOST=%u", hip->host) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_BUS=%u", hip->bus) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_TARGET=%u", hip->target) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_LUN=%u", hip->lun) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_VENDOR=%.8s", hip->vendor) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_MODEL=%.16s", hip->model) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_REV=%.4s", hip->rev) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_TYPE=%d", hip->scsi_type) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_REMOVABLE=%d", hip->removable) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_EMULATED=%d", hip->emulated) + 1; + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_EVENT_ATTACHED=%lu", + hip->event_attached) + 1; + if (1 == hip->action) { + envp [k++] = scratch; + scratch += sprintf (scratch, "SCSI_EVENT_DETACHED=%lu", + hip->event_detached) + 1; + } + + envp [k++] = 0; + /* assert: (scratch - buf) < sizeof buf */ + + /* NOTE: user mode daemons can call the agents too */ + + value = call_usermodehelper (argv [0], argv, envp); + kfree (buf); + kfree (envp); + if (value != 0) { + SCSI_LOG_TIMEOUT(1, printk("sm_call_policy: " + "call_usermodehelper returned %d\n", value)); + } +} + +#else + +static void sm_call_policy (Sm_hotinfo * hip) { } + +#endif + +MODULE_AUTHOR("Douglas Gilbert"); +MODULE_DESCRIPTION("SCSI monitor (scsimon) driver"); + +static int __init init_scsimon(void) +{ + int res; + + sm_init_time = jiffies; + scsimon_template.module = THIS_MODULE; + res = scsi_register_module(MODULE_SCSI_DEV, &scsimon_template); + misc_register(&scsimon_miscdev); + return res; +} + +static void __exit exit_scsimon( void) +{ + misc_deregister(&scsimon_miscdev); + scsi_unregister_module(MODULE_SCSI_DEV, &scsimon_template); + sm_trunc_alist(0); + sm_trunc_dlist(0); +} + +module_init(init_scsimon); +module_exit(exit_scsimon); diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/sg.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/sg.c --- linux-2.4.20-wolk4.1s/drivers/scsi/sg.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/sg.c 2003-06-02 17:23:46.000000000 +0200 @@ -7,7 +7,7 @@ * Original driver (sg.c): * Copyright (C) 1992 Lawrence Foard * Version 2 and 3 extensions to driver: - * Copyright (C) 1998 - 2002 Douglas Gilbert + * Copyright (C) 1998 - 2003 Douglas Gilbert * * Modified 19-JAN-1998 Richard Gooch Devfs support * @@ -19,9 +19,9 @@ */ #include #ifdef CONFIG_PROC_FS - static char * sg_version_str = "Version: 3.1.24 (20020505)"; + static char * sg_version_str = "Version: 3.1.25 (20030529)"; #endif - static int sg_version_num = 30124; /* 2 digits for each component */ + static int sg_version_num = 30125; /* 2 digits for each component */ /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First @@ -1885,11 +1885,7 @@ static int sg_write_xfer(Sg_request * sr res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up); if (res) return res; - for (; k < schp->k_use_sg; ++k, ++sclp) { - ksglen = (int)sclp->length; - p = sclp->address; - if (NULL == p) - break; + for ( ; p; ++sclp, ksglen = (int)sclp->length, p = sclp->address) { ok = (SG_USER_MEM != mem_src_arr[k]); if (usglen <= 0) break; @@ -1912,6 +1908,9 @@ static int sg_write_xfer(Sg_request * sr up += ksglen; usglen -= ksglen; } + ++k; + if (k >= schp->k_use_sg) + return 0; } } } @@ -2041,11 +2040,7 @@ static int sg_read_xfer(Sg_request * srp res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up); if (res) return res; - for (; k < schp->k_use_sg; ++k, ++sclp) { - ksglen = (int)sclp->length; - p = sclp->address; - if (NULL == p) - break; + for ( ; p; ++sclp, ksglen = (int)sclp->length, p = sclp->address) { ok = (SG_USER_MEM != mem_src_arr[k]); if (usglen <= 0) break; @@ -2068,6 +2063,9 @@ static int sg_read_xfer(Sg_request * srp up += ksglen; usglen -= ksglen; } + ++k; + if (k >= schp->k_use_sg) + return 0; } } } diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/sparcsi.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/sparcsi.c --- linux-2.4.20-wolk4.1s/drivers/scsi/sparcsi.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/sparcsi.c 2003-06-02 17:23:43.000000000 +0200 @@ -0,0 +1,387 @@ +/* + sparcsi.c (c) 1997-1999 Grant Guenther + + This is the low-level protocol module for the WBS-11A parallel + port SCSI adapter. This adapter has been marketed by LinkSys + as the "ParaSCSI+" and by Shining Technologies as the "SparCSI". + The device is constructed from the KBIC-951A ISA replicator + chip from KingByte and the NCR 5380. + +*/ + +#define SPARCSI_VERSION "0.91" + +#define PPSC_BASE +#define PPSC_HA_MODULE + +#include "ppscsi.h" + +#define r12w() (delay_p,inw(pha->port+1)&0xffff) + +#define j44(a,b) ((((a>>4)&0x0f)|(b&0xf0))^0x88) +#define j53(w) (((w>>3)&0x1f)|((w>>4)&0xe0)) + +static char sparcsi_map[256]; /* status bits permutation */ + +static void sparcsi_init (PHA *pha) +{ + +/* { REQ, BSY, MSG, CD, IO} */ + + char key[5] = {0x20,0x40,0x10,0x08,0x04}; + + ppsc_make_map(sparcsi_map,key,0); + sprintf(pha->ident,"sparcsi %s (%s), WBS-11A", + SPARCSI_VERSION,PPSC_H_VERSION); +} + +static void sparcsi_write_regr (PHA *pha, int regr, int value) +{ + switch (pha->mode) { + + case 0: + case 1: + case 2: w0(regr|0x10); w2(4); w2(6); w2(4); + w0(value); w2(5); w2(4); + break; + + case 3: w0(0x20); w2(4); w2(6); w2(4); w3(regr); + w4(value); w2(4); w2(0); w2(4); + break; + + } +} + +static int sparcsi_read_regr (PHA *pha, int regr) +{ + int a, b; + + switch (pha->mode) { + + case 0: w0(regr|0x18); w2(4); w2(6); w2(4); w2(5); + a = r1(); w0(0x58); b = r1(); w2(4); + return j44(a,b); + + case 1: w0(regr|0x58); w2(4); w2(6); w2(4); w2(5); + a = r12w(); w2(4); + return j53(a); + + case 2: w0(regr|0x98); w2(4); w2(6); w2(4); w2(0xa5); + a = r0(); w2(4); + return a; + + case 3: w0(0x20); w2(4); w2(6); w2(4); w3(regr); + w2(0xe4); a = r4(); w2(4); w2(0); w2(4); + return a; + + } + return -1; +} + +static void sparcsi_read_block (PHA *pha, char *buf, int len) +{ + int k, a, b; + + switch (pha->mode) { + + case 0: w0(8); w2(4); w2(6); w2(4); + for (k=0;kmode) { + + case 0: + case 1: + case 2: w0(0); w2(4); w2(6); w2(4); + for(k=0;ksaved_r0 = r0(); + pha->saved_r2 = r2(); + w2(4); +} + +static void sparcsi_disconnect (PHA *pha) +{ + w0(pha->saved_r0); + w2(pha->saved_r2); +} + +#define WR(r,v) sparcsi_write_regr(pha,r,v) +#define RR(r) (sparcsi_read_regr(pha,r)) + +static int sparcsi_test_proto (PHA *pha) +{ + int k, e; + + e = 0; + + sparcsi_connect(pha); + + if (!pha->private[0]) { /* reset the SCSI bus on first sight */ + + if (V_FULL) printk("%s: SCSI reset ...\n",pha->device); + + WR(1,0x80); udelay(60); + WR(1,0); + scsi_sleep(5*HZ); + pha->private[0] = 1; + } + + WR(1,0); + WR(1,1); + + if (V_PROBE) + printk("%s: 5380 regrs [4]=%x [5]=%x\n",pha->device,RR(4),RR(5)); + + for (k=0;k<256;k++) { + WR(0,k); + if (RR(0) != k) e++; + WR(0,255-k); + if (RR(0) != (255-k)) e++; + } + + WR(1,0); + + sparcsi_disconnect(pha); + + return e; +} + +static int sparcsi_select (PHA *pha, int initiator, int target) +{ + WR(3,0); WR(1,1); + WR(0,(1 << initiator)); WR(2,1); udelay(100); + if (RR(1) != 0x41) { + WR(1,0); + return -1; + } + + WR(1,5); WR(0,(1 << initiator)|(1 << target)); + WR(2,0); WR(2,0); WR(2,0); + return 0; +} + +static int sparcsi_test_select (PHA *pha) +{ + return ((RR(4) & 0x42) == 0x42); +} + +static void sparcsi_select_finish (PHA *pha) +{ + WR(3,2); WR(1,5); WR(1,1); +} + +static void sparcsi_deselect (PHA *pha) +{ + WR(1,0); +} + +static int sparcsi_get_bus_status (PHA *pha) +{ + int s; + + s = RR(4); + return sparcsi_map[s]; +} + +static void sparcsi_slow_start (PHA *pha, char *val) +{ + int ph, io; + + ph = ((RR(4)>>2)&7); + io = (ph & 1); + + WR(3,ph); + WR(1,1-io); + if (io) *val = RR(0); else WR(0,*val); + WR(1,0x10+(1-io)); +} + +static int sparcsi_slow_done (PHA *pha) +{ + return ((RR(4) & 0x20) == 0); +} + +static void sparcsi_slow_end (PHA *pha) +{ + int io; + + io = ((RR(4)>>2)&1); + + WR(1,1-io); +} + +static void sparcsi_start_block (PHA *pha, int rd) +{ + if (rd) { + + WR(3,1); WR(1,0); + WR(2,2); WR(7,3); + WR(3,1); WR(1,0); + + } else { + + WR(3,0); WR(1,1); + WR(2,2); WR(5,0); + WR(3,0); WR(1,1); + + } + pha->priv_flag = rd; +} + +static int sparcsi_transfer_ready (PHA *pha) +{ + int chunk; + + chunk = 512; + if ((pha->data_count == 0) && (!pha->priv_flag)) chunk++; + + if (r1() & 0x40) return chunk; + if (!(RR(5) & 8)) return -1; + return 0; +} + +static int sparcsi_transfer_block (PHA *pha, char * buf, int buflen, int rd) +{ + int k, n; + + k = 0; + while (k < buflen) { + + n = sparcsi_transfer_ready(pha); + + if (n <= 0) break; + + if (n > (buflen - k)) n = buflen - k; + + if (rd) sparcsi_read_block(pha,buf,n); + else sparcsi_write_block(pha,buf,n); + + k += n; buf += n; + } + + return k; +} + +static int sparcsi_transfer_done (PHA *pha) +{ + return 1; +} + +static void sparcsi_end_block (PHA *pha, int rd) +{ + char buf[2] = {0,0}; + + if (!rd) sparcsi_write_block(pha,buf,1); + + WR(2,0); +} + +static void sparcsi_reset_bus (PHA *pha) +{ + WR(1,1); WR(3,0); + WR(2,0); + WR(1,0x80); udelay(60); + WR(1,0); + WR(2,0); + WR(1,1); WR(3,0); + WR(2,0); +} + +static char *(mode_strings[4]) = {"Nybble","KBIC 5/3","PS/2","EPP"}; + +static struct ppsc_protocol sparcsi_psp = { + + {&host0,&host1,&host2,&host3}, /* params */ + &host_structs, /* hosts */ + 4, /* num_modes */ + 3, /* epp_first */ + 1, /* default_delay */ + 1, /* can_message */ + 16, /* sg_tablesize */ + mode_strings, + sparcsi_init, + NULL, + sparcsi_connect, + sparcsi_disconnect, + sparcsi_test_proto, + sparcsi_select, + sparcsi_test_select, + sparcsi_select_finish, + sparcsi_deselect, + sparcsi_get_bus_status, + sparcsi_slow_start, + sparcsi_slow_done, + sparcsi_slow_end, + sparcsi_start_block, + sparcsi_transfer_block, + sparcsi_transfer_ready, + sparcsi_transfer_done, + sparcsi_end_block, + sparcsi_reset_bus +}; + +int sparcsi_detect (Scsi_Host_Template *tpnt) +{ + return ppsc_detect( &sparcsi_psp, tpnt, verbose); +} + +#ifdef MODULE + +Scsi_Host_Template driver_template = PPSC_TEMPLATE(sparcsi); + +#include "scsi_module.c" + +#else + +void sparcsi_setup (char *str, int *ints) +{ + ppsc_gen_setup(stt,4,str); +} + +#endif + +/* end of sparcsi.c */ + diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/t348.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/t348.c --- linux-2.4.20-wolk4.1s/drivers/scsi/t348.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/t348.c 2003-06-02 17:23:43.000000000 +0200 @@ -0,0 +1,316 @@ +/* + t348.c (c) 1997-1999 Grant Guenther + + This is the low-level protocol module for the Adaptec APA-348 + (aka Trantor T348) parallel port SCSI adapter. It forms part + of the 'ppSCSI' suite of drivers. + +*/ + +#define T348_VERSION "0.92" + +#define PPSC_BASE +#define PPSC_HA_MODULE + +#include "ppscsi.h" + +#define j44(a,b) (((a<<1)&0xf0)+((b>>3)&0x0f)) + +static char t348_map[256]; /* status bits permutation */ + +static void t348_init (PHA *pha) +{ + +/* { REQ, BSY, MSG, CD, IO} */ + + char key[5] = {0x20,0x40,0x10,0x08,0x04}; + + ppsc_make_map(t348_map,key,0); + sprintf(pha->ident,"t348 %s (%s), Adaptec APA-348", + T348_VERSION,PPSC_H_VERSION); +} + +static void t348_write_regr (PHA *pha, int regr, int value) +{ + w0(0x40+regr); w2(1); w2(0); w0(value); w2(8); w2(0); +} + +static int t348_read_regr (PHA *pha, int regr) +{ + int s,a,b; + + w0(0x10+regr); s = r2(); w2(s|1); w2(s); w2(8); + w0(0x80); a = r1(); w0(0); b = r1(); w2(0); + return j44(a,b); +} + +static void t348_connect (PHA *pha) +{ + int t; + + pha->saved_r0 = r0(); + w0(0); + t = r2(); + w2(t%16); w0(0xfe); w2(t%4); w2((t%4)+8); w2(0); + pha->saved_r2 = t; +} + +static void t348_disconnect (PHA *pha) +{ + w0(0x71); w2(1); w2(0); + w0(pha->saved_r0); + w2(pha->saved_r2); +} + +static int t348_test_proto (PHA *pha) +{ + int k, e, a, b; + int wnt[3] = {0x6c, 0x55, 0xaa}; + + e = 0; + + t348_connect(pha); + + switch (pha->mode) { + + case 0: w0(0x70); w2(1); w2(0); w0(0); + for (k=0;k<3;k++) { + w2(8); a = r1(); w2(0); + w2(8); w2(8); w2(8); w2(8); w2(8); + b = r1(); w2(0); + if (j44(b,a) != wnt[k]) e++; + } + break; + + case 1: w0(0x50); w2(1); w2(0); + for (k=0;k<3;k++) { + w2(0xe0); w2(0xe8); + if (r0() != wnt[k]) e++; + w2(0xe0); w2(0xe8); + } + + } + + t348_disconnect(pha); + + return e; +} + +/* The T348 appears to contain a NCR 5380 core. The following + functions use the 5380 registers. See NCR5380.h for clues. +*/ + +#define WR(r,v) t348_write_regr(pha,r,v) +#define RR(r) (t348_read_regr(pha,r)) + +static int t348_select (PHA *pha, int initiator, int target) +{ + WR(3,0); WR(1,1); + WR(0,(1 << initiator)); WR(2,1); udelay(100); + if (RR(1) != 0x41) { + WR(1,0); + return -1; + } + + WR(1,5); WR(0,(1 << initiator)|(1 << target)); + WR(2,0); WR(2,0); WR(2,0); + return 0; +} + +static int t348_test_select (PHA *pha) +{ + return ((RR(4) & 0x42) == 0x42); +} + +static void t348_select_finish (PHA *pha) +{ + WR(3,2); WR(1,5); WR(1,1); +} + +static void t348_deselect (PHA *pha) +{ + WR(1,0); +} + +static int t348_get_bus_status (PHA *pha) +{ + int s; + + s = RR(4); + return t348_map[s]; +} + +static void t348_slow_start (PHA *pha, char *val) +{ + int ph, io; + + ph = ((RR(4)>>2)&7); + io = (ph & 1); + + WR(3,ph); + WR(1,1-io); + if (io) *val = RR(0); else WR(0,*val); + WR(1,0x10+(1-io)); +} + +static int t348_slow_done (PHA *pha) +{ + return ((RR(4) & 0x20) == 0); +} + +static void t348_slow_end (PHA *pha) +{ + int io; + + io = ((RR(4)>>2)&1); + + WR(1,1-io); +} + +static void t348_start_block (PHA *pha, int rd) +{ + if (rd) { + + WR(3,1); WR(1,0); + WR(2,2); WR(7,3); + WR(3,1); WR(1,0); + + switch (pha->mode) { + + case 0: w0(0x31); w2(1); w2(0); w0(0x80); w2(8); + break; + + case 1: w0(0x21); w2(1); w2(0); w2(0xe8); + break; + } + + } else { + + WR(3,0); WR(1,1); + WR(2,2); WR(5,0); + WR(3,0); WR(1,1); + + w0(0x61); w2(1); w2(0); + } +} + +static int t348_transfer_ready (PHA *pha) +{ + if (r1() & 0x80) return 1; + + if (pha->data_dir == 0) return 0; + return -1; +} + +static int t348_transfer_block (PHA *pha, char * buf, int buflen, int rd) +{ + int k, a, b; + + k = 0; + while (k < buflen) { + + if (t348_transfer_ready(pha) <= 0) break; + + if (rd) { + switch(pha->mode) { + + case 0: a = r1(); w0(0); b = r1(); w0(0xc0); + buf[k++] = j44(a,b); + a = r1(); w0(0x40); b = r1(); w0(0x80); + buf[k++] = j44(a,b); + break; + + case 1: buf[k++] = r0(); w2(0xea); + buf[k++] = r0(); w2(0xe8); + break; + } + + } else { + + w0(buf[k++]); w2(2); + w0(buf[k++]); w2(0); + } + + } + + return k; +} + +static int t348_transfer_done (PHA *pha) +{ + return 1; +} + +static void t348_end_block (PHA *pha, int rd) +{ + w2(0); + WR(2,0); +} + + +static void t348_reset_bus (PHA *pha) +{ + WR(1,1); WR(3,0); + WR(2,0); + WR(1,0x80); udelay(60); + WR(1,0); + WR(2,0); + WR(1,1); WR(3,0); + WR(2,0); +} + +static char *(mode_strings[2]) = {"Nybble","PS/2"}; + +static struct ppsc_protocol t348_psp = { + + {&host0,&host1,&host2,&host3}, /* params */ + &host_structs, /* hosts */ + 2, /* num_modes */ + 2, /* epp_first */ + 1, /* default_delay */ + 1, /* can_message */ + 0, /* sg_tablesize */ + mode_strings, + t348_init, + NULL, + t348_connect, + t348_disconnect, + t348_test_proto, + t348_select, + t348_test_select, + t348_select_finish, + t348_deselect, + t348_get_bus_status, + t348_slow_start, + t348_slow_done, + t348_slow_end, + t348_start_block, + t348_transfer_block, + t348_transfer_ready, + t348_transfer_done, + t348_end_block, + t348_reset_bus +}; + +int t348_detect (Scsi_Host_Template *tpnt) +{ + return ppsc_detect( &t348_psp, tpnt, verbose); +} + +#ifdef MODULE + +Scsi_Host_Template driver_template = PPSC_TEMPLATE(t348); + +#include "scsi_module.c" + +#else + +void t348_setup (char *str, int *ints) +{ + ppsc_gen_setup(stt,4,str); +} + +#endif + +/* end of t348.c */ + diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/t358.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/t358.c --- linux-2.4.20-wolk4.1s/drivers/scsi/t358.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/t358.c 2003-06-02 17:23:43.000000000 +0200 @@ -0,0 +1,392 @@ +/* + t358.c (c) 1997-1999 Grant Guenther + + This is the low-level protocol module for the Adaptec APA-358 + (aka Trantor T358) parallel port SCSI adapter. It forms part + of the 'ppSCSI' suite of drivers. + +*/ + +#define T358_VERSION "0.91" + +#define PPSC_BASE +#define PPSC_HA_MODULE + +#include "ppscsi.h" + +#define j44(a,b) (((a<<1)&0xf0)+((b>>3)&0x0f)) + +static char t358_map[256]; /* status bits permutation */ + +static void t358_init (PHA *pha) +{ + +/* { REQ, BSY, MSG, CD, IO} */ + + char key[5] = {0x20,0x40,0x10,0x08,0x04}; + + ppsc_make_map(t358_map,key,0); + sprintf(pha->ident,"t358 %s (%s), Adaptec APA-358", + T358_VERSION,PPSC_H_VERSION); +} + +static void t358_write_regr (PHA *pha, int regr, int value) +{ + int x; + + switch (pha->mode) { + + case 0: + case 1: w0(regr); x = r2(); w2(1); w2(9); w2(0); w2(0); + w0(value); w2(1); w2(3); w2(0); w2(x); + break; + + case 2: w2(0xc0); w3(regr); w4(value); + break; + + } +} + +static int t358_read_regr (PHA *pha, int regr) +{ + int h, l; + + switch (pha->mode) { + + case 0: w0(regr); w2(1); w2(9); w2(0); w2(0); + w0(0x80); w2(2); h = r1(); + w0(0); l = r1(); w2(0); + return j44(h,l); + + case 1: w0(regr); h = r2(); w2(1); w2(9); w2(0); w2(0); + w2(0xe2); l = r0(); w2(h); + return l; + + case 2: h = r2(); w2(0xe0); w3(regr); w2(0xe0); + l = r4(); w2(h); + return l; + } + + return 0; +} + +static void t358_read_block (PHA *pha, char *buf, int len) +{ + int k, h, l; + + switch (pha->mode) { + + case 0: w0(0x10); w2(1); w2(9); w2(0); w2(0); + for (k=0;kmode) { + + case 0: + case 1: w0(0x10); x = r2(); + w2(1); w2(9); w2(0); w2(0); + for (k=0;ksaved_r0 = r0(); + w0(0); + pha->saved_r2 = r2(); + b = pha->saved_r2 % 4; + w0(0xf7); w2(b+4); w2(b); w2(b+8); w2(b); w2(0); + + if (pha->mode) { w0(0x80); w2(1); w2(9); w2(1); w2(0); } + else { w0(0xa0); w2(1); w2(9); w2(0); } +} + +static void t358_disconnect (PHA *pha) +{ + w0(pha->saved_r0); + w2(pha->saved_r2); +} + +static int t358_test_proto (PHA *pha) +{ + int h, l, a, b; + int j = 0, k = 0, e = 0; + + t358_connect(pha); + + switch (pha->mode) { + + case 0: w0(0x80); w2(8); h = r1(); w0(0); l = r1(); + w2(0); w2(8); a = r1(); w0(0); b = r1(); w2(0); + k = j44(h,l); j = j44(a,b); + break; + + case 1: w2(0xe0); w0(0); w2(0xe8); k = r0(); + w2(0xe0); w2(0xe8); j = r0(); w2(0xe0); + break; + + case 2: w0(0xa0); w2(1); w2(9); w2(0); + w0(0x80); w2(8); h = r1(); w0(0); l = r1(); + w2(0); w2(8); a = r1(); w0(0); b = r1(); w2(0); + k = j44(h,l); j = j44(a,b); + w0(0x80); w2(1); w2(9); w2(1); w2(0); + + } + + if (V_PROBE) printk("%s: Signature: %x %x\n",pha->device,k,j); + + if ((k != 0xe8) || (j != 0xff)) e++; + + t358_disconnect(pha); + + if (!e) { + + t358_connect(pha); + + for (j=0;j<256;j++) { + t358_write_regr(pha,0,j); + k = t358_read_regr(pha,0); + if (k != j) e++; + } + + t358_disconnect(pha); + + } + + return e; +} + +/* The T358 appears to contain a NCR 53c400 core. Check NCR5380.h + for hints about the regrs ... */ + +#define WR(r,v) t358_write_regr(pha,r+8,v) +#define RR(r) (t358_read_regr(pha,r+8)) + +static int t358_select (PHA *pha, int initiator, int target) +{ + WR(3,0); WR(1,1); + WR(0,(1 << initiator)); WR(2,1); udelay(100); + if (RR(1) != 0x41) { + WR(1,0); + return -1; + } + + WR(1,5); WR(0,(1 << initiator)|(1 << target)); + WR(2,0); WR(2,0); WR(2,0); + return 0; +} + +static int t358_test_select (PHA *pha) +{ + return ((RR(4) & 0x42) == 0x42); +} + +static void t358_select_finish (PHA *pha) +{ + WR(3,2); WR(1,5); WR(1,1); +} + +static void t358_deselect (PHA *pha) +{ + WR(1,0); +} + +static int t358_get_bus_status (PHA *pha) +{ + int s; + + s = RR(4); + return t358_map[s]; +} + +static void t358_slow_start (PHA *pha, char *val) +{ + int ph, io; + + ph = ((RR(4)>>2)&7); + io = (ph & 1); + + WR(3,ph); + WR(1,1-io); + if (io) *val = RR(0); else WR(0,*val); + WR(1,0x10+(1-io)); +} + +static int t358_slow_done (PHA *pha) +{ + return ((RR(4) & 0x20) == 0); +} + +static void t358_slow_end (PHA *pha) +{ + int io; + + io = ((RR(4)>>2)&1); + + WR(1,1-io); +} + +static void t358_start_block (PHA *pha, int rd) +{ + if (rd) { + WR(3,1); WR(1,0); + WR(2,2); + WR(0x10,0x40); WR(2,0); WR(2,0xa); + WR(3,1); WR(1,0); WR(7,3); + } else { + WR(3,0); WR(1,1); + WR(2,2); + WR(0x10,0); WR(2,0); WR(2,0xa); + WR(3,0); WR(1,1); WR(5,0); + } + WR(0x11,pha->tlen/128); +} + +static int t358_transfer_ready (PHA *pha) +{ + int r; + + r = RR(0x10); + + if (!(r & 4)) return 128; /* 4 is host buffer not ready */ + + if (r & 1) return -1; /* last block transferred */ + + return 0; +} + +static int t358_transfer_block (PHA *pha, char * buf, int buflen, int rd) +{ + int k, n; + + k = 0; + while (k < buflen) { + + n = t358_transfer_ready(pha); + + if (n <= 0) break; + + if (n > (buflen - k)) n = buflen - k; + + if (rd) t358_read_block(pha,buf,n); + else t358_write_block(pha,buf,n); + + k += n; buf += n; + + } + + return k; +} + +static int t358_transfer_done (PHA *pha) +{ + if (RR(0x10) & 1) return 1; /* last block transferred */ + return 0; +} + +static void t358_end_block (PHA *pha, int rd) +{ + WR(2,0); +} + + +static void t358_reset_bus (PHA *pha) +{ + WR(1,1); WR(3,0); + WR(2,0); + WR(1,0x80); udelay(60); + WR(1,0); + WR(2,0); + WR(1,1); WR(3,0); + WR(2,0); +} + +static char *(mode_strings[3]) = {"Nybble","PS/2","EPP"}; + +static struct ppsc_protocol t358_psp = { + + {&host0,&host1,&host2,&host3}, /* params */ + &host_structs, /* hosts */ + 3, /* num_modes */ + 2, /* epp_first */ + 1, /* default_delay */ + 1, /* can_message */ + 16, /* sg_tablesize */ + mode_strings, + t358_init, + NULL, + t358_connect, + t358_disconnect, + t358_test_proto, + t358_select, + t358_test_select, + t358_select_finish, + t358_deselect, + t358_get_bus_status, + t358_slow_start, + t358_slow_done, + t358_slow_end, + t358_start_block, + t358_transfer_block, + t358_transfer_ready, + t358_transfer_done, + t358_end_block, + t358_reset_bus +}; + +int t358_detect (Scsi_Host_Template *tpnt ) +{ + return ppsc_detect( &t358_psp, tpnt, verbose); +} + +#ifdef MODULE + +Scsi_Host_Template driver_template = PPSC_TEMPLATE(t358); + +#include "scsi_module.c" + +#else + +void t358_setup (char *str, int *ints) +{ + ppsc_gen_setup(stt,4,str); +} + +#endif + +/* end of t358.c */ + diff -Naurp linux-2.4.20-wolk4.1s/drivers/scsi/vpi0.c linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/vpi0.c --- linux-2.4.20-wolk4.1s/drivers/scsi/vpi0.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/scsi/vpi0.c 2003-06-02 17:23:43.000000000 +0200 @@ -0,0 +1,274 @@ +/* + vpi0.c (c) 1995-1999 Grant Guenther + (c) 1997-1999 David Campbell + + This is the ppSCSI protocol module for the Iomega VPI0 adapter + found in the original ZIP-100 drives and the Jaz Traveller. + +*/ + +#define VPI0_VERSION "0.91" + +#define PPSC_BASE +#define PPSC_HA_MODULE + +#include "ppscsi.h" + +static char vpi0_map[256]; /* status bits permutation */ + +static void vpi0_init (PHA *pha) +{ + +/* *** No MSG line on the VPI0 ! *** */ + +/* { REQ, BSY, MSG, CD, IO} */ + + char key[5] = {0x80,0x40,0x00,0x20,0x10}; + + ppsc_make_map(vpi0_map,key,0); + sprintf(pha->ident,"vpi0 %s (%s) ",VPI0_VERSION,PPSC_H_VERSION); +} + +#define j44(a,b) ((a&0xf0)|((b>>4)&0x0f)) + +#define CST(v) w2(0xc);w0(v);w2(4);w2(6);w2(4);w2(0xc); +#define DST(v) w2(0xc);w0(v);w2(0xc);w2(0xe);w2(0xc);w2(4);w2(0xc); + +static void vpi0_connect (PHA *pha) +{ + pha->saved_r0 = r0(); + pha->saved_r2 = r2(); + + CST(0); CST(0x3c); CST(0x20); + if (pha->mode >= 2) { CST(0xcf) } else { CST(0x8f) } +} + +static void vpi0_disconnect (PHA *pha) +{ + DST(0); DST(0x3c); DST(0x20); DST(0xf); + + w2(pha->saved_r2); + w0(pha->saved_r0); +} + + +/* There are no data-transfer tests available, just this simple + check that we are talking to a VPI0. */ +static int vpi0_test_proto (PHA *pha) +{ + int e = 2; + + vpi0_connect(pha); + w2(0xe); + if ((r1() & 8) == 8) e--; + w2(0xc); + if ((r1() & 8) == 0) e--; + vpi0_disconnect(pha); + return e; +} + +static int vpi0_select (PHA *pha, int initiator, int target) +{ + w2(0xc); + if (r1() & 0x40) return -1; /* bus busy */ + + w0(1<mode) { + + case 0: if (first) w2(4); + h = r1(); w2(6); + l = r1(); w2(4); + return j44(h,l); + + case 1: if (first) w2(0x25); + l = r0(); + w2(0x27); w2(0x25); + return l; + + case 2: if (first) w2(0x24); + return r4(); + + default: return -1; + + } +} + +static inline void vpi0_write (PHA *pha, int v, int first ) +{ + switch (pha->mode) { + + case 0: + case 1: if (first) w2(0xc); + w0(v); w2(0xe); w2(0xc); + break; + + case 2: if (first) w2(0x4); + w4(v); + break; + + } +} + +static void vpi0_slow_start (PHA *pha, char *val) +{ + int r; + + w2(0xc); + + r = (r1() & 0x10); + + if (r) *val = vpi0_read(pha,1); + else vpi0_write(pha,*val,1); + +} + +static int vpi0_slow_done (PHA *pha) +{ + return 1; /* vpi0 does its own REQ/ACK handshaking */ +} + +static void vpi0_slow_end (PHA *pha) +{ + w2(0xc); +} + +static void vpi0_start_block (PHA *pha, int rd) +{ + pha->priv_flag = rd; +} + +static int vpi0_transfer_ready (PHA *pha) +{ + int b; + + b = vpi0_get_bus_status(pha); + if ((b & PPSC_PH_STAT) == PPSC_PH_STAT) return -1; + if (b == (PPSC_REQ|PPSC_BSY| pha->priv_flag)) return 128; + return 0; +} + +static int vpi0_transfer_block (PHA *pha, char * buf, int buflen, int rd) +{ + int k, n, i; + + k = 0; + while (k < buflen) { + n = vpi0_transfer_ready(pha); + if (n <= 0 ) break; + if (n > (buflen-k)) n = buflen-k; + for (i=0;i + (c) 1997-1999 David Campbell + (c) 2000 Tim Waugh + + This is the ppSCSI protocol module for the Iomega VPI2 adapter + found in the newer ZIP-100 drives. + +*/ + +#error "This doesn't work yet." + +#define VPI2_VERSION "0.91" + +#define PPSC_BASE +#define PPSC_HA_MODULE + +#include "ppscsi.h" + +static char vpi2_map[256]; /* status bits permutation */ + +static void vpi2_init (PHA *pha) +{ + +/* *** No MSG line on the VPI2 ! *** */ /* tmw: is this true for VPI2? */ + +/* { REQ, BSY, MSG, CD, IO} */ + + char key[5] = {0x80,0x40,0x00,0x20,0x10}; + + ppsc_make_map(vpi2_map,key,0); + sprintf(pha->ident,"vpi2 %s (%s) ",VPI2_VERSION,PPSC_H_VERSION); +} + +#define j44(a,b) ((a&0xf0)|((b>>4)&0x0f)) + +#define CST(v) w2(0xc);w0(v);w2(4);w2(6);w2(4);w2(0xc); +#define DST(v) w2(0xc);w0(v);w2(0xc);w2(0xe);w2(0xc);w2(4);w2(0xc); + +static inline int imm_cpp (PHA *pha, unsigned char b) +{ + unsigned char s1, s2, s3; + + w2(0xc); + udelay(2); /* 1 usec - infinite */ + w0(0xaa); + udelay(10); /* 7 usec - infinite */ + w0(0x55); + udelay(10); /* 7 usec - infinite */ + w0(0x00); + udelay(10); /* 7 usec - infinite */ + w0(0xff); + udelay(10); /* 7 usec - infinite */ + s1 = r1() & 0xb8; + w0(0x87); + udelay(10); /* 7 usec - infinite */ + s2 = r1() & 0xb8; + w0(0x78); + udelay(10); + s3 = r1() & 0x38; + /* + * Values for b are: + * 0000 00aa Assign address aa to current device + * 0010 00aa Select device aa in EPP Winbond mode + * 0010 10aa Select device aa in EPP mode + * 0011 xxxx Deselect all devices + * 0110 00aa Test device aa + * 1101 00aa Select device aa in ECP mode + * 1110 00aa Select device aa in Compatible mode + */ + w0(b); + udelay(2); /* 1 usec - infinite */ + w2(0x0c); + udelay(10); /* 7 usec - infinite */ + w2(0x0d); + udelay(2); /* 1 usec - infinite */ + w2(0x0c); + udelay(10); /* 7 usec - infinite */ + w0(0xff); + udelay(10); /* 7 usec - infinite */ + + /* + * The following table is electrical pin values. + * (BSY is inverted at the CTR register) + * + * BSY ACK POut SEL Fault + * S1 0 X 1 1 1 + * S2 1 X 0 1 1 + * S3 L X 1 1 S + * + * L => Last device in chain + * S => Selected + * + * Observered values for S1,S2,S3 are: + * Disconnect => f8/58/78 + * Connect => f8/58/70 + */ + if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x30)) + return 1; /* Connected */ + if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x38)) + return 0; /* Disconnected */ + + return -1; /* No device present */ +} + +static inline int do_vpi2_connect (PHA *pha) +{ + pha->saved_r0 = r0(); + pha->saved_r2 = r2(); + + imm_cpp(pha, 0xe0); /* Select device 0 in compatible mode */ + imm_cpp(pha, 0x30); /* Disconnect all devices */ + + if (pha->mode >= 2) + /* Select device 0 in EPP mode */ + return imm_cpp (pha, 0x28); + + /* Select device 0 in compatible mode */ + return imm_cpp (pha, 0xe0); +} + +static void vpi2_connect (PHA *pha) +{ + printk ("--> vpi2_connect\n"); + do_vpi2_connect (pha); + printk ("<--\n"); +} + +static void vpi2_disconnect (PHA *pha) +{ + printk ("--> vpi2_disconnect\n"); + imm_cpp (pha, 0x30); /* Disconnect all devices */ + + w2(pha->saved_r2); + w0(pha->saved_r0); + printk ("<--\n"); +} + + +/* There are no data-transfer tests available, just this simple + check that we are talking to a VPI2. */ +static int vpi2_test_proto (PHA *pha) +{ + int e = 1; + + printk ("--> vpi2_test_proto\n"); + if (do_vpi2_connect(pha) == 1) + e--; + + vpi2_disconnect (pha); + printk ("<-- %d\n", e); + return e; +} + +static int vpi2_select (PHA *pha, int initiator, int target) +{ + printk ("--> vpi2_select\n"); + w2(0xc); + if (r1() & 0x08) { + printk ("<-- -1 (busy)\n"); + return -1; /* bus busy */ + } + + /* + * Now assert the SCSI ID (HOST and TARGET) on the data bus + */ + w2(0x4); + w0(0x80 | (1 << target)); + udelay (1); + + /* + * Deassert SELIN first followed by STROBE + */ + w2(0xc); + w2(0xd); + + printk ("<-- 0\n"); + return 0; + +} + +static int vpi2_test_select (PHA *pha) +{ + int val = r1() & 0x08; + printk ("--> vpi2_test_select\n<-- %d\n", val); + return val; /* BSY asserted ? */ +} + +static void vpi2_select_finish (PHA *pha) +{ + printk ("--> vpi2_select_finish\n<--\n"); + w2(0xc); +} + +static void vpi2_deselect (PHA *pha) +{ + printk ("--> vpi2_deselect\n<--\n"); + w2(0xc); +} + +static int vpi2_get_bus_status (PHA *pha) +{ + int val; + printk ("--> vpi2_get_bus_status\n"); + w2(0xc); + val = vpi2_map[r1()]; + printk ("<-- %d\n", val); + return val; +} + +/* These functions are inlined so the C optimiser can move the switches + outside of loops where possible, am I dreaming ? */ + +static inline int vpi2_read (PHA *pha, int first) +{ + int l, h; + + printk ("--> vpi2_read\n<--\n"); + + switch (pha->mode) { + + case 0: if (first) w2(4); + w2(0x6); h = r1(); + w2(0x5); l = r1(); w2(4); + return j44(h,l); + + case 1: if (first) w2(0x25); + w2(0x26); + l = r0(); + w2(0x25); + return l; + + case 2: if (first) w2(0x24); + return r4(); + + default: return -1; + + } +} + +static inline void vpi2_write (PHA *pha, int v, int first ) +{ + static int alternate; + + printk ("--> vpi2_write\n"); + + switch (pha->mode) { + + case 0: + case 1: + if (first) { + w2(0xc); + alternate = 0; + } + w0(v); + if (alternate) + w2(0x0); + else + w2(0x5); + alternate = 1 - alternate; + break; + + case 2: if (first) w2(0x4); + w4(v); + break; + + } + printk ("<--\n"); +} + +static void vpi2_slow_start (PHA *pha, char *val) +{ + int r; + + printk ("--> vpi2_slow_start\n"); + + w2(0xc); + + r = (r1() & 0x10); + + if (r) *val = vpi2_read(pha,1); + else vpi2_write(pha,*val,1); + + printk ("<--\n"); +} + +static int vpi2_slow_done (PHA *pha) +{ + printk ("--> vpi2_slow_done\n<--\n"); + return 1; /* vpi2 does its own REQ/ACK handshaking */ +} + +static void vpi2_slow_end (PHA *pha) +{ + printk ("--> vpi2_slow_end\n<--\n"); + w2(0xc); +} + +static void vpi2_start_block (PHA *pha, int rd) +{ + printk ("--> vpi2_start_block\n<--\n"); + pha->priv_flag = rd; +} + +static int vpi2_transfer_ready (PHA *pha) +{ + int b; + + printk ("--> vpi2_transfer_ready\n<--\n"); + b = vpi2_get_bus_status(pha); + if ((b & PPSC_PH_STAT) == PPSC_PH_STAT) return -1; + if (b == (PPSC_REQ|PPSC_BSY| pha->priv_flag)) return 128; + return 0; +} + +static int vpi2_transfer_block (PHA *pha, char * buf, int buflen, int rd) +{ + int k, n, i; + + printk ("--> vpi2_transfer_block\n"); + k = 0; + while (k < buflen) { + n = vpi2_transfer_ready(pha); + if (n <= 0 ) break; + if (n > (buflen-k)) n = buflen-k; + for (i=0;i vpi2_transfer_done\n<-- 1\n"); + return 1; +} + +static void vpi2_end_block (PHA *pha, int rd) +{ + printk ("--> vpi2_end_block\n<--\n"); + w2(0xc); +} + +static void vpi2_reset_bus (PHA *pha) +{ + printk ("--> vpi2_reset_bus\n<--\n"); + w2(0xc); + w0(0x40); w2(8); udelay(60); + w2(0xc); +} + +/* Make these correspond to the actual modes supported by the adapter */ + +static char *(mode_strings[3]) = {"Nybble","PS/2","EPP"}; + +static struct ppsc_protocol vpi2_psp = { + + {&host0,&host1,&host2,&host3}, /* params */ + &host_structs, /* hosts */ + 3, /* num_modes */ + 2, /* epp_first */ + 1, /* default_delay */ + 0, /* can_message */ + 16, /* sg_tablesize */ + mode_strings, + vpi2_init, + NULL, + vpi2_connect, + vpi2_disconnect, + vpi2_test_proto, + vpi2_select, + vpi2_test_select, + vpi2_select_finish, + vpi2_deselect, + vpi2_get_bus_status, + vpi2_slow_start, + vpi2_slow_done, + vpi2_slow_end, + vpi2_start_block, + vpi2_transfer_block, + vpi2_transfer_ready, + vpi2_transfer_done, + vpi2_end_block, + vpi2_reset_bus +}; + +int vpi2_detect (Scsi_Host_Template *tpnt) +{ + int val; + printk ("--> vpi2_detect\n"); + val = ppsc_detect( &vpi2_psp, tpnt, verbose); + printk ("<-- %d\n", val); + return val; +} + +#ifdef MODULE + +Scsi_Host_Template driver_template = PPSC_TEMPLATE(vpi2); + +#include "scsi_module.c" + +#else + +void vpi2_setup (char *str, int *ints) +{ + printk ("--> vpi2_setup\n"); + ppsc_gen_setup(stt,4,str); + printk ("<--\n"); +} + +#endif + +/* end of vpi2.c */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/adm1021.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/adm1021.c --- linux-2.4.20-wolk4.1s/drivers/sensors/adm1021.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/adm1021.c 2003-06-01 18:14:30.000000000 +0200 @@ -441,8 +441,8 @@ void adm1021_update_client(struct i2c_cl down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || + !data->valid) { #ifdef DEBUG printk("Starting adm1021 update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/adm1024.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/adm1024.c --- linux-2.4.20-wolk4.1s/drivers/sensors/adm1024.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/adm1024.c 2003-06-01 18:14:30.000000000 +0200 @@ -570,14 +570,13 @@ void adm1024_init_client(struct i2c_clie void adm1024_update_client(struct i2c_client *client) { struct adm1024_data *data = client->data; + int timeout = data->type == adm1024 ? HZ / 2 : HZ * 2; u8 i; down(&data->update_lock); - if ( - (jiffies - data->last_updated > - (data->type == adm1024 ? HZ / 2 : HZ * 2)) - || (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + timeout) + || !data->valid) { #ifdef DEBUG printk("Starting adm1024 update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/adm1025.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/adm1025.c --- linux-2.4.20-wolk4.1s/drivers/sensors/adm1025.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/adm1025.c 2003-06-01 18:14:30.000000000 +0200 @@ -502,14 +502,13 @@ void adm1025_init_client(struct i2c_clie void adm1025_update_client(struct i2c_client *client) { struct adm1025_data *data = client->data; + int timeout = data->type == adm1025 ? HZ / 2 : HZ * 2; u8 i; down(&data->update_lock); - if ( - (jiffies - data->last_updated > - (data->type == adm1025 ? HZ / 2 : HZ * 2)) - || (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + timeout) + || !data->valid) { #ifdef DEBUG printk("Starting adm1025 update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/adm9240.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/adm9240.c --- linux-2.4.20-wolk4.1s/drivers/sensors/adm9240.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/adm9240.c 2003-06-01 18:14:30.000000000 +0200 @@ -579,14 +579,14 @@ void adm9240_init_client(struct i2c_clie void adm9240_update_client(struct i2c_client *client) { struct adm9240_data *data = client->data; + int timeout = data->type == adm9240 ? HZ / 2 : HZ * 2; u8 i; down(&data->update_lock); if ( - (jiffies - data->last_updated > - (data->type == adm9240 ? HZ / 2 : HZ * 2)) - || (jiffies < data->last_updated) || !data->valid) { + time_after(jiffies, data->last_updated + timeout) + || !data->valid) { #ifdef DEBUG printk("Starting adm9240 update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/bt869.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/bt869.c --- linux-2.4.20-wolk4.1s/drivers/sensors/bt869.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/bt869.c 2003-06-01 18:14:30.000000000 +0200 @@ -697,8 +697,8 @@ void bt869_update_client(struct i2c_clie down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { #ifdef DEBUG printk("Starting bt869 update\n"); #endif diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/ddcmon.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/ddcmon.c --- linux-2.4.20-wolk4.1s/drivers/sensors/ddcmon.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/ddcmon.c 2003-06-01 18:14:30.000000000 +0200 @@ -278,8 +278,8 @@ void ddcmon_update_client(struct i2c_cli down(&data->update_lock); - if ((jiffies - data->last_updated > 300 * HZ) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies ,data->last_updated + 300 * HZ) + || !data->valid) { if (i2c_smbus_write_byte(client, 0)) { #ifdef DEBUG printk("ddcmon read start has failed!\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/ds1621.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/ds1621.c --- linux-2.4.20-wolk4.1s/drivers/sensors/ds1621.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/ds1621.c 2003-06-01 18:14:30.000000000 +0200 @@ -390,8 +390,8 @@ void ds1621_update_client(struct i2c_cli down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { #ifdef DEBUG printk("Starting ds1621 update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/eeprom.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/eeprom.c --- linux-2.4.20-wolk4.1s/drivers/sensors/eeprom.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/eeprom.c 2003-06-01 18:14:30.000000000 +0200 @@ -339,8 +339,8 @@ void eeprom_update_client(struct i2c_cli down(&data->update_lock); - if ((jiffies - data->last_updated > 300 * HZ) | - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + 300 * HZ) + || !data->valid) { #ifdef DEBUG printk("Starting eeprom update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/fscpos.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/fscpos.c --- linux-2.4.20-wolk4.1s/drivers/sensors/fscpos.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/fscpos.c 2003-06-01 18:14:30.000000000 +0200 @@ -410,8 +410,8 @@ void fscpos_update_client(struct i2c_cli down(&data->update_lock); - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + 2 * HZ) + || !data->valid) { #ifdef DEBUG printk("Starting fscpos update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/fscscy.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/fscscy.c --- linux-2.4.20-wolk4.1s/drivers/sensors/fscscy.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/fscscy.c 2003-06-01 18:14:30.000000000 +0200 @@ -495,8 +495,8 @@ void fscscy_update_client(struct i2c_cli down(&data->update_lock); - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + 2 * HZ) + || !data->valid) { #ifdef DEBUG printk("Starting fscscy update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/gl518sm.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/gl518sm.c --- linux-2.4.20-wolk4.1s/drivers/sensors/gl518sm.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/gl518sm.c 2003-06-01 18:14:30.000000000 +0200 @@ -574,8 +574,8 @@ void gl518_update_client(struct i2c_clie down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { #ifdef DEBUG printk("Starting gl518 update\n"); @@ -654,7 +654,7 @@ void gl518_update_client_rev00(struct i2 if (data->iterate == 1) { /* 10 sec delay */ /* as that update is slow, we consider the data valid for 30 seconds */ if ( - ((jiffies - data->last_updated_v00 > 30 * HZ) + (time_after(jiffies, data->last_updated_v00 + 30 * HZ) || (data->alarms & 7) || (!data->valid)) && (!data->iterate_lock)) { data->iterate_lock = 1; diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/gl520sm.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/gl520sm.c --- linux-2.4.20-wolk4.1s/drivers/sensors/gl520sm.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/gl520sm.c 2003-06-01 18:14:30.000000000 +0200 @@ -526,8 +526,8 @@ void gl520_update_client(struct i2c_clie down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { #ifdef DEBUG printk("Starting gl520 update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/it87.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/it87.c --- linux-2.4.20-wolk4.1s/drivers/sensors/it87.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/it87.c 2003-06-01 18:14:30.000000000 +0200 @@ -665,8 +665,8 @@ void it87_update_client(struct i2c_clien down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { if (update_vbat) { /* Cleared after each update, so reenable. Value diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/lm75.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/lm75.c --- linux-2.4.20-wolk4.1s/drivers/sensors/lm75.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/lm75.c 2003-06-01 18:14:30.000000000 +0200 @@ -342,8 +342,8 @@ void lm75_update_client(struct i2c_clien down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { #ifdef DEBUG printk("Starting lm75 update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/lm78.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/lm78.c --- linux-2.4.20-wolk4.1s/drivers/sensors/lm78.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/lm78.c 2003-06-01 18:14:30.000000000 +0200 @@ -622,8 +622,8 @@ void lm78_update_client(struct i2c_clien down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { #ifdef DEBUG printk("Starting lm78 update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/lm80.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/lm80.c --- linux-2.4.20-wolk4.1s/drivers/sensors/lm80.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/lm80.c 2003-06-01 18:14:30.000000000 +0200 @@ -507,8 +507,8 @@ void lm80_update_client(struct i2c_clien down(&data->update_lock); - if ((jiffies - data->last_updated > 2 * HZ) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + 2 * HZ) + || !data->valid) { #ifdef DEBUG printk("Starting lm80 update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/lm87.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/lm87.c --- linux-2.4.20-wolk4.1s/drivers/sensors/lm87.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/lm87.c 2003-06-01 18:14:30.000000000 +0200 @@ -648,9 +648,8 @@ void lm87_update_client(struct i2c_clien down(&data->update_lock); - if ((jiffies - data->last_updated > HZ) || /* 1 sec cache */ - (jiffies < data->last_updated) || - !data->valid) { + if (time_after(jiffies, data->last_updated + HZ) /* 1 sec cache */ + || !data->valid) { for (i = 0; i <= 5; i++) { data->in[i] = lm87_read_value(client,LM87_REG_IN(i)); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/lm92.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/lm92.c --- linux-2.4.20-wolk4.1s/drivers/sensors/lm92.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/lm92.c 2003-06-01 18:14:30.000000000 +0200 @@ -134,7 +134,7 @@ static int lm92_read (struct i2c_client lm92_t *data = (lm92_t *) client->data; u16 value[5]; - if ((jiffies - data->timestamp) > HZ) { + if (time_after(jiffies, data->timestamp + HZ)) { if (lm92_read16 (client,LM92_REG_TEMPERATURE,value) < 0 || lm92_read16 (client,LM92_REG_TRIP_HYSTERISIS,value + 1) < 0 || lm92_read16 (client,LM92_REG_TRIP_CRITICAL,value + 2) < 0 || diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/matorb.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/matorb.c --- linux-2.4.20-wolk4.1s/drivers/sensors/matorb.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/matorb.c 2003-06-01 18:14:30.000000000 +0200 @@ -284,8 +284,8 @@ void matorb_update_client(struct i2c_cli down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + !data->valid) { #ifdef DEBUG printk("Starting matorb update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/maxilife.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/maxilife.c --- linux-2.4.20-wolk4.1s/drivers/sensors/maxilife.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/maxilife.c 2003-06-01 18:14:30.000000000 +0200 @@ -848,8 +848,8 @@ void maxi_update_client(struct i2c_clien down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { #ifdef DEBUG printk("maxilife: Starting MaxiLife update\n"); @@ -985,9 +985,8 @@ void maxi99_update_client(struct i2c_cli /*maxi_write_token_loop(client, MAXI_TOK_LCD_LINE3, 13, "Linux 2.2.13"); */ - if ((jiffies - last_updated[sensor][which] > 2 * HZ) || - (jiffies < last_updated[sensor][which] - || !last_updated[sensor][which])) { + if (time_after(jiffies, last_updated[sensor][which] + 2 * HZ) + || !last_updated[sensor][which]) { int tmp, i; diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/mtp008.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/mtp008.c --- linux-2.4.20-wolk4.1s/drivers/sensors/mtp008.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/mtp008.c 2003-06-01 18:14:30.000000000 +0200 @@ -662,8 +662,8 @@ void mtp008_update_client(struct i2c_cli down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { #ifdef DEBUG printk("Starting MTP008 update\n"); #endif diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/pcf8574.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/pcf8574.c --- linux-2.4.20-wolk4.1s/drivers/sensors/pcf8574.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/pcf8574.c 2003-06-01 18:14:30.000000000 +0200 @@ -312,8 +312,8 @@ void pcf8574_update_client(struct i2c_cl down(&data->update_lock); - if ((jiffies - data->last_updated > 5*HZ) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + 5*HZ) + || !data->valid) { #ifdef DEBUG printk("Starting pcf8574 update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/pcf8591.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/pcf8591.c --- linux-2.4.20-wolk4.1s/drivers/sensors/pcf8591.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/pcf8591.c 2003-06-01 18:14:30.000000000 +0200 @@ -337,8 +337,8 @@ void pcf8591_update_client(struct i2c_cl down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { #ifdef DEBUG printk(KERN_DEBUG "Starting pcf8591 update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/sis5595.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/sis5595.c --- linux-2.4.20-wolk4.1s/drivers/sensors/sis5595.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/sis5595.c 2003-06-01 18:14:30.000000000 +0200 @@ -635,8 +635,8 @@ void sis5595_update_client(struct i2c_cl down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { for (i = 0; i <= data->maxins; i++) { data->in[i] = diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/smsc47m1.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/smsc47m1.c --- linux-2.4.20-wolk4.1s/drivers/sensors/smsc47m1.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/smsc47m1.c 2003-06-01 18:14:30.000000000 +0200 @@ -391,8 +391,8 @@ void smsc47m1_update_client(struct i2c_c down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { for (i = 1; i <= 2; i++) { data->fan[i - 1] = smsc47m1_read_value(client, SMSC47M1_REG_FAN(i)); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/thmc50.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/thmc50.c --- linux-2.4.20-wolk4.1s/drivers/sensors/thmc50.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/thmc50.c 2003-06-01 18:14:30.000000000 +0200 @@ -364,8 +364,8 @@ void thmc50_update_client(struct i2c_cli down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { #ifdef DEBUG printk("Starting thmc50 update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/via686a.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/via686a.c --- linux-2.4.20-wolk4.1s/drivers/sensors/via686a.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/via686a.c 2003-06-01 18:14:30.000000000 +0200 @@ -742,8 +742,8 @@ void via686a_update_client(struct i2c_cl down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { for (i = 0; i <= 4; i++) { data->in[i] = diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/vt1211.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/vt1211.c --- linux-2.4.20-wolk4.1s/drivers/sensors/vt1211.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/vt1211.c 2003-06-01 18:14:30.000000000 +0200 @@ -505,8 +505,8 @@ void vt1211_update_client(struct i2c_cli down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { data->uch_config = vt_rdval(client, VT1211_REG_UCH_CONFIG); for (i = 0; i <= 6; i++) { if(ISVOLT(i, data->uch_config)) { diff -Naurp linux-2.4.20-wolk4.1s/drivers/sensors/w83781d.c linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/w83781d.c --- linux-2.4.20-wolk4.1s/drivers/sensors/w83781d.c 2003-05-15 21:52:35.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/sensors/w83781d.c 2003-06-01 18:14:30.000000000 +0200 @@ -1485,8 +1485,8 @@ void w83781d_update_client(struct i2c_cl down(&data->update_lock); - if ((jiffies - data->last_updated > HZ + HZ / 2) || - (jiffies < data->last_updated) || !data->valid) { + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { #ifdef DEBUG printk(KERN_DEBUG "Starting device update\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/usb/Config.in linux-2.4.20-wolk4.2-fullkernel/drivers/usb/Config.in --- linux-2.4.20-wolk4.1s/drivers/usb/Config.in 2003-05-15 21:52:36.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/usb/Config.in 2003-06-03 20:02:49.000000000 +0200 @@ -32,7 +32,13 @@ if [ "$CONFIG_USB" = "y" -o "$CONFIG_US comment 'USB Device Class drivers' dep_tristate ' USB Audio support' CONFIG_USB_AUDIO $CONFIG_USB $CONFIG_SOUND dep_tristate ' EMI 2|6 USB Audio interface support' CONFIG_USB_EMI26 $CONFIG_USB_AUDIO - dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB $CONFIG_EXPERIMENTAL + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_BLUEZ" = "n" ]; then + dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB + else + comment ' USB Bluetooth can only be used with disabled Bluetooth subsystem' + fi + fi dep_tristate ' USB MIDI support' CONFIG_USB_MIDI $CONFIG_USB if [ "$CONFIG_SCSI" = "n" ]; then comment ' SCSI support is needed for USB Storage' @@ -117,8 +123,5 @@ if [ "$CONFIG_USB" = "y" -o "$CONFIG_US dep_tristate ' Tieman Voyager USB Braille display support (EXPERIMENTAL)' CONFIG_USB_BRLVGER $CONFIG_USB $CONFIG_EXPERIMENTAL dep_tristate ' USB LCD device support' CONFIG_USB_LCD $CONFIG_USB dep_tristate ' USB Modem Alcatel Speedtouch support' CONFIG_USB_SPEEDTOUCH $CONFIG_ATM $CONFIG_USB - if [ "$CONFIG_USB_SPEEDTOUCH" != "n" ]; then - define_bool CONFIG_ATM y - fi fi endmenu diff -Naurp linux-2.4.20-wolk4.1s/drivers/usb/storage/transport.c linux-2.4.20-wolk4.2-fullkernel/drivers/usb/storage/transport.c --- linux-2.4.20-wolk4.1s/drivers/usb/storage/transport.c 2002-12-18 01:03:58.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/usb/storage/transport.c 2003-06-02 17:21:08.000000000 +0200 @@ -1233,7 +1233,8 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *s US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n", le32_to_cpu(bcs->Signature), bcs->Tag, bcs->Residue, bcs->Status); - if (bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) || + if ((bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN) && + bcs->Signature != cpu_to_le32(US_BULK_CS_SIGN2)) || bcs->Tag != bcb->Tag || bcs->Status > US_BULK_STAT_PHASE || partial != 13) { US_DEBUGP("Bulk logical error\n"); diff -Naurp linux-2.4.20-wolk4.1s/drivers/usb/storage/transport.h linux-2.4.20-wolk4.2-fullkernel/drivers/usb/storage/transport.h --- linux-2.4.20-wolk4.1s/drivers/usb/storage/transport.h 2002-12-18 01:03:58.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/usb/storage/transport.h 2003-06-03 11:49:38.000000000 +0200 @@ -106,6 +106,7 @@ struct bulk_cs_wrap { #define US_BULK_CS_WRAP_LEN 13 #define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */ +#define US_BULK_CS_SIGN2 0x55425355 /* spells out 'USBU', hack */ #define US_BULK_STAT_OK 0 #define US_BULK_STAT_FAIL 1 #define US_BULK_STAT_PHASE 2 diff -Naurp linux-2.4.20-wolk4.1s/drivers/usb/storage/unusual_devs.h linux-2.4.20-wolk4.2-fullkernel/drivers/usb/storage/unusual_devs.h --- linux-2.4.20-wolk4.1s/drivers/usb/storage/unusual_devs.h 2003-05-15 21:52:37.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/usb/storage/unusual_devs.h 2003-06-03 11:49:41.000000000 +0200 @@ -37,12 +37,6 @@ * then by ProductID. */ -UNUSUAL_DEV(0x05e3,0x0700,0x000,0xffff, - "Carry", - "USB Reader UICGL", - US_SC_SCSI,US_PR_BULK,NULL, - US_FL_FIX_INQUIRY), - UNUSUAL_DEV( 0x03ee, 0x0000, 0x0000, 0x0245, "Mitsumi", "CD-R/RW Drive", @@ -82,6 +76,12 @@ UNUSUAL_DEV( 0x0411, 0x001c, 0x0113, 0x US_SC_SCSI, US_PR_BULK, NULL, US_FL_FIX_INQUIRY | US_FL_START_STOP), +UNUSUAL_DEV( 0x0421, 0x0404, 0x0000, 0xffff, + "Nokia", + "5510", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_START_STOP), + #ifdef CONFIG_USB_STORAGE_DPCM UNUSUAL_DEV( 0x0436, 0x0005, 0x0100, 0x0100, "Microtech", @@ -103,6 +103,22 @@ UNUSUAL_DEV( 0x04a4, 0x0004, 0x0001, 0x "DVD-CAM DZ-MV100A Camcorder", US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN), +/* Reported by Khalid Aziz + * This entry is needed because the device reports Sub=ff */ +UNUSUAL_DEV( 0x04b8, 0x0602, 0x0110, 0x0110, + "Epson", + "785EPX Storage", + US_SC_SCSI, US_PR_BULK, NULL, US_FL_SINGLE_LUN), + +/* Reported by Jan Willamowius + * The device needs the flags only. + */ +UNUSUAL_DEV( 0x04c8, 0x0723, 0x0000, 0x9999, + "Konica", + "KD-200Z", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_START_STOP), + UNUSUAL_DEV( 0x04cb, 0x0100, 0x0000, 0x2210, "Fujifilm", "FinePix 1400Zoom", @@ -127,12 +143,6 @@ UNUSUAL_DEV( 0x04da, 0x0901, 0x0100, 0x "LS-120 Camera", US_SC_UFI, US_PR_CBI, NULL, 0), -/* From Yukihiro Nakai, via zaitcev@yahoo.com. */ -UNUSUAL_DEV( 0x04da, 0x0d05, 0x0000, 0x0000, - "Sharp CE-CW05", - "CD-R/RW Drive", - US_SC_8070, US_PR_CB, NULL, 0), - /* Most of the following entries were developed with the help of * Shuttle/SCM directly. */ @@ -219,18 +229,12 @@ UNUSUAL_DEV( 0x0525, 0xa140, 0x0100, 0x US_FL_FIX_INQUIRY | US_FL_START_STOP ), /* This entry is needed because the device reports Sub=ff */ -UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0422, +UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0440, "Sony", - "DSC-S30/S70/S75/505V/F505/F707", + "DSC-S30/S70/S75/505V/F505/F707/F717", US_SC_SCSI, US_PR_CB, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ), -UNUSUAL_DEV( 0x054c, 0x0010, 0x0106, 0x0430, - "Sony", - "DSC-U10", - US_SC_SCSI, US_PR_CB, NULL, - US_FL_SINGLE_LUN | US_FL_START_STOP | US_FL_MODE_XLATE ), - /* Reported by wim@geeks.nl */ UNUSUAL_DEV( 0x054c, 0x0025, 0x0100, 0x0100, "Sony", @@ -256,6 +260,13 @@ UNUSUAL_DEV( 0x054c, 0x0032, 0x0000, 0x "Memorystick MSC-U01N", US_SC_UFI, US_PR_CB, NULL, US_FL_SINGLE_LUN | US_FL_START_STOP ), + +/* Attempt to get the Sony MSC-U03 to work on a Vaio PCG-SRX77 */ +UNUSUAL_DEV( 0x054c, 0x0069, 0x0000, 0x9999, + "Sony", + "Memorystick MSC-U03", + US_SC_UFI, US_PR_CB, NULL, + US_FL_SINGLE_LUN | US_FL_START_STOP ), /* Submitted by Nathan Babb */ UNUSUAL_DEV( 0x054c, 0x006d, 0x0000, 0x9999, @@ -406,7 +417,7 @@ UNUSUAL_DEV( 0x0781, 0x0002, 0x0009, 0x "Sandisk", "ImageMate SDDR-31", US_SC_SCSI, US_PR_BULK, NULL, - US_FL_IGNORE_SER | US_FL_START_CHECK ), + US_FL_IGNORE_SER), UNUSUAL_DEV( 0x0781, 0x0100, 0x0100, 0x0100, "Sandisk", @@ -505,6 +516,18 @@ UNUSUAL_DEV( 0x07c4, 0xa109, 0x0000, 0x US_FL_MODE_XLATE ), #endif +/* Datafab KECF-USB / Sagatek DCS-CF / Simpletech Flashlink UCF-100 + * Only revision 1.13 tested (same for all of the above devices, + * based on the Datafab DF-UG-07 chip). Needed for US_FL_FIX_INQUIRY. + * Submitted by Marek Michalkiewicz . + * See also http://martin.wilck.bei.t-online.de/#kecf . + */ +UNUSUAL_DEV( 0x07c4, 0xa400, 0x0000, 0xffff, + "Datafab", + "KECF-USB", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY ), + /* Casio QV 2x00/3x00/4000/8000 digital still cameras are not conformant * to the USB storage specification in two ways: * - They tell us they are using transport protocol CBI. In reality they @@ -524,6 +547,12 @@ UNUSUAL_DEV( 0x097a, 0x0001, 0x0000, 0x US_SC_SCSI, US_PR_CB, NULL, US_FL_MODE_XLATE ), +UNUSUAL_DEV( 0x0a16, 0x8888, 0x0100, 0x0100, + "IBM", + "IBM USB Memory Key", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY ), + #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x0bf6, 0xa001, 0x0100, 0x0110, "ATI", diff -Naurp linux-2.4.20-wolk4.1s/drivers/usb/storage/usb.c linux-2.4.20-wolk4.2-fullkernel/drivers/usb/storage/usb.c --- linux-2.4.20-wolk4.1s/drivers/usb/storage/usb.c 2003-05-15 21:52:37.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/usb/storage/usb.c 2002-12-18 01:03:58.000000000 +0100 @@ -453,20 +453,6 @@ static int usb_stor_control_thread(void US_DEBUGP("Faking INQUIRY command\n"); fill_inquiry_response(us, data_ptr, 36); us->srb->result = GOOD << 1; - } else if ((us->srb->cmnd[0] == START_STOP) && - (us->flags & US_FL_START_CHECK)) { - unsigned char saved_cdb[6]; - - /* Handle those devices which fake - * START_STOP on us, this confuses - * the hell out of media check code. */ - US_DEBUGP("Convering START_STOP command\n"); - memcpy(saved_cdb, us->srb->cmnd, 6); - memset(us->srb->cmnd, 0, 6); - us->srb->cmnd[0] = TEST_UNIT_READY; - US_DEBUG(usb_stor_show_command(us->srb)); - us->proto_handler(us->srb, us); - memcpy(us->srb->cmnd, saved_cdb, 6); } else { /* we've got a command, let's do it! */ US_DEBUG(usb_stor_show_command(us->srb)); diff -Naurp linux-2.4.20-wolk4.1s/drivers/usb/storage/usb.h linux-2.4.20-wolk4.2-fullkernel/drivers/usb/storage/usb.h --- linux-2.4.20-wolk4.1s/drivers/usb/storage/usb.h 2003-05-15 21:52:37.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/usb/storage/usb.h 2003-06-03 11:49:38.000000000 +0200 @@ -98,7 +98,6 @@ struct us_unusual_dev { #define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 commands for Win/MacOS compatibility */ #define US_FL_START_STOP 0x00000004 /* ignore START_STOP commands */ -#define US_FL_START_CHECK 0x00000008 /* START_STOP => TEST UNIT READY */ #define US_FL_IGNORE_SER 0x00000010 /* Ignore the serial number given */ #define US_FL_SCM_MULT_TARG 0x00000020 /* supports multiple targets */ #define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ diff -Naurp linux-2.4.20-wolk4.1s/drivers/video/vesafb.c linux-2.4.20-wolk4.2-fullkernel/drivers/video/vesafb.c --- linux-2.4.20-wolk4.1s/drivers/video/vesafb.c 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/drivers/video/vesafb.c 2003-06-02 17:21:08.000000000 +0200 @@ -95,6 +95,7 @@ static union { static int inverse = 0; static int mtrr = 1; +static int vram __initdata = 0; /* needed for vram boot option */ static int currcon = 0; static int pmi_setpal = 0; /* pmi for palette changes ??? */ @@ -480,6 +481,10 @@ int __init vesafb_setup(char *options) pmi_setpal=1; else if (! strcmp(this_opt, "mtrr")) mtrr=1; + /* checks for vram boot option */ + else if (! strncmp(this_opt, "vram:", 5)) + vram = simple_strtoul(this_opt+5, NULL, 0); + else if (!strncmp(this_opt, "font:", 5)) strcpy(fb_info.fontname, this_opt+5); } @@ -638,6 +643,13 @@ int __init vesafb_init(void) video_height = screen_info.lfb_height; video_linelength = screen_info.lfb_linelength; video_size = screen_info.lfb_width * screen_info.lfb_height * video_bpp / 8; + + /* FIXME: Should we clip against declared size for banked devices ? */ + + /* sets video_size according to vram boot option */ + if (vram && vram * 1024 * 1024 > video_size) + video_size = vram * 1024 * 1024; + video_visual = (video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; diff -Naurp linux-2.4.20-wolk4.1s/evfs/Makefile linux-2.4.20-wolk4.2-fullkernel/evfs/Makefile --- linux-2.4.20-wolk4.1s/evfs/Makefile 2003-05-15 21:52:38.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/evfs/Makefile 2003-06-02 17:21:01.000000000 +0200 @@ -2,7 +2,7 @@ CFLAGS=-Wall -O6 -fomit-frame-pointer -f .c.o: gcc $(CFLAGS) -c $< -all: efs install +all: efs aes.o: aes.c aes.h sha256.o: sha256.c sha256.h getpw.o: getpw.c getpw.h diff -Naurp linux-2.4.20-wolk4.1s/evfs/efs.c linux-2.4.20-wolk4.2-fullkernel/evfs/efs.c --- linux-2.4.20-wolk4.1s/evfs/efs.c 2003-05-15 21:52:38.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/evfs/efs.c 2003-06-02 17:21:01.000000000 +0200 @@ -1,4 +1,4 @@ -/* evfs 0.1 2003 sd */ +/* evfs 0.3 2003 sd */ #define MINLEN 6 /* minimum password len */ #define MAX_MOUNTS_PER_USER 3 /* maximum evfs mounts per user */ @@ -163,12 +163,14 @@ int do_create(char *mark) while (1) { pwd1 = getpwd("Enter your new password:"); pwd2 = getpwd("Retype your new password:"); - if (strcmp(pwd1, pwd2)) { - printf("Sorry, passwords do not match.\n"); + + if ((!pwd1 || !pwd2) || (strlen(pwd1) < MINLEN)) { + printf("Sorry, but minimal length for password is %d characters\n", MINLEN); goto out; } - if (strlen(pwd1) < MINLEN) { - printf("Sorry, but minimal length for password is %d characters\n", MINLEN); + + if (strcmp(pwd1, pwd2)) { + printf("Sorry, passwords do not match.\n"); goto out; } putpwd(pwd2); @@ -321,7 +323,7 @@ badperm: /* uh, uh, everything is really ok ? hard to believe, but ok, we'll mount it now */ sfree(buf); - buf = salloc(strlen(from) + strlen(pwd) + 3); + buf = salloc(strlen(from) + strlen(pwd) + strlen(to) + 3); /* thanx Paul Lasarev! */ sprintf(buf, "%s %s %s", from, to, pwd); i = mount(from, to, "evfs", MOUNT_FLAGS, buf); if (!i) { @@ -344,7 +346,7 @@ badperm: int main(int argc, char *argv[]) { printf( - "Encrypted Virtual File System v0.2 (linux release)\n" + "Encrypted Virtual File System v0.3 (linux release)\n" "(c) 2003 sd http://hysteria.sk/evfs\n"); if (argc != 2 && argc != 3) { printf("use:\n" @@ -354,6 +356,7 @@ int main(int argc, char *argv[]) "be directories and *must* match your uid/gid\n", argv[0], argv[0]); return 1; } + setfsgid(getgid()); /* uhh uhh. this is essential *g* */ setfsuid(getuid()); if (argc == 3) { char *from = argv[1]; diff -Naurp linux-2.4.20-wolk4.1s/evfs/evfs_core.c linux-2.4.20-wolk4.2-fullkernel/evfs/evfs_core.c --- linux-2.4.20-wolk4.1s/evfs/evfs_core.c 2003-05-15 21:52:38.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/evfs/evfs_core.c 1970-01-01 01:00:00.000000000 +0100 @@ -1,1205 +0,0 @@ -/* evfs 0.2 2003 sd */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "evfs.h" -#include "aes.h" -#include "sha256.h" -#include "base64.h" - -/* those is considered to be the fastest */ -#define EVFS_BLK_SIZE PAGE_CACHE_SIZE -#define EVFS_BLK_BITS 12 -/* padlen, all of it's bits must be *always* 1 in line, f.e. : 1,3,7,15,31 ... */ -#define PADLEN (AES_BLOCK_SIZE-1) -#define KBUFSZ (PADLEN+PAGE_CACHE_SIZE) -#define SALTLEN 16 - -//#define track() printk("track: " __func__ "()/%d reached\n", __LINE__) -#define track() - - -extern long sys_readlink(const char * path, char * buf, int bufsiz); -extern long sys_link(const char * oldname, const char * newname); -extern long sys_unlink(const char * pathname); -extern long sys_symlink(const char * oldname, const char * newname); -extern long sys_mkdir(const char * pathname, int mode); -extern long sys_rmdir(const char * pathname); -extern long sys_mknod(const char * filename, int mode, dev_t dev); -extern long sys_rename(const char * oldname, const char * newname); - - -struct evfs_ctx { - struct aes_ctx aes; /* master aes key */ - /* we've 256 salts by 16 bytes, after 1mb it will repeat - - give chance to compress really big files ;)) */ - /* (256*PAGE_CACHE_SIZE) */ - char salts[256][SALTLEN]; - int recursion; -}; - - -static struct super_operations evfs_sbops; -static struct inode_operations evfs_file_iops; -static struct inode_operations evfs_dir_iops; -static struct file_operations evfs_fops; -static struct file_operations evfs_dir_fops; -static struct address_space_operations evfs_aops; -static struct address_space_operations evfs_link_aops; -static struct dentry_operations evfs_dentry_ops; - -/************************************************************************** - General purpose functions - **************************************************************************/ - -#define get_mem() kmalloc(PAGE_CACHE_SIZE + 1024, GFP_KERNEL) -#define put_mem(x) kfree(x) -#define COPY_INODE(i,g) \ - i->i_size = S_ISREG(g->i_mode)?((g->i_size > PADLEN)?g->i_size - PADLEN:0):(S_ISLNK(g->i_mode)?0:g->i_size); \ - i->i_ino = g->i_ino; \ - i->i_mode = g->i_mode; \ - i->i_nlink = g->i_nlink; \ - i->i_uid = g->i_uid; \ - i->i_gid = g->i_gid; \ - i->i_rdev = g->i_rdev; \ - i->i_atime = g->i_atime; \ - i->i_mtime = g->i_mtime; \ - i->i_ctime = g->i_ctime; \ - i->i_blkbits = EVFS_BLK_BITS; \ - i->i_blksize = EVFS_BLK_SIZE; \ - i->i_blocks = (g->i_blocks * (1 << g->i_blkbits)) / EVFS_BLK_SIZE; - - -struct evfs_inode { - char *host_filename; - char *sym; - struct file *fd; -}; -#define evfs_i(x) (*((struct evfs_inode *) &(x)->u.generic_ip)) -#define file_evfs_i(file) (&evfs_i((file)->f_dentry->d_inode)) -#define evfs_key(x) ((struct evfs_ctx *) (x)->u.generic_sbp) -#define gk(i) (evfs_key((i->i_sb))) - -static int my_truncate(struct dentry *dentry, loff_t length) -{ - struct inode *inode = dentry->d_inode; - int error; - struct iattr newattrs; - - down(&inode->i_sem); - newattrs.ia_size = length; - newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; - error = notify_change(dentry, &newattrs); - up(&inode->i_sem); - return error; -} - -static inline char *get_salt(struct evfs_ctx *ctx, u8 index, char *buf) -{ - if (!ctx) - memset(buf, 0, SALTLEN); - else - memcpy(buf, &ctx->salts[index][0], SALTLEN); - return buf; -} - -static inline char *kstrdup(char *s) -{ - char *p = kmalloc(strlen(s) + 1, GFP_KERNEL); - if (!p) - return NULL; - strcpy(p, s); - return p; -} - -static inline int hpath_lookup_dir(char *name, struct nameidata *nd, int flags) -{ - int error = 0; - track(); - if (path_init(name, LOOKUP_POSITIVE|LOOKUP_DIRECTORY|flags, nd)) - error = path_walk(name, nd); - track(); - return error; -} - - -static inline int hpath_lookup(char *name, struct nameidata *nd) -{ - int error = 0; - track(); - if (path_init(name, LOOKUP_POSITIVE, nd)) - error = path_walk(name, nd); - track(); - return error; -} - -static int read_name(struct inode *ino, char *name) -{ - struct nameidata nd; - int error = hpath_lookup(name, &nd); - track(); - if (error) return error; - if (!nd.dentry->d_inode) { - path_release(&nd); - return -ENOENT; - } - COPY_INODE(ino, nd.dentry->d_inode); - path_release(&nd); - return error; -} - -static int file_type(char *name, int *rdev) -{ - struct nameidata nd; - int error = hpath_lookup(name, &nd); - track(); - if (!error) { - if (nd.dentry->d_inode) { - error = nd.dentry->d_inode->i_mode; - if (rdev) - *rdev = nd.dentry->d_inode->i_rdev; - } else { - error = -1024; - } - path_release(&nd); - } - return error; -} - - - -/* translate our virtual path (discovered by traversing - dcache tree) to real encrypted names path */ -static char *dentry_name(struct dentry *dentry, int extra, struct super_block *sb) -{ - struct dentry *parent; - char *name, *root; - int len, rootlen; - char tmp[NAME_MAX + 1]; - - track(); -/* if ((dentry->d_name.len == sizeof(EVFS_COOKIE)-1) && - (!memcmp(dentry->d_name.name, EVFS_COOKIE, sizeof(EVFS_COOKIE)-1))) - return NULL; */ - len = 0; - for (parent = dentry; parent->d_parent != parent; parent = parent->d_parent) - len += norm2baselen((parent->d_name.len + PADLEN) & ~PADLEN) + 1; /* +1 for '/' */ - - track(); - root = evfs_i(parent->d_inode).host_filename; - rootlen = strlen(root); - len += rootlen; - track(); - name = kmalloc(len + extra + 1, GFP_KERNEL); - if (!name) - return NULL; - track(); - memcpy(name, root, rootlen); - name[len] = 0; - - /* count length of whole tree (only approx!) */ - track(); - for (parent = dentry; parent->d_parent != parent; parent = parent->d_parent) { - int alen = (parent->d_name.len + PADLEN) & ~PADLEN; - int elen = norm2baselen(alen); - char salt[SALTLEN]; - - track(); - len -= elen + 1; - name[len] = '/'; - memset(tmp, 0, alen); - memcpy(tmp, parent->d_name.name, parent->d_name.len); - track(); - if (!sb) sb = dentry->d_inode->i_sb; - aes_encrypt_str(&evfs_key(sb)->aes, tmp, tmp, alen, get_salt(NULL, 0, salt)); - track(); - base64_encode(tmp, name + len + 1, alen); - } - return name; -} - -static char *inode_name(struct inode *ino, int extra) -{ - struct dentry *dentry; - - track(); - dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias); - return(dentry_name(dentry, extra, ino->i_sb)); -} - -static struct inode *get_inode(struct super_block *sb, struct dentry *dentry, - int *error) -{ - struct inode *inode; - char *name; - int type, err = -ENOMEM, rdev; - - track(); - inode = new_inode(sb); - if(inode == NULL) - goto out; - - evfs_i(inode).host_filename = NULL; - evfs_i(inode).fd = NULL; - evfs_i(inode).sym = NULL; - insert_inode_hash(inode); - if(dentry){ - name = dentry_name(dentry, 0, sb); - if(name == NULL){ - err = -ENOMEM; - goto out_put; - } - type = file_type(name, &rdev); - if (type == -1024) { - type = S_IFLNK; - } else - if (S_ISLNK(type)) { - int c, n; - char *buf = get_mem(); - mm_segment_t fs = get_fs(); - set_fs(KERNEL_DS); - c = sys_readlink(name, buf, PAGE_CACHE_SIZE-1); - set_fs(fs); - n = base2normlen(c); - if ((c > 0) && !(n & PADLEN)) { - char *tmp = get_mem(); - char salt[SALTLEN]; - /* symlink is ok, decode it */ - base64_decode(buf, tmp, c); - aes_decrypt_str(&evfs_key(sb)->aes, tmp, tmp, n, get_salt(NULL, 0, salt)); - tmp[n] = 0; - evfs_i(inode).sym = tmp; - } - put_mem(buf); - } - kfree(name); - } - else type = S_IFDIR; - inode->i_sb = sb; - - err = 0; - if(S_ISLNK(type)) - inode->i_op = &page_symlink_inode_operations; - else if(S_ISDIR(type)) - inode->i_op = &evfs_dir_iops; - else inode->i_op = &evfs_file_iops; - - if(S_ISDIR(type)) inode->i_fop = &evfs_dir_fops; - else inode->i_fop = &evfs_fops; - - if(S_ISLNK(type)) - inode->i_mapping->a_ops = &evfs_link_aops; - else inode->i_mapping->a_ops = &evfs_aops; - - if (S_ISCHR(type)) - init_special_inode(inode, S_IFCHR, rdev); - else - if (S_ISBLK(type)) - init_special_inode(inode, S_IFBLK, rdev); - else - if (S_ISFIFO(type)) - init_special_inode(inode, S_IFIFO, 0); - else - if (S_ISSOCK(type)) - init_special_inode(inode, S_IFSOCK, 0); - - if(error) *error = err; - return(inode); - out_put: - iput(inode); - out: - if(error) *error = err; - return(NULL); -} - - - -/************************************************************************** - Super operations - **************************************************************************/ -/* purge an evfs inode */ -static void evfs_delete_inode(struct inode *ino) -{ - track(); - if (evfs_i(ino).host_filename) - kfree(evfs_i(ino).host_filename); - evfs_i(ino).host_filename = NULL; - - if(evfs_i(ino).fd) { - /* set real size */ - if (S_ISREG(ino->i_mode)) - my_truncate(evfs_i(ino).fd->f_dentry, ino->i_size + PADLEN); - fput(evfs_i(ino).fd); - evfs_i(ino).fd = NULL; - } - if(evfs_i(ino).sym) { - put_mem(evfs_i(ino).sym); - evfs_i(ino).sym = NULL; - } - clear_inode(ino); -} - - -/* stat a filesystem */ -int evfs_statfs(struct super_block *sb, struct statfs *sf) -{ - struct nameidata nd; - int error; - error = hpath_lookup(evfs_i(sb->s_root->d_inode).host_filename, &nd); - if (!error) { - error = vfs_statfs(nd.dentry->d_inode->i_sb, sf); - path_release(&nd); - } - return error; -} - -static void evfs_putsuper(struct super_block *s) -{ - track(); - kfree(evfs_key(s)); -} - -/* read evfs superblock */ -static struct super_block *evfs_read_super(struct super_block *s, void *d, int silent) -{ - char *data = d; - char *password; - char *name, *to; - struct inode *root_inode; - char buf[32]; - struct sha256_ctx ctx; - struct nameidata nd, ns; - struct dentry *parent; - - int uid = current->fsuid; - int gid = current->fsgid; - - track(); - /* first some basic super ops */ - s->s_blocksize = EVFS_BLK_SIZE; - s->s_blocksize_bits = EVFS_BLK_BITS; - s->s_magic = EVFS_MAGIC; - s->s_op = &evfs_sbops; - - /* and some common checks */ - if (!data || !*data) { - printk("evfs: source mount directory not specified\n"); - return NULL; - } - - /* extract from, to and password */ - for (to = data; *to != ' '; to++) { - if (!*to) { - printk("evfs: invalid number of arguments (destination and password missing)\n"); - return NULL; - } - } - *to++ = 0; - - for (password = to; *password != ' '; password++) - if (!*password) { - printk("evfs: no password supplied while mounting %s\n", data); - return NULL; - } - *password++ = 0; - - if (hpath_lookup_dir(to, &nd, LOOKUP_FOLLOW)) { - printk("evfs: error while looking up mount destination!\n"); - return NULL; - } - - /* check uid ... */ - if (uid) - if ((nd.dentry->d_inode->i_uid != uid) || (!nd.dentry->d_inode->i_gid != gid)) { - printk("evfs: *WARNING*, uid %d supplied someone's else directory as destination!\n", uid); - goto out_nd; - } - - /* and absolute path */ - if (data[0] != '/') { - printk("evfs: attempted to mount relative path %s!\n", data); - goto out_nd; - } - - /* create root inode */ - root_inode = get_inode(s, NULL, NULL); - if (!root_inode) - goto out_nd; - name = kstrdup(data); - track(); - s->s_root = d_alloc_root(root_inode); - evfs_i(root_inode).host_filename = name; - track(); - - if (hpath_lookup_dir(name, &ns, 0)) - goto out; - - if (ns.dentry->d_inode->i_sb->s_magic == EVFS_MAGIC) { - printk("evfs: uid %d tried to mount evfs from evfs - not supported yet, to avoid recursion.\n", uid); - goto out_put; - } - - COPY_INODE(root_inode, ns.dentry->d_inode); - - track(); - /* hrmm. comparing whether source is not in destinating directory *is* good idea */ - for (parent = ns.dentry; parent != parent->d_parent; parent = parent->d_parent) { - if (parent == nd.dentry) - goto out_put; - } - track(); - - if (uid) - if ((root_inode->i_uid != uid || root_inode->i_gid != gid) && - ((uid != 0) && (gid != 0))) - goto out_put; - - evfs_key(s) = kmalloc(sizeof(struct evfs_ctx), GFP_KERNEL); - if (!evfs_key(s)) - goto out_put; - sha256_init(&ctx); - sha256_update(&ctx, password, strlen(password)); - sha256_final(&ctx, buf); - memset(&ctx, 0xF8, sizeof(ctx)); - aes_set_key(&evfs_key(s)->aes, buf); - evfs_key(s)->recursion = 0; - memset(evfs_key(s)->salts, buf[0] + buf[31], sizeof(evfs_key(s)->salts)); - /* initialize disk block salts (one for one blocks, 256 total, then repeats */ - aes_encrypt_str(&evfs_key(s)->aes, &evfs_key(s)->salts[0][0], &evfs_key(s)->salts[0][0], sizeof(evfs_key(s)->salts), buf); - memset(buf, 0xF8, 32); - - path_release(&nd); - path_release(&ns); - return s; -out_put: - track(); - path_release(&ns); -out: - iput(root_inode); -out_nd: - track(); - path_release(&nd); - return NULL; -} - -/************************************************************************** - Inode operations - **************************************************************************/ -int evfs_create(struct inode *dir, struct dentry *dentry, int mode) -{ - struct inode *inode; - char *name; - struct file *fd; - int error; - - track(); - inode = get_inode(dir->i_sb, dentry, &error); - if (error) return(error); - name = dentry_name(dentry, 0, dir->i_sb); - if(name == NULL){ - iput(inode); - return(-ENOMEM); - } - fd = filp_open(name, O_CREAT | O_EXCL, mode); - error = IS_ERR(fd); - if (!error) { - my_truncate(fd->f_dentry, PADLEN); - fput(fd); - } - else error = PTR_ERR(fd); - if(!error) error = read_name(inode, name); - kfree(name); - if(error) { - iput(inode); - return(error); - } - d_instantiate(dentry, inode); - return(0); -} - -struct dentry *evfs_lookup(struct inode *ino, struct dentry *dentry) -{ - struct inode *inode; - char *name; - int error; - - track(); - inode = get_inode(ino->i_sb, dentry, &error); - if(error != 0) return(ERR_PTR(error)); - name = dentry_name(dentry, 0, ino->i_sb); - if(name == NULL) return(ERR_PTR(-ENOMEM)); - error = read_name(inode, name); - kfree(name); - if(error){ - iput(inode); - if(error == -ENOENT) inode = NULL; - else return(ERR_PTR(error)); - } - d_add(dentry, inode); - dentry->d_op = &evfs_dentry_ops; - return(NULL); -} - -static char *inode_dentry_name(struct inode *ino, struct dentry *dentry) -{ - char *file; - int fl, i; - int alen = (dentry->d_name.len + PADLEN) & ~PADLEN; - int elen = norm2baselen(alen); - char tmp[NAME_MAX + 1]; - char salt[SALTLEN]; - -/* if ((dentry->d_name.len == sizeof(EVFS_COOKIE)-1) && - (!memcmp(dentry->d_name.name, EVFS_COOKIE, sizeof(EVFS_COOKIE)-1))) - return NULL; */ - - track(); - file = inode_name(ino, elen + 1); - if (file == NULL) return(NULL); - fl = strlen(file); - file[fl++] = '/'; - memset(tmp, 0, alen); - memcpy(tmp, dentry->d_name.name, dentry->d_name.len); - aes_encrypt_str(&evfs_key(ino->i_sb)->aes, tmp, tmp, alen, get_salt(NULL, 0, salt)); - i = base64_encode(tmp, file + fl, alen); - file[fl + i] = 0; - return(file); -} - -int evfs_link(struct dentry *to, struct inode *ino, struct dentry *from) -{ - char *from_name, *to_name; - int err; - mm_segment_t fs; - - track(); - if((from_name = inode_dentry_name(ino, from)) == NULL) - return(-ENOMEM); - to_name = dentry_name(to, 0, ino->i_sb); - if(to_name == NULL){ - kfree(from_name); - return(-ENOMEM); - } - fs = get_fs(); set_fs(KERNEL_DS); - err = sys_link(to_name, from_name); - set_fs(fs); - kfree(from_name); - kfree(to_name); - return(err); -} - -int evfs_unlink(struct inode *ino, struct dentry *dentry) -{ - char *file; - int err; - mm_segment_t fs; - - track(); - if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); - fs = get_fs(); set_fs(KERNEL_DS); - err = sys_unlink(file); - set_fs(fs); - kfree(file); - return(err); -} - -int evfs_symlink(struct inode *ino, struct dentry *dentry, const char *to) -{ - char *file; - int err; - mm_segment_t fs; - char salt[SALTLEN]; - char *buf = get_mem(); - char *buf2 = get_mem(); - - int len = strlen(to); - int alen = (len + PADLEN) & ~PADLEN; - - track(); - if (alen > PAGE_CACHE_SIZE) return -ENOMEM; - - if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); - fs = get_fs(); set_fs(KERNEL_DS); - - if (!buf) return -ENOMEM; - if (!buf2) { - put_mem(buf); - return -ENOMEM; - } - - memset(buf, 0, alen); - memcpy(buf, to, len); - - aes_encrypt_str(&gk(ino)->aes, buf, buf, alen, get_salt(NULL, 0, salt)); - buf2[base64_encode(buf, buf2, alen)] = 0; - - err = sys_symlink(buf2, file); - put_mem(buf); - put_mem(buf2); - set_fs(fs); - kfree(file); - return(err); -} - -int evfs_mkdir(struct inode *ino, struct dentry *dentry, int mode) -{ - char *file; - int err; - mm_segment_t fs; - - track(); - if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); - fs = get_fs(); set_fs(KERNEL_DS); - err = sys_mkdir(file, mode); - set_fs(fs); - kfree(file); - return(err); -} - -int evfs_rmdir(struct inode *ino, struct dentry *dentry) -{ - char *file; - int err; - mm_segment_t fs; - - if((file = inode_dentry_name(ino, dentry)) == NULL) return(-ENOMEM); - fs = get_fs(); set_fs(KERNEL_DS); - err = sys_rmdir(file); - set_fs(fs); - kfree(file); - return(err); -} - -int evfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev) -{ - struct inode *inode; - char *name; - int error; - mm_segment_t fs; - - track(); - inode = get_inode(dir->i_sb, dentry, &error); - if(error) return(error); - name = dentry_name(dentry, 0, dir->i_sb); - if(name == NULL){ - iput(inode); - return(-ENOMEM); - } - init_special_inode(inode, mode, dev); - fs = get_fs(); set_fs(KERNEL_DS); - error = sys_mknod(name, mode, dev); - set_fs(fs); - if(!error) error = read_name(inode, name); - kfree(name); - if(error){ - iput(inode); - return(error); - } - d_instantiate(dentry, inode); - return(0); -} - -int evfs_rename(struct inode *from_ino, struct dentry *from, - struct inode *to_ino, struct dentry *to) -{ - char *from_name, *to_name; - int err; - mm_segment_t fs; - - if((from_name = inode_dentry_name(from_ino, from)) == NULL) - return(-ENOMEM); - if((to_name = inode_dentry_name(to_ino, to)) == NULL){ - kfree(from_name); - return(-ENOMEM); - } - fs = get_fs(); set_fs(KERNEL_DS); - err = sys_rename(from_name, to_name); - set_fs(fs); - kfree(from_name); - kfree(to_name); - return(err); -} - -void evfs_truncate(struct inode *ino) -{ - return -EINVAL; -} - -int evfs_permission(struct inode *ino, int desired) -{ - int err; - char *name; - struct nameidata nd; - - track(); - name = inode_name(ino, 0); - if(name == NULL) return(-ENOMEM); - - err = hpath_lookup(name, &nd); - kfree(name); - if(!err) { - err = permission(nd.dentry->d_inode, desired); - path_release(&nd); - } - return(err); -} - -int evfs_setattr(struct dentry *dentry, struct iattr *attr) -{ - struct nameidata nd; - char *name; - int err; - - track(); - name = dentry_name(dentry, 0, NULL); - if(name == NULL) return(-ENOMEM); - err = hpath_lookup(name, &nd); - kfree(name); - if (!err) { - /* handle truncate */ - if (attr->ia_valid & ATTR_SIZE) { - attr->ia_size += PADLEN; - } - err = inode_setattr(nd.dentry->d_inode, attr); - path_release(&nd); - } - return(err); -} - -/************************************************************************** - File operations - **************************************************************************/ - - -int evfs_file_open(struct inode *ino, struct file *file) -{ - char *name; - struct file *fd; - - track(); - if(evfs_i(ino).fd) { - fput(evfs_i(ino).fd); - evfs_i(ino).fd = NULL; - } - name = dentry_name(file->f_dentry, 0, ino->i_sb); - if(name == NULL) - return(-ENOMEM); - - fd = filp_open(name, file->f_flags & ~(O_APPEND | O_EXCL | O_CREAT), file->f_mode); - kfree(name); - if (IS_ERR(fd)) return(PTR_ERR(fd)); - file_evfs_i(file)->fd = fd; - return(0); -} - -int evfs_fsync(struct file *file, struct dentry *dentry, int datasync) -{ - return(0); -} - -/************************************************************************** - Directory operations - **************************************************************************/ -int evfs_dir_release(struct inode *ino, struct file *file) -{ - track(); - return(0); -} - -struct my_ent { - void *old_filler; - void *old_ent; - struct super_block *sb; -}; - -static int my_filldir(struct my_ent *e, const char * name, int namlen, loff_t offset, - ino_t ino, unsigned int d_type) -{ - filldir_t old_filldir; - int len, nlen; - char buf[NAME_MAX + 1]; - char salt[SALTLEN]; - - old_filldir = e->old_filler; - /* hide magic */ - if ((namlen == sizeof(EVFS_COOKIE)-1) && (!memcmp(name, EVFS_COOKIE, namlen))) - return 0; - /* and do not ever try to decode '.' and '..' */ - if ((name[0] == '.') && ((namlen == 1) || (namlen == 2 && name[1] == '.'))) - return old_filldir(e->old_ent, name, namlen, offset, ino, d_type); - /* the rest will get decrypted */ - len = base2normlen(namlen); - /* unaligned sucks */ - if (len & PADLEN) - return 0; - - base64_decode(name, buf, namlen); - aes_decrypt_str(&evfs_key(e->sb)->aes, buf, buf, len, get_salt(NULL, 0, salt)); - nlen = strnlen(buf, len); - buf[nlen] = 0; - return old_filldir(e->old_ent, buf, nlen, offset, ino, d_type); -} - -int evfs_readdir(struct file *file, void *ent, filldir_t filldir) -{ - struct my_ent e; - track(); - e.old_filler = filldir; - e.old_ent = ent; - e.sb = file->f_dentry->d_inode->i_sb; - return vfs_readdir(file_evfs_i(file)->fd, (void *) my_filldir, (void *) &e); -} - -/************************************************************************** - Address space operations - **************************************************************************/ -int evfs_do_read(struct file *file, long long *start, char *buf, size_t count) -{ - int ret = -EBADF; - mm_segment_t fs = get_fs(); - set_fs(KERNEL_DS); - - ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode, - file, *start, count); - if (!ret) { - ssize_t (*read)(struct file *, char *, size_t, loff_t *); - ret = -EINVAL; - if (file->f_op && (read = file->f_op->read) != NULL) { - ret = read(file, buf, count, start); - } - } - if (ret > 0) - dnotify_parent(file->f_dentry, DN_ACCESS); - set_fs(fs); - return ret; -} - -int evfs_do_write(struct file *file, long long *start, char *buf, size_t count) -{ - int ret = -EBADF; - mm_segment_t fs = get_fs(); - struct inode *inode = file->f_dentry->d_inode; - set_fs(KERNEL_DS); - - track(); - ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, - *start, count); - if (!ret) { - ssize_t (*write)(struct file *, const char *, size_t, loff_t *); - ret = -EINVAL; - if (file->f_op && (write = file->f_op->write) != NULL) { - ret = write(file, buf, count, start); - } - } - if (ret > 0) - dnotify_parent(file->f_dentry, DN_MODIFY); - set_fs(fs); - return ret; -} - - -int evfs_writepage(struct page *page) -{ - struct address_space *mapping = page->mapping; - struct inode *inode = mapping->host; - char *buffer; - unsigned long long base; - int count = PAGE_CACHE_SIZE; - int end_index = inode->i_size >> PAGE_CACHE_SHIFT; - int err; - char *kbuf = get_mem(); - char buf[SALTLEN]; - - if (!kbuf) - return -ENOMEM; - - track(); - if (page->index >= end_index) - count = (inode->i_size & (PAGE_CACHE_SIZE-1)); - - buffer = kmap(page); - base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT; - - aes_encrypt_str(&gk(inode)->aes, kbuf, buffer, (count+PADLEN) & ~PADLEN, get_salt(gk(inode), page->index, buf)); - err = evfs_do_write(evfs_i(inode).fd, &base, kbuf, (count + PADLEN) & ~PADLEN); - if(err != count){ - ClearPageUptodate(page); - goto out; - } - - if (base > inode->i_size) { - inode->i_size = base; - } - - /* this is just for everyone else using that file, real fs will get - notified by regular do_truncate about real size when we'll fput this - file */ - evfs_i(inode).fd->f_dentry->d_inode->i_size = inode->i_size + PADLEN; - - if (PageError(page)) - ClearPageError(page); - err = 0; - - out: - kunmap(page); - - UnlockPage(page); - put_mem(kbuf); - return err; -} - - -int evfs_readpage(struct file *file, struct page *page) -{ - char *buffer; - long long start, tmp; - int err = 0; - struct inode *inode = file->f_dentry->d_inode; - struct file *f = file_evfs_i(file)->fd; - int end_index = inode->i_size >> PAGE_CACHE_SHIFT; - char buf[SALTLEN]; - - track(); - start = (long long) page->index << PAGE_CACHE_SHIFT; - buffer = kmap(page); - tmp = start; - err = evfs_do_read(f, &start, buffer, - PAGE_CACHE_SIZE); - if(err < 0) goto out; - - if (err & PADLEN) { - if (!(page->index >= end_index)) - printk("EVFS WARNING: access beyond end of padding of file!\n"); - } - /* yeah ! */ - aes_decrypt_str(&gk(inode)->aes, buffer, buffer, err & ~PADLEN, get_salt(gk(inode), page->index, buf)); - - /* do we've reached padding (i.e. virtual size) ? */ - if (start > inode->i_size) { - /* my dear, we did - round it up to virtual size */ - start = inode->i_size; - err = start - tmp; - if (err < 0) err = 0; - } - - flush_dcache_page(page); - SetPageUptodate(page); - if (PageError(page)) ClearPageError(page); - err = 0; - out: - kunmap(page); - UnlockPage(page); - return(err); -} - - -int evfs_prepare_write(struct file *file, struct page *page, - unsigned int from, unsigned int to) -{ - return 0; -} - -int evfs_commit_write(struct file *file, struct page *page, unsigned from, - unsigned to) -{ - struct address_space *mapping = page->mapping; - struct inode *inode = mapping->host; - char *buffer, *kbuf; - long long o, tmp, start; - int err = 0; - int end_index = inode->i_size >> PAGE_CACHE_SHIFT; - char buf[SALTLEN]; - - kbuf = get_mem(); - if (!kbuf) - return -ENOMEM; - - track(); - o = tmp = start = (long long) (page->index << PAGE_CACHE_SHIFT); - buffer = kmap(page); - - memset(kbuf, 0, PAGE_CACHE_SIZE); - - /* we've to get at least partly complete page to do some encryption */ - err = evfs_do_read(file_evfs_i(file)->fd, &tmp, kbuf, PAGE_CACHE_SIZE); - if (err < 0) goto out; - if (err & PADLEN) { - if (!(page->index >= end_index)) - printk("EVFS WARNING: access beyond end of padding of file!\n"); - } - /* oki, we've that bitch, now decrypt it :) */ - aes_decrypt_str(&gk(inode)->aes, kbuf, kbuf, (err + PADLEN) & ~PADLEN, get_salt(gk(inode), page->index, buf)); - /* overwrite it with new data */ - memcpy(kbuf + from, buffer + from, to - from); - if (to > err) err = to; - /* and encrypt whole thingie */ - aes_encrypt_str(&gk(inode)->aes, kbuf, kbuf, (err + PADLEN) & ~PADLEN, get_salt(gk(inode), page->index, buf)); - err = evfs_do_write(file_evfs_i(file)->fd, &start, kbuf, (err + PADLEN) & ~PADLEN); - if (err < to) - err = -EPIPE; - else { - o += to; - if (o > inode->i_size) - inode->i_size = o; - err = 0; - /* this is just for everyone else using that file, real fs will get - notified by regular do_truncate about real size when we'll fput this - file */ - evfs_i(inode).fd->f_dentry->d_inode->i_size = inode->i_size + PADLEN; - } -out: - kunmap(page); - put_mem(kbuf); - return(err); -} - -static __inline__ int -do_revalidate(struct dentry *dentry) -{ - struct inode * inode = dentry->d_inode; - if (inode->i_op && inode->i_op->revalidate) - return inode->i_op->revalidate(dentry); - return 0; -} - - -int evfs_link_readpage(struct file *file, struct page *page) -{ - struct inode *ino; - char *buffer; - long long start; - int err; - - track(); - start = page->index << PAGE_CACHE_SHIFT; - buffer = kmap(page); - ino = page->mapping->host; - track(); - - err = -EINVAL; - if (ino) { - if ((!evfs_i(ino).sym) || (!ino)) - err = -ENOENT; - else { - strncpy(buffer, evfs_i(ino).sym, PAGE_CACHE_SIZE-1); - buffer[PAGE_CACHE_SIZE-1] = 0; - err = strlen(buffer); - } - } - if(err > 0) { - flush_dcache_page(page); - SetPageUptodate(page); - if (PageError(page)) ClearPageError(page); - err = 0; - } - kunmap(page); - UnlockPage(page); - return(err); -} - - -int evfs_d_delete(struct dentry *dentry) -{ - return(1); -} - - -DECLARE_FSTYPE(evfs_type, "evfs", evfs_read_super, 0); - -static int __init init_evfs(void) -{ - gen_tabs(); - return register_filesystem(&evfs_type); -} - -static void __exit exit_evfs(void) -{ - unregister_filesystem(&evfs_type); -} - -static struct super_operations evfs_sbops = { - put_inode: force_delete, - put_super: evfs_putsuper, - delete_inode: evfs_delete_inode, - statfs: evfs_statfs -}; - -static struct inode_operations evfs_file_iops = { - create: evfs_create, - link: evfs_link, - unlink: evfs_unlink, - symlink: evfs_symlink, - mkdir: evfs_mkdir, - rmdir: evfs_rmdir, - mknod: evfs_mknod, - rename: evfs_rename, - truncate: evfs_truncate, - permission: evfs_permission, - setattr: evfs_setattr -}; - -static struct inode_operations evfs_dir_iops = { - create: evfs_create, - lookup: evfs_lookup, - link: evfs_link, - unlink: evfs_unlink, - symlink: evfs_symlink, - mkdir: evfs_mkdir, - rmdir: evfs_rmdir, - mknod: evfs_mknod, - rename: evfs_rename, - truncate: evfs_truncate, - permission: evfs_permission, - setattr: evfs_setattr -}; - -static struct file_operations evfs_fops = { - owner: NULL, - read: generic_file_read, - write: generic_file_write, - mmap: generic_file_mmap, - open: evfs_file_open, - release: NULL, - fsync: evfs_fsync, -}; - -static struct file_operations evfs_dir_fops = { - owner: NULL, - readdir: evfs_readdir, - open: evfs_file_open, - release: evfs_dir_release, - fsync: evfs_fsync, -}; - -static struct dentry_operations evfs_dentry_ops = { - d_delete: evfs_d_delete, -}; - -static struct address_space_operations evfs_aops = { - writepage: evfs_writepage, - readpage: evfs_readpage, - prepare_write: evfs_prepare_write, - commit_write: evfs_commit_write -}; - -static struct address_space_operations evfs_link_aops = { - readpage: evfs_link_readpage -}; - -EXPORT_NO_SYMBOLS; - -module_init(init_evfs); -module_exit(exit_evfs); -MODULE_LICENSE("GPL"); diff -Naurp linux-2.4.20-wolk4.1s/fs/Config.in linux-2.4.20-wolk4.2-fullkernel/fs/Config.in --- linux-2.4.20-wolk4.1s/fs/Config.in 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/Config.in 2003-06-05 23:30:57.000000000 +0200 @@ -176,6 +176,10 @@ else define_tristate CONFIG_ZISOFS_FS n fi +# Meta block cache for Extended Attributes (ext2/ext3) +#tristate 'Meta block cache' CONFIG_FS_MBCACHE +define_tristate CONFIG_FS_MBCACHE y + mainmenu_option next_comment comment 'Partition Types' source fs/partitions/Config.in diff -Naurp linux-2.4.20-wolk4.1s/fs/Makefile linux-2.4.20-wolk4.2-fullkernel/fs/Makefile --- linux-2.4.20-wolk4.1s/fs/Makefile 2003-05-15 21:52:38.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/Makefile 2003-06-05 23:30:57.000000000 +0200 @@ -94,6 +94,9 @@ obj-y += binfmt_script.o obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o +export-objs += mbcache.o +obj-$(CONFIG_FS_MBCACHE) += mbcache.o + # persistent filesystems obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o)) diff -Naurp linux-2.4.20-wolk4.1s/fs/block_dev.c linux-2.4.20-wolk4.2-fullkernel/fs/block_dev.c --- linux-2.4.20-wolk4.1s/fs/block_dev.c 2003-05-15 21:52:38.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/block_dev.c 2003-06-05 23:30:57.000000000 +0200 @@ -653,7 +653,7 @@ int blkdev_put(struct block_device *bdev down(&bdev->bd_sem); lock_kernel(); - if (kind == BDEV_FILE && bdev->bd_openers == 1) + if (kind == BDEV_FILE) __block_fsync(bd_inode); else if (kind == BDEV_FS) fsync_no_super(rdev); diff -Naurp linux-2.4.20-wolk4.1s/fs/buffer.c linux-2.4.20-wolk4.2-fullkernel/fs/buffer.c --- linux-2.4.20-wolk4.1s/fs/buffer.c 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/buffer.c 2003-06-03 09:40:33.000000000 +0200 @@ -142,6 +142,7 @@ void unlock_buffer(struct buffer_head *b { clear_bit(BH_Wait_IO, &bh->b_state); clear_bit(BH_Launder, &bh->b_state); + clear_bit(BH_Atomic, &bh->b_state); /* * When a locked buffer is visible to the I/O layer BH_Launder * is set. This means before unlocking we must clear BH_Launder, @@ -835,7 +836,6 @@ static void free_more_memory(void) balance_dirty(); wakeup_bdflush(); try_to_free_pages(GFP_NOIO); - run_task_queue(&tq_disk); yield(); } @@ -844,7 +844,7 @@ void init_buffer(struct buffer_head *bh, bh->b_list = BUF_CLEAN; bh->b_end_io = handler; bh->b_private = private; - bh->b_journal_head = NULL; + bh->b_journal_head = NULL; } void end_buffer_io_async(struct buffer_head * bh, int uptodate) @@ -2432,6 +2432,7 @@ int brw_kiovec(int rw, int nr, struct ki struct page * map; struct buffer_head *tmp, **bhs = NULL; int iosize = size; + unsigned int atomic_seq; if (!nr) return 0; @@ -2448,6 +2449,10 @@ int brw_kiovec(int rw, int nr, struct ki panic("brw_kiovec: iobuf not initialised"); } + atomic_seq = 0; + if (rw == WRITE) + atomic_seq = blk_get_atomic_seq(); + /* * OK to walk down the iovec doing page IO on each page we find. */ @@ -2504,7 +2509,8 @@ int brw_kiovec(int rw, int nr, struct ki init_buffer(tmp, end_buffer_io_kiobuf, iobuf); tmp->b_dev = dev; tmp->b_blocknr = blocknr; - tmp->b_state = (1 << BH_Mapped) | (1 << BH_Lock) | (1 << BH_Req); + tmp->b_state = (1 << BH_Mapped) | (1 << BH_Lock) | (1 << BH_Req) | (1 << BH_Atomic); + bh_elv_seq(tmp) = atomic_seq; if (rw == WRITE) { set_bit(BH_Uptodate, &tmp->b_state); @@ -2522,12 +2528,16 @@ int brw_kiovec(int rw, int nr, struct ki * Wait for IO if we have got too much */ if (bhind >= KIO_MAX_SECTORS) { + if (atomic_seq) + blk_refile_atomic_queue(atomic_seq); kiobuf_wait_for_io(iobuf); /* wake-one */ err = wait_kio(rw, bhind, bhs, size); if (err >= 0) transferred += err; else goto finished; + if (rw == WRITE) + atomic_seq = blk_get_atomic_seq(); bhind = 0; } @@ -2546,12 +2556,12 @@ int brw_kiovec(int rw, int nr, struct ki /* Is there any IO still left to submit? */ if (bhind) { + if (atomic_seq) + blk_refile_atomic_queue(atomic_seq); kiobuf_wait_for_io(iobuf); /* wake-one */ err = wait_kio(rw, bhind, bhs, size); if (err >= 0) transferred += err; - else - goto finished; } finished: @@ -2817,6 +2827,13 @@ static void sync_page_buffers(struct buf int try_to_free_buffers(struct page * page, unsigned int gfp_mask) { struct buffer_head * tmp, * bh = page->buffers; + int was_uptodate = 1; + + if (!PageLocked(page)) + BUG(); + + if (!bh) + return 1; spin_lock(&lru_list_lock); write_lock(&hash_table_lock); @@ -2838,7 +2855,8 @@ int try_to_free_buffers(struct page * pa tmp = tmp->b_this_page; if (p->b_dev == B_FREE) BUG(); - + if (!buffer_uptodate(p)) + was_uptodate = 0; remove_inode_queue(p); __remove_from_queues(p); __put_unused_buffer_head(p); @@ -2846,7 +2864,15 @@ int try_to_free_buffers(struct page * pa spin_unlock(&unused_list_lock); /* Wake up anyone waiting for buffer heads */ - wake_up(&buffer_wait); + smp_mb(); + if (waitqueue_active(&buffer_wait)) + wake_up(&buffer_wait); + + /* + * Make sure we don't read buffers again when they are reattached + */ + if (was_uptodate) + SetPageUptodate(page); /* And free the page */ page->buffers = NULL; @@ -3333,6 +3359,7 @@ int brw_kvec_async(int rw, kvec_cb_t cb, int length; unsigned sector_size = 1 << sector_shift; int i; + unsigned int atomic_seq; struct brw_cb *brw_cb; @@ -3373,6 +3400,10 @@ int brw_kvec_async(int rw, kvec_cb_t cb, brw_cb->cb = cb; brw_cb->nr = 0; + atomic_seq = 0; + if (rw == WRITE) + atomic_seq = blk_get_atomic_seq(); + /* This is ugly. FIXME. */ for (i=0, veclet=vec->veclet; inr; i++,veclet++) { struct page *page = veclet->page; @@ -3397,8 +3428,9 @@ int brw_kvec_async(int rw, kvec_cb_t cb, init_buffer(tmp, end_buffer_io_kiobuf_async, NULL); tmp->b_dev = dev; tmp->b_blocknr = blknr++; - tmp->b_state = (1 << BH_Mapped) | (1 << BH_Lock) - | (1 << BH_Req); + tmp->b_state = (1 << BH_Mapped) | (1 << BH_Lock) | + (1 << BH_Req) | (1 << BH_Atomic); + bh_elv_seq(tmp) = atomic_seq; tmp->b_private = brw_cb; if (rw == WRITE) { @@ -3426,6 +3458,8 @@ submit: for (i=0; inr; i++) submit_bh(rw, brw_cb->bh[i]); brw_cb_put(brw_cb); + if (atomic_seq) + blk_refile_atomic_queue(atomic_seq); return 0; diff -Naurp linux-2.4.20-wolk4.1s/fs/eventpoll.c linux-2.4.20-wolk4.2-fullkernel/fs/eventpoll.c --- linux-2.4.20-wolk4.1s/fs/eventpoll.c 2003-05-15 21:52:39.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/eventpoll.c 2003-06-02 23:24:54.000000000 +0200 @@ -153,6 +153,14 @@ struct eventpoll { /* Protect the this structure access */ rwlock_t lock; + /* + * This semaphore is used to ensure that files are not removed + * while epoll is using them. This is read-held during the event + * collection loop and it is write-held during the file cleanup + * path, the epoll file exit code and the ctl operations. + */ + struct rw_semaphore sem; + /* Wait queue used by sys_epoll_wait() */ wait_queue_head_t wq; @@ -279,16 +287,6 @@ static struct inode *ep_eventpoll_inode( /* Safe wake up implementation */ static struct poll_safewake psw; -/* - * This semaphore is used to ensure that files are not removed - * while epoll is using them. Namely the f_op->poll(), since - * it has to be called from outside the lock, must be protected. - * This is read-held during the event transfer loop to userspace - * and it is write-held during the file cleanup path and the epoll - * file exit code. - */ -static struct rw_semaphore epsem; - /* Slab cache used to allocate "struct epitem" */ static kmem_cache_t *epi_cache; @@ -356,15 +354,14 @@ static void ep_poll_safewake(struct poll list_for_each(lnk, lsthead) { tncur = list_entry(lnk, struct wake_task_node, llink); - if (tncur->task == this_task) { - if (tncur->wq == wq || ++wake_nests > EP_MAX_POLLWAKE_NESTS) { - /* - * Ops ... loop detected or maximum nest level reached. - * We abort this wake by breaking the cycle itself. - */ - spin_unlock_irqrestore(&psw->lock, flags); - return; - } + if (tncur->wq == wq || + (tncur->task == this_task && ++wake_nests > EP_MAX_POLLWAKE_NESTS)) { + /* + * Ops ... loop detected or maximum nest level reached. + * We abort this wake by breaking the cycle itself. + */ + spin_unlock_irqrestore(&psw->lock, flags); + return; } } @@ -436,14 +433,15 @@ void eventpoll_release(struct file *file * The only hit might come from ep_free() but by holding the semaphore * will correctly serialize the operation. */ - down_write(&epsem); + while (!list_empty(lsthead)) { epi = list_entry(lsthead->next, struct epitem, fllink); EP_LIST_DEL(&epi->fllink); + down_write(&epi->ep->sem); ep_remove(epi->ep, epi); + up_write(&epi->ep->sem); } - up_write(&epsem); } @@ -567,9 +565,18 @@ asmlinkage long sys_epoll_ctl(int epfd, error = -EEXIST; break; case EPOLL_CTL_DEL: - if (epi) + if (epi) { + /* + * We need to protect the remove operation because another + * thread might be doing an epoll_wait() and using the + * target file. + */ + down_write(&ep->sem); + error = ep_remove(ep, epi); - else + + up_write(&ep->sem); + } else error = -ENOENT; break; case EPOLL_CTL_MOD: @@ -702,10 +709,6 @@ static int ep_getfd(int *efd, struct ino file->f_vfsmnt = mntget(eventpoll_mnt); file->f_dentry = dget(dentry); - /* - * Initialize the file as read/write because it could be used - * with write() to add/remove/change interest sets. - */ file->f_pos = 0; file->f_flags = O_RDONLY; file->f_op = &eventpoll_fops; @@ -814,6 +817,7 @@ static int ep_init(struct eventpoll *ep, unsigned int i, hsize; rwlock_init(&ep->lock); + init_rwsem(&ep->sem); init_waitqueue_head(&ep->wq); init_waitqueue_head(&ep->poll_wait); INIT_LIST_HEAD(&ep->rdllist); @@ -840,11 +844,15 @@ static void ep_free(struct eventpoll *ep struct list_head *lsthead, *lnk; struct epitem *epi; + /* We need to release all tasks waiting for these file */ + if (waitqueue_active(&ep->poll_wait)) + ep_poll_safewake(&psw, &ep->poll_wait); + /* * We need to lock this because we could be hit by * eventpoll_release() while we're freeing the "struct eventpoll". */ - down_write(&epsem); + down_write(&ep->sem); /* * Walks through the whole hash by unregistering poll callbacks. @@ -862,7 +870,7 @@ static void ep_free(struct eventpoll *ep /* * Walks through the whole hash by freeing each "struct epitem". At this * point we are sure no poll callbacks will be lingering around, and also by - * write-holding "epsem" we can be sure that no file cleanup code will hit + * write-holding "sem" we can be sure that no file cleanup code will hit * us during this operation. So we can avoid the lock on "ep->lock". */ for (i = 0, hsize = 1 << ep->hashbits; i < hsize; i++) { @@ -875,7 +883,7 @@ static void ep_free(struct eventpoll *ep } } - up_write(&epsem); + up_write(&ep->sem); /* Free hash pages */ ep_free_pages(ep->hpages, EP_HASH_PAGES(ep->hashbits)); @@ -1337,20 +1345,6 @@ static int ep_collect_ready_items(struct /* If this file is already in the ready list we exit soon */ if (!EP_IS_LINKED(&epi->txlink)) { /* - * We need to increase the usage count of the "struct epitem" because - * another thread might call EPOLL_CTL_DEL on this target and make the - * object to vanish underneath our nose. - */ - ep_use_epitem(epi); - - /* - * We need to increase the usage count of the "struct file" because - * another thread might call close() on this target and make the file - * to vanish before we will be able to call f_op->poll(). - */ - get_file(epi->file); - - /* * This is initialized in this way so that the default * behaviour of the reinjecting code will be to push back * the item inside the ready list. @@ -1388,19 +1382,21 @@ static int ep_send_events(struct eventpo struct epitem *epi; struct epoll_event event[EP_MAX_BUF_EVENTS]; + /* + * We can loop without lock because this is a task private list. + * The test done during the collection loop will guarantee us that + * another task will not try to collect this file. Also, items + * cannot vanish during the loop because we are holding "sem". + */ list_for_each(lnk, txlist) { epi = list_entry(lnk, struct epitem, txlink); - /* Get the ready file event set */ - revents = epi->file->f_op->poll(epi->file, NULL); - /* - * Release the file usage before checking the event mask. - * In case this call will lead to the file removal, its - * ->event.events member has been already set to zero and - * this will make the event to be dropped. + * Get the ready file event set. We can safely use the file + * because we are holding the "sem" in read and this will + * guarantee that both the file and the item will not vanish. */ - fput(epi->file); + revents = epi->file->f_op->poll(epi->file, NULL); /* * Set the return event set for the current file descriptor. @@ -1415,17 +1411,8 @@ static int ep_send_events(struct eventpo eventbuf++; if (eventbuf == EP_MAX_BUF_EVENTS) { if (__copy_to_user(&events[eventcnt], event, - eventbuf * sizeof(struct epoll_event))) { - /* - * We need to complete the loop to decrement the file - * usage before returning from this function. - */ - for (lnk = lnk->next; lnk != txlist; lnk = lnk->next) { - epi = list_entry(lnk, struct epitem, txlink); - fput(epi->file); - } + eventbuf * sizeof(struct epoll_event))) return -EFAULT; - } eventcnt += eventbuf; eventbuf = 0; } @@ -1446,7 +1433,8 @@ static int ep_send_events(struct eventpo /* * Walk through the transfer list we collected with ep_collect_ready_items() * and, if 1) the item is still "alive" 2) its event set is not empty 3) it's - * not already linked, links it to the ready list. + * not already linked, links it to the ready list. Same as above, we are holding + * "sem" so items cannot vanish underneath our nose. */ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist) { @@ -1474,8 +1462,6 @@ static void ep_reinject_items(struct eve list_add_tail(&epi->rdllink, &ep->rdllist); ricnt++; } - - ep_release_epitem(epi); } if (ricnt) { @@ -1509,17 +1495,12 @@ static int ep_events_transfer(struct eve /* * We need to lock this because we could be hit by - * eventpoll_release() while we're transfering - * events to userspace. Read-holding "epsem" will lock - * out eventpoll_release() during the whole - * transfer loop and this will garantie us that the - * file will not vanish underneath our nose when - * we will call f_op->poll() from ep_send_events(). + * eventpoll_release() and epoll_ctl(EPOLL_CTL_DEL). */ - down_read(&epsem); + down_read(&ep->sem); /* Collect/extract ready items */ - if (ep_collect_ready_items(ep, &txlist, maxevents)) { + if (ep_collect_ready_items(ep, &txlist, maxevents) > 0) { /* Build result set in userspace */ eventcnt = ep_send_events(ep, &txlist, events); @@ -1527,7 +1508,7 @@ static int ep_events_transfer(struct eve ep_reinject_items(ep, &txlist); } - up_read(&epsem); + up_read(&ep->sem); return eventcnt; } @@ -1677,9 +1658,6 @@ static int __init eventpoll_init(void) { int error; - /* Initialize the semaphore used to syncronize the file cleanup code */ - init_rwsem(&epsem); - /* Initialize the structure used to perform safe poll wait head wake ups */ ep_poll_safewake_init(&psw); diff -Naurp linux-2.4.20-wolk4.1s/fs/evfs/evfs_core.c linux-2.4.20-wolk4.2-fullkernel/fs/evfs/evfs_core.c --- linux-2.4.20-wolk4.1s/fs/evfs/evfs_core.c 2003-05-15 21:52:39.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/evfs/evfs_core.c 2003-06-02 17:21:02.000000000 +0200 @@ -1,4 +1,4 @@ -/* evfs 0.2 2003 sd */ +/* evfs 0.3 2003 sd */ #include #include @@ -422,7 +422,7 @@ static struct super_block *evfs_read_sup /* check uid ... */ if (uid) - if ((nd.dentry->d_inode->i_uid != uid) || (!nd.dentry->d_inode->i_gid != gid)) { + if ((nd.dentry->d_inode->i_uid != uid) || (nd.dentry->d_inode->i_gid != gid)) { printk("evfs: *WARNING*, uid %d supplied someone's else directory as destination!\n", uid); goto out_nd; } diff -Naurp linux-2.4.20-wolk4.1s/fs/exec.c linux-2.4.20-wolk4.2-fullkernel/fs/exec.c --- linux-2.4.20-wolk4.1s/fs/exec.c 2003-05-15 21:52:39.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/exec.c 2003-06-02 17:19:00.000000000 +0200 @@ -1024,6 +1024,11 @@ int do_execve(char * filename, char ** a struct file *file; int retval; int i; +#ifdef CONFIG_GRKERNSEC + struct file *old_exec_file; + struct acl_subject_label *old_acl; + struct rlimit old_rlim[RLIM_NLIMITS]; +#endif /* RSBAC */ #ifdef CONFIG_RSBAC @@ -1038,15 +1043,6 @@ int do_execve(char * filename, char ** a if (IS_ERR(file)) return retval; -#ifdef CONFIG_GRKERNSEC - if (current->exec_file) { - fput(current->exec_file); - current->exec_file = NULL; - } - get_file(file); - current->exec_file = file; -#endif - gr_learn_resource(current, RLIMIT_NPROC, atomic_read(¤t->user->processes)); if (gr_handle_nproc()) { @@ -1138,8 +1134,6 @@ int do_execve(char * filename, char ** a bprm.exec = bprm.p; - gr_set_proc_label(file->f_dentry, file->f_vfsmnt); - gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); gr_handle_exec_args(&bprm, argv); @@ -1152,8 +1146,22 @@ int do_execve(char * filename, char ** a if (retval < 0) goto out; +#ifdef CONFIG_GRKERNSEC + old_acl = current->acl; + memcpy(old_rlim, current->rlim, sizeof(old_rlim)); + old_exec_file = current->exec_file; + get_file(file); + current->exec_file = file; +#endif + + gr_set_proc_label(file->f_dentry, file->f_vfsmnt); + retval = search_binary_handler(&bprm,regs); - if (retval >= 0) + if (retval >= 0) { +#ifdef CONFIG_GRKERNSEC + if (old_exec_file) + fput(old_exec_file); +#endif /* execve success */ { /* RSBAC: notify ADF of changed program in this process */ @@ -1180,20 +1188,20 @@ int do_execve(char * filename, char ** a return retval; } + } +#ifdef CONFIG_GRKERNSEC + current->acl = old_acl; + memcpy(current->rlim, old_rlim, sizeof(old_rlim)); + fput(current->exec_file); + current->exec_file = old_exec_file; +#endif out: /* Something went wrong, return the inode and free the argument pages*/ allow_write_access(bprm.file); if (bprm.file) fput(bprm.file); -#ifdef CONFIG_GRKERNSEC - if (current->exec_file) { - fput(current->exec_file); - current->exec_file = NULL; - } -#endif - for (i = 0 ; i < MAX_ARG_PAGES ; i++) { struct page * page = bprm.page[i]; if (page) diff -Naurp linux-2.4.20-wolk4.1s/fs/fcntl.c linux-2.4.20-wolk4.2-fullkernel/fs/fcntl.c --- linux-2.4.20-wolk4.1s/fs/fcntl.c 2003-05-15 21:52:39.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/fcntl.c 2003-06-02 14:40:59.000000000 +0200 @@ -59,11 +59,11 @@ static int expand_files(struct files_str */ static int locate_fd(struct files_struct *files, - struct file *file, int orig_start) + struct file *file, unsigned int orig_start) { unsigned int newfd; int error; - int start; + unsigned int start; write_lock(&files->file_lock); @@ -121,7 +121,7 @@ static inline void allocate_fd(struct fi fd_install(fd, file); } -static int dupfd(struct file *file, int start) +static int dupfd(struct file *file, unsigned int start) { struct files_struct * files = current->files; int ret; @@ -255,10 +255,8 @@ static long do_fcntl(unsigned int fd, un switch (cmd) { case F_DUPFD: - if (arg < current->rlim[RLIMIT_NOFILE].rlim_cur) { - get_file(filp); - err = dupfd(filp, arg); - } + get_file(filp); + err = dupfd(filp, arg); break; case F_GETFD: err = get_close_on_exec(fd); diff -Naurp linux-2.4.20-wolk4.1s/fs/inode.c linux-2.4.20-wolk4.2-fullkernel/fs/inode.c --- linux-2.4.20-wolk4.1s/fs/inode.c 2003-05-15 21:52:40.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/inode.c 2003-06-05 09:13:29.000000000 +0200 @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -381,7 +382,6 @@ static inline int try_to_sync_unused_lis struct list_head *tmp = head; struct inode *inode; - spin_lock(&inode_lock); while (nr_inodes && (tmp = tmp->prev) != head) { inode = list_entry(tmp, struct inode, i_list); @@ -402,7 +402,6 @@ static inline int try_to_sync_unused_lis } } } - spin_unlock(&inode_lock); return nr_inodes; } @@ -503,29 +502,21 @@ void sync_inodes(kdev_t dev) static void try_to_sync_unused_inodes(void) { struct super_block * sb; - int nr_inodes = inodes_stat.nr_unused; - int global_pass = 0, local_pass; + int nr_inodes; - restart: + spin_lock(&inode_lock); + nr_inodes = inodes_stat.nr_unused; spin_lock(&sb_lock); - local_pass = 0; sb = sb_entry(super_blocks.next); - while (nr_inodes && sb != sb_entry(&super_blocks)) { - if (local_pass < global_pass || list_empty(&sb->s_dirty)) { - sb = sb_entry(sb->s_list.next); - local_pass++; + for (; nr_inodes && sb != sb_entry(&super_blocks); sb = sb_entry(sb->s_list.next)) { + if (list_empty(&sb->s_dirty)) continue; - } - sb->s_count++; spin_unlock(&sb_lock); - down_read(&sb->s_umount); - if (sb->s_root) - nr_inodes = try_to_sync_unused_list(&sb->s_dirty, nr_inodes); - drop_super(sb); - global_pass = local_pass + 1; - goto restart; + nr_inodes = try_to_sync_unused_list(&sb->s_dirty, nr_inodes); + spin_lock(&sb_lock); } spin_unlock(&sb_lock); + spin_unlock(&inode_lock); } static DECLARE_WAIT_QUEUE_HEAD(kinoded_wait) ; @@ -661,7 +652,7 @@ static void dispose_list(struct list_hea truncate_inode_pages(&inode->i_data, 0); clear_inode(inode); destroy_inode(inode); - inodes_stat.nr_inodes--; + /* inodes_stat.nr_inodes maintained by caller */ } } @@ -696,6 +687,7 @@ static int invalidate_list(struct list_h busy = 1; } /* only unused inodes may be cached with i_count zero */ + inodes_stat.nr_inodes -= count; inodes_stat.nr_unused -= count; return busy; } @@ -781,7 +773,7 @@ static void _prune_icache(int goal) { LIST_HEAD(list); struct list_head *entry, *freeable = &list; - int count; + int count, avg_pages; struct inode * inode; spin_lock(&inode_lock); @@ -805,9 +797,10 @@ static void _prune_icache(int goal) list_add(tmp, freeable); inode->i_state |= I_FREEING; count++; - if (!--goal) + if (--goal <= 0) break; } + inodes_stat.nr_inodes -= count; inodes_stat.nr_unused -= count; spin_unlock(&inode_lock); @@ -815,25 +808,87 @@ static void _prune_icache(int goal) kmem_cache_shrink(inode_cachep); /* - * If we didn't freed enough clean inodes + * If we didn't freed enough clean inodes * start a sync now. */ - if (goal) + if (goal > 0) try_to_sync_unused_inodes(); + +#ifdef CONFIG_HIGHMEM + /* Excuse the double negative; the code below is emergency. */ + if (goal <= 0) + return; + if (freeable_lowmem() * PAGE_SIZE < 10 * inodes_stat.nr_unused * + sizeof(struct inode)) + return; + wakeup_bdflush(); + /* + * On highmem machines it is possible to have low memory + * filled with inodes that cannot be reclaimed because they + * have pagecache pages in highmem attached to them. In this + * special case we reclaim the pagecache pages together with + * the inodes, we only do this if we have lots of of inodes. + * We also restrict ourselves to reclaiming inodes that have + * not too much cache attached. + * + * Note that this code doesn't reclaim the inodes; if they become + * reclaimable they'll end up on the inode_unused list and they'll + * get reclaimed next time prune_icache() gets called. + */ + avg_pages = atomic_read(&page_cache_size) + 1; + avg_pages -= atomic_read(&buffermem_pages) + swapper_space.nrpages; + avg_pages = avg_pages / (inodes_stat.nr_inodes + 1); + spin_lock(&inode_lock); + while (goal-- > 0) { + if (list_empty(&inode_unused_pagecache)) + break; + entry = inode_unused_pagecache.prev; + list_del(entry); + list_add(entry, &inode_unused_pagecache); + + /* grab inode */ + inode = INODE(entry); + /* Don't nuke inodes that still have a lot of page cache */ + if (inode->i_mapping->nrpages > 2 * avg_pages) + continue; + if (inode->i_state & I_LOCK) + continue; + inode->i_state |= I_LOCK; + spin_unlock(&inode_lock); + + /* + * If the inode only has clean pages we can free all its + * pagecache memory; the inode will automagically be refiled + * into the unused_list. If the inode has dirty pages we'll + * skip it for now; bdflush (which we woke up above) will + * eventually make the inode freeable. + */ + if (list_empty(&inode->i_mapping->dirty_pages) && + !inode_has_buffers(inode)) + invalidate_inode_pages(inode); + + /* release inode */ + spin_lock(&inode_lock); + inode->i_state &= ~I_LOCK; + } + spin_unlock(&inode_lock); +#endif /* CONFIG_HIGHMEM */ } void prune_icache(int goal) { atomic_add(goal, &kinoded_goal); if (atomic_read(&kinoded_goal) > 16) { wake_up_interruptible(&kinoded_wait); - } + } } int shrink_icache_memory(int priority, int gfp_mask) { - int count = 0; + int count; + count = inodes_stat.nr_unused / priority; - prune_icache(count); + if (count > 0) + prune_icache(count); return 0; } @@ -1292,12 +1347,34 @@ void update_atime (struct inode *inode) { if (inode->i_atime == CURRENT_TIME) return; - if ( IS_NOATIME (inode) ) return; - if ( IS_NODIRATIME (inode) && S_ISDIR (inode->i_mode) ) return; - if ( IS_RDONLY (inode) ) return; + if (IS_NOATIME(inode)) + return; + if (IS_NODIRATIME(inode) && S_ISDIR(inode->i_mode)) + return; + if (IS_RDONLY(inode)) + return; inode->i_atime = CURRENT_TIME; mark_inode_dirty_sync (inode); -} /* End Function update_atime */ +} + +/** + * update_mctime - update the mtime and ctime + * @inode: inode accessed + * + * Update the modified and changed times on an inode for writes to special + * files such as fifos. No change is forced if the timestamps are already + * up-to-date or if the filesystem is readonly. + */ + +void update_mctime (struct inode *inode) +{ + if (inode->i_mtime == CURRENT_TIME && inode->i_ctime == CURRENT_TIME) + return; + if (IS_RDONLY(inode)) + return; + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + mark_inode_dirty (inode); +} /* diff -Naurp linux-2.4.20-wolk4.1s/fs/ioctl.c linux-2.4.20-wolk4.2-fullkernel/fs/ioctl.c --- linux-2.4.20-wolk4.1s/fs/ioctl.c 2003-05-15 21:52:40.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/ioctl.c 2003-06-02 17:21:08.000000000 +0200 @@ -39,6 +39,13 @@ static int file_ioctl(struct file *filp, return put_user(inode->i_sb->s_blocksize, (int *) arg); case FIONREAD: return put_user(i_size_read(inode) - filp->f_pos, (int *) arg); + + case FIOFLUSH: + write_inode_now(inode, 1); + invalidate_inode_buffers(inode); + invalidate_inode_pages(inode); + return 0; + } if (filp->f_op && filp->f_op->ioctl) return filp->f_op->ioctl(inode, filp, cmd, arg); diff -Naurp linux-2.4.20-wolk4.1s/fs/jbd/commit.c linux-2.4.20-wolk4.2-fullkernel/fs/jbd/commit.c --- linux-2.4.20-wolk4.1s/fs/jbd/commit.c 2003-05-15 21:52:40.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/jbd/commit.c 2003-06-01 18:13:40.000000000 +0200 @@ -334,6 +334,11 @@ sync_datalist_empty: */ while ((jh = commit_transaction->t_async_datalist)) { struct buffer_head *bh = jh2bh(jh); + if (__buffer_state(bh, Freed)) { + BUFFER_TRACE(bh, "Cleaning freed buffer"); + clear_bit(BH_Freed, &bh->b_state); + clear_bit(BH_Dirty, &bh->b_state); + } if (buffer_locked(bh)) { spin_unlock(&journal_datalist_lock); unlock_journal(journal); diff -Naurp linux-2.4.20-wolk4.1s/fs/jbd/journal.c linux-2.4.20-wolk4.2-fullkernel/fs/jbd/journal.c --- linux-2.4.20-wolk4.1s/fs/jbd/journal.c 2003-05-15 21:52:40.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/jbd/journal.c 2003-06-01 18:14:35.000000000 +0200 @@ -1803,9 +1803,9 @@ struct journal_head *journal_add_journal if (buffer_jbd(bh)) { /* Someone did it for us! */ - J_ASSERT_BH(bh, bh->b_journal_head != NULL); + J_ASSERT_BH(bh, bh->b_journal_head != NULL); journal_free_journal_head(jh); - jh = bh->b_journal_head; + jh = bh->b_journal_head; } else { /* * We actually don't need jh_splice_lock when @@ -1813,7 +1813,7 @@ struct journal_head *journal_add_journal */ spin_lock(&jh_splice_lock); set_bit(BH_JBD, &bh->b_state); - bh->b_journal_head = jh; + bh->b_journal_head = jh; jh->b_bh = bh; atomic_inc(&bh->b_count); spin_unlock(&jh_splice_lock); @@ -1822,7 +1822,7 @@ struct journal_head *journal_add_journal } jh->b_jcount++; spin_unlock(&journal_datalist_lock); - return bh->b_journal_head; + return bh->b_journal_head; } /* diff -Naurp linux-2.4.20-wolk4.1s/fs/jfs/jfs_logmgr.c linux-2.4.20-wolk4.2-fullkernel/fs/jfs/jfs_logmgr.c --- linux-2.4.20-wolk4.1s/fs/jfs/jfs_logmgr.c 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/jfs/jfs_logmgr.c 2003-06-01 18:14:26.000000000 +0200 @@ -1834,6 +1834,7 @@ static inline void lbmRedrive(struct lbu static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp) { struct lbuf *bp; + unsigned long flags; /* * allocate a log buffer @@ -1841,6 +1842,8 @@ static int lbmRead(struct jfs_log * log, *bpp = bp = lbmAllocate(log, pn); jfs_info("lbmRead: bp:0x%p pn:0x%x", bp, pn); + LCACHE_LOCK(flags); /* disable+lock */ + bp->l_flag |= lbmREAD; bp->l_bh.b_reqnext = NULL; clear_bit(BH_Uptodate, &bp->l_bh.b_state); @@ -1849,10 +1852,13 @@ static int lbmRead(struct jfs_log * log, set_bit(BH_Req, &bp->l_bh.b_state); bp->l_bh.b_rdev = bp->l_bh.b_dev; bp->l_bh.b_rsector = bp->l_blkno << (log->l2bsize - 9); + bh_elv_seq(&bp->l_bh) = 0; generic_make_request(READ, &bp->l_bh); run_task_queue(&tq_disk); - wait_event(bp->l_ioevent, (bp->l_flag != lbmREAD)); + LCACHE_SLEEP_COND(bp->l_ioevent, (bp->l_flag != lbmREAD), flags); + + LCACHE_UNLOCK(flags); /* unlock+enable */ return 0; } @@ -1985,6 +1991,7 @@ static void lbmStartIO(struct lbuf * bp) set_bit(BH_Req, &bp->l_bh.b_state); bp->l_bh.b_rdev = bp->l_bh.b_dev; bp->l_bh.b_rsector = bp->l_blkno << (bp->l_log->l2bsize - 9); + bh_elv_seq(&bp->l_bh) = 0; generic_make_request(WRITE, &bp->l_bh); INCREMENT(lmStat.submitted); diff -Naurp linux-2.4.20-wolk4.1s/fs/mbcache.c linux-2.4.20-wolk4.2-fullkernel/fs/mbcache.c --- linux-2.4.20-wolk4.1s/fs/mbcache.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/fs/mbcache.c 2003-06-02 17:23:46.000000000 +0200 @@ -0,0 +1,715 @@ +/* + * linux/fs/mbcache.c + * (C) 2001-2002 Andreas Gruenbacher, + */ + +/* + * Filesystem Meta Information Block Cache (mbcache) + * + * The mbcache caches blocks of block devices that need to be located + * by their device/block number, as well as by other criteria (such + * as the block's contents). + * + * There can only be one cache entry in a cache per device and block number. + * Additional indexes need not be unique in this sense. The number of + * additional indexes (=other criteria) can be hardwired (at compile time) + * or specified at cache create time. + * + * Each cache entry is of fixed size. An entry may be `valid' or `invalid' + * in the cache. A valid entry is in the main hash tables of the cache, + * and may also be in the lru list. An invalid entry is not in any hashes + * or lists. + * + * A valid cache entry is only in the lru list if no handles refer to it. + * Invalid cache entries will be freed when the last handle to the cache + * entry is released. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#ifdef MB_CACHE_DEBUG +# define mb_debug(f...) do { \ + printk(KERN_DEBUG f); \ + printk("\n"); \ + } while (0) +#define mb_assert(c) do { if (!(c)) \ + printk(KERN_ERR "assertion " #c " failed\n"); \ + } while(0) +#else +# define mb_debug(f...) do { } while(0) +# define mb_assert(c) do { } while(0) +#endif +#define mb_error(f...) do { \ + printk(KERN_ERR f); \ + printk("\n"); \ + } while(0) + +MODULE_AUTHOR("Andreas Gruenbacher "); +MODULE_DESCRIPTION("Meta block cache (for extended attributes)"); + +MODULE_LICENSE("GPL"); + + +EXPORT_SYMBOL_GPL(mb_cache_create); +EXPORT_SYMBOL_GPL(mb_cache_shrink); +EXPORT_SYMBOL_GPL(mb_cache_destroy); +EXPORT_SYMBOL_GPL(mb_cache_entry_alloc); +EXPORT_SYMBOL_GPL(mb_cache_entry_insert); +EXPORT_SYMBOL_GPL(mb_cache_entry_release); +EXPORT_SYMBOL_GPL(mb_cache_entry_takeout); +EXPORT_SYMBOL_GPL(mb_cache_entry_free); +EXPORT_SYMBOL_GPL(mb_cache_entry_dup); +EXPORT_SYMBOL_GPL(mb_cache_entry_get); +#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) +EXPORT_SYMBOL_GPL(mb_cache_entry_find_first); +EXPORT_SYMBOL_GPL(mb_cache_entry_find_next); +#endif + + +/* + * Global data: list of all mbcache's, lru list, and a spinlock for + * accessing cache data structures on SMP machines. (The lru list is + * global across all mbcaches.) + */ + +static LIST_HEAD(mb_cache_list); +static LIST_HEAD(mb_cache_lru_list); +static spinlock_t mb_cache_spinlock = SPIN_LOCK_UNLOCKED; + +static inline void +mb_cache_lock(void) +{ + spin_lock(&mb_cache_spinlock); +} + +static inline void +mb_cache_unlock(void) +{ + spin_unlock(&mb_cache_spinlock); +} + +static inline int +mb_cache_indexes(struct mb_cache *cache) +{ +#ifdef MB_CACHE_INDEXES_COUNT + return MB_CACHE_INDEXES_COUNT; +#else + return cache->c_indexes_count; +#endif +} + +/* + * What the mbcache registers as to get shrunk dynamically. + */ + +static void +mb_cache_memory_pressure(int priority, unsigned int gfp_mask); + +static struct cache_definition mb_cache_definition = { + "mb_cache", + mb_cache_memory_pressure +}; + + +static inline void +__mb_cache_entry_takeout_lru(struct mb_cache_entry *ce) +{ + if (ce->e_lru_list.prev) { + list_del(&ce->e_lru_list); + ce->e_lru_list.prev = NULL; + } +} + + +static inline void +__mb_cache_entry_into_lru(struct mb_cache_entry *ce) +{ + list_add(&ce->e_lru_list, &mb_cache_lru_list); +} + + +static inline int +__mb_cache_entry_in_lru(struct mb_cache_entry *ce) +{ + return (ce->e_lru_list.prev != NULL); +} + + +/* + * Insert the cache entry into all hashes. + */ +static inline void +__mb_cache_entry_link(struct mb_cache_entry *ce) +{ + struct mb_cache *cache = ce->e_cache; + unsigned int bucket = (HASHDEV(ce->e_dev) + ce->e_block) % + cache->c_bucket_count; + int n; + + list_add(&ce->e_block_list, &cache->c_block_hash[bucket]); + for (n=0; ne_indexes[n].o_key % cache->c_bucket_count; + list_add(&ce->e_indexes[n].o_list, + &cache->c_indexes_hash[n][bucket]); + } +} + + +/* + * Remove the cache entry from all hashes. + */ +static inline void +__mb_cache_entry_unlink(struct mb_cache_entry *ce) +{ + int n; + + list_del(&ce->e_block_list); + ce->e_block_list.prev = NULL; + for (n=0; ne_cache); n++) + list_del(&ce->e_indexes[n].o_list); +} + + +static inline int +__mb_cache_entry_is_linked(struct mb_cache_entry *ce) +{ + return (ce->e_block_list.prev != NULL); +} + + +static inline struct mb_cache_entry * +__mb_cache_entry_read(struct mb_cache_entry *ce) +{ + __mb_cache_entry_takeout_lru(ce); + atomic_inc(&ce->e_used); + return ce; +} + + +static inline void +__mb_cache_entry_forget(struct mb_cache_entry *ce) +{ + struct mb_cache *cache = ce->e_cache; + + mb_assert(atomic_read(&ce->e_used) == 0); + atomic_dec(&cache->c_entry_count); + if (cache->c_op.free) + cache->c_op.free(ce); + kmem_cache_free(cache->c_entry_cache, ce); +} + + +static inline void +__mb_cache_entry_release_unlock(struct mb_cache_entry *ce) +{ + if (atomic_dec_and_test(&ce->e_used)) { + if (__mb_cache_entry_is_linked(ce)) + __mb_cache_entry_into_lru(ce); + else { + mb_cache_unlock(); + __mb_cache_entry_forget(ce); + return; + } + } + mb_cache_unlock(); +} + + +/* + * mb_cache_memory_pressure() memory pressure callback + * + * This function is called by the kernel memory management when memory + * gets low. + * + * @priority: Amount by which to shrink the cache (0 = highes priority) + * @gfp_mask: (ignored) + */ +static void +mb_cache_memory_pressure(int priority, unsigned int gfp_mask) +{ + LIST_HEAD(free_list); + struct list_head *l; + int count = 0; + + mb_cache_lock(); + list_for_each_prev(l, &mb_cache_list) { + struct mb_cache *cache = + list_entry(l, struct mb_cache, c_cache_list); + mb_debug("cache %s (%d)", cache->c_name, + atomic_read(&cache->c_entry_count)); + count += atomic_read(&cache->c_entry_count); + } + mb_debug("trying to free %d of %d entries", + count / (priority ? priority : 1), count); + if (priority) + count /= priority; + while (count && !list_empty(&mb_cache_lru_list)) { + struct mb_cache_entry *ce = + list_entry(mb_cache_lru_list.prev, + struct mb_cache_entry, e_lru_list); + list_del(&ce->e_lru_list); + list_add(&ce->e_lru_list, &free_list); + if (__mb_cache_entry_is_linked(ce)) + __mb_cache_entry_unlink(ce); + count--; + } + mb_cache_unlock(); + l = free_list.prev; + while (l != &free_list) { + struct mb_cache_entry *ce = list_entry(l, + struct mb_cache_entry, e_lru_list); + l = l->prev; + __mb_cache_entry_forget(ce); + } + if (count) + mb_debug("%d fewer entries freed", count); +} + + +/* + * mb_cache_create() create a new cache + * + * All entries in one cache are equal size. Cache entries may be from + * multiple devices. If this is the first mbcache created, registers + * the cache with kernel memory management. Returns NULL if no more + * memory was available. + * + * @name: name of the cache (informal) + * @cache_op: contains the callback called when freeing a cache entry + * @entry_size: The size of a cache entry, including + * struct mb_cache_entry + * @indexes_count: number of additional indexes in the cache. Must equal + * MB_CACHE_INDEXES_COUNT if the number of indexes is + * hardwired. + * @bucket_count: number of hash buckets + */ +struct mb_cache * +mb_cache_create(const char *name, struct mb_cache_op *cache_op, + size_t entry_size, int indexes_count, int bucket_count) +{ + int m=0, n; + struct mb_cache *cache = NULL; + + if(entry_size < sizeof(struct mb_cache_entry) + + indexes_count * sizeof(struct mb_cache_entry_index)) + return NULL; + + MOD_INC_USE_COUNT; + cache = kmalloc(sizeof(struct mb_cache) + + indexes_count * sizeof(struct list_head), GFP_KERNEL); + if (!cache) + goto fail; + cache->c_name = name; + if (cache_op) + cache->c_op.free = cache_op->free; + else + cache->c_op.free = NULL; + atomic_set(&cache->c_entry_count, 0); + cache->c_bucket_count = bucket_count; +#ifdef MB_CACHE_INDEXES_COUNT + mb_assert(indexes_count == MB_CACHE_INDEXES_COUNT); +#else + cache->c_indexes_count = indexes_count; +#endif + cache->c_block_hash = kmalloc(bucket_count * sizeof(struct list_head), + GFP_KERNEL); + if (!cache->c_block_hash) + goto fail; + for (n=0; nc_block_hash[n]); + for (m=0; mc_indexes_hash[m] = kmalloc(bucket_count * + sizeof(struct list_head), + GFP_KERNEL); + if (!cache->c_indexes_hash[m]) + goto fail; + for (n=0; nc_indexes_hash[m][n]); + } + cache->c_entry_cache = kmem_cache_create(name, entry_size, 0, + 0 /*SLAB_POISON | SLAB_RED_ZONE*/, NULL, NULL); + if (!cache->c_entry_cache) + goto fail; + + mb_cache_lock(); + if (list_empty(&mb_cache_list)) + register_cache(&mb_cache_definition); + list_add(&cache->c_cache_list, &mb_cache_list); + mb_cache_unlock(); + return cache; + +fail: + if (cache) { + while (--m >= 0) + kfree(cache->c_indexes_hash[m]); + if (cache->c_block_hash) + kfree(cache->c_block_hash); + kfree(cache); + } + MOD_DEC_USE_COUNT; + return NULL; +} + + +/* + * mb_cache_shrink() + * + * Removes all cache entires of a device from the cache. All cache entries + * currently in use cannot be freed, and thus remain in the cache. All others + * are freed. + * + * @cache: which cache to shrink + * @dev: which device's cache entries to shrink + */ +void +mb_cache_shrink(struct mb_cache *cache, kdev_t dev) +{ + LIST_HEAD(free_list); + struct list_head *l; + + mb_cache_lock(); + l = mb_cache_lru_list.prev; + while (l != &mb_cache_lru_list) { + struct mb_cache_entry *ce = + list_entry(l, struct mb_cache_entry, e_lru_list); + l = l->prev; + if (ce->e_dev == dev) { + list_del(&ce->e_lru_list); + list_add(&ce->e_lru_list, &free_list); + if (__mb_cache_entry_is_linked(ce)) + __mb_cache_entry_unlink(ce); + } + } + mb_cache_unlock(); + l = free_list.prev; + while (l != &free_list) { + struct mb_cache_entry *ce = + list_entry(l, struct mb_cache_entry, e_lru_list); + l = l->prev; + __mb_cache_entry_forget(ce); + } +} + + +/* + * mb_cache_destroy() + * + * Shrinks the cache to its minimum possible size (hopefully 0 entries), + * and then destroys it. If this was the last mbcache, un-registers the + * mbcache from kernel memory management. + */ +void +mb_cache_destroy(struct mb_cache *cache) +{ + LIST_HEAD(free_list); + struct list_head *l; + int n; + + mb_cache_lock(); + l = mb_cache_lru_list.prev; + while (l != &mb_cache_lru_list) { + struct mb_cache_entry *ce = + list_entry(l, struct mb_cache_entry, e_lru_list); + l = l->prev; + if (ce->e_cache == cache) { + list_del(&ce->e_lru_list); + list_add(&ce->e_lru_list, &free_list); + if (__mb_cache_entry_is_linked(ce)) + __mb_cache_entry_unlink(ce); + } + } + list_del(&cache->c_cache_list); + if (list_empty(&mb_cache_list)) + unregister_cache(&mb_cache_definition); + mb_cache_unlock(); + + l = free_list.prev; + while (l != &free_list) { + struct mb_cache_entry *ce = + list_entry(l, struct mb_cache_entry, e_lru_list); + l = l->prev; + __mb_cache_entry_forget(ce); + } + + if (atomic_read(&cache->c_entry_count) > 0) { + mb_error("cache %s: %d orphaned entries", + cache->c_name, + atomic_read(&cache->c_entry_count)); + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + /* We don't have kmem_cache_destroy() in 2.2.x */ + kmem_cache_shrink(cache->c_entry_cache); +#else + kmem_cache_destroy(cache->c_entry_cache); +#endif + for (n=0; n < mb_cache_indexes(cache); n++) + kfree(cache->c_indexes_hash[n]); + kfree(cache->c_block_hash); + + kfree(cache); + + MOD_DEC_USE_COUNT; +} + + +/* + * mb_cache_entry_alloc() + * + * Allocates a new cache entry. The new entry will not be valid initially, + * and thus cannot be looked up yet. It should be filled with data, and + * then inserted into the cache using mb_cache_entry_insert(). Returns NULL + * if no more memory was available. + */ +struct mb_cache_entry * +mb_cache_entry_alloc(struct mb_cache *cache) +{ + struct mb_cache_entry *ce; + + atomic_inc(&cache->c_entry_count); + ce = kmem_cache_alloc(cache->c_entry_cache, GFP_KERNEL); + if (ce) { + ce->e_lru_list.prev = NULL; + ce->e_block_list.prev = NULL; + ce->e_cache = cache; + atomic_set(&ce->e_used, 1); + } + return ce; +} + + +/* + * mb_cache_entry_insert() + * + * Inserts an entry that was allocated using mb_cache_entry_alloc() into + * the cache. After this, the cache entry can be looked up, but is not yet + * in the lru list as the caller still holds a handle to it. Returns 0 on + * success, or -EBUSY if a cache entry for that device + inode exists + * already (this may happen after a failed lookup, but when another process + * has inserted the same cache entry in the meantime). + * + * @dev: device the cache entry belongs to + * @block: block number + * @keys: array of additional keys. There must be indexes_count entries + * in the array (as specified when creating the cache). + */ +int +mb_cache_entry_insert(struct mb_cache_entry *ce, kdev_t dev, + unsigned long block, unsigned int keys[]) +{ + struct mb_cache *cache = ce->e_cache; + unsigned int bucket = (HASHDEV(dev) + block) % cache->c_bucket_count; + struct list_head *l; + int error = -EBUSY, n; + + mb_cache_lock(); + list_for_each_prev(l, &cache->c_block_hash[bucket]) { + struct mb_cache_entry *ce = + list_entry(l, struct mb_cache_entry, e_block_list); + if (ce->e_dev == dev && ce->e_block == block) + goto out; + } + mb_assert(!__mb_cache_entry_is_linked(ce)); + ce->e_dev = dev; + ce->e_block = block; + for (n=0; ne_indexes[n].o_key = keys[n]; + __mb_cache_entry_link(ce); +out: + mb_cache_unlock(); + return error; +} + + +/* + * mb_cache_entry_release() + * + * Release a handle to a cache entry. When the last handle to a cache entry + * is released it is either freed (if it is invalid) or otherwise inserted + * in to the lru list. + */ +void +mb_cache_entry_release(struct mb_cache_entry *ce) +{ + mb_cache_lock(); + __mb_cache_entry_release_unlock(ce); +} + + +/* + * mb_cache_entry_takeout() + * + * Take a cache entry out of the cache, making it invalid. The entry can later + * be re-inserted using mb_cache_entry_insert(), or released using + * mb_cache_entry_release(). + */ +void +mb_cache_entry_takeout(struct mb_cache_entry *ce) +{ + mb_cache_lock(); + mb_assert(!__mb_cache_entry_in_lru(ce)); + if (__mb_cache_entry_is_linked(ce)) + __mb_cache_entry_unlink(ce); + mb_cache_unlock(); +} + + +/* + * mb_cache_entry_free() + * + * This is equivalent to the sequence mb_cache_entry_takeout() -- + * mb_cache_entry_release(). + */ +void +mb_cache_entry_free(struct mb_cache_entry *ce) +{ + mb_cache_lock(); + mb_assert(!__mb_cache_entry_in_lru(ce)); + if (__mb_cache_entry_is_linked(ce)) + __mb_cache_entry_unlink(ce); + __mb_cache_entry_release_unlock(ce); +} + + +/* + * mb_cache_entry_dup() + * + * Duplicate a handle to a cache entry (does not duplicate the cache entry + * itself). After the call, both the old and the new handle must be released. + */ +struct mb_cache_entry * +mb_cache_entry_dup(struct mb_cache_entry *ce) +{ + atomic_inc(&ce->e_used); + return ce; +} + + +/* + * mb_cache_entry_get() + * + * Get a cache entry by device / block number. (There can only be one entry + * in the cache per device and block.) Returns NULL if no such cache entry + * exists. + */ +struct mb_cache_entry * +mb_cache_entry_get(struct mb_cache *cache, kdev_t dev, unsigned long block) +{ + unsigned int bucket = (HASHDEV(dev) + block) % cache->c_bucket_count; + struct list_head *l; + struct mb_cache_entry *ce; + + mb_cache_lock(); + list_for_each(l, &cache->c_block_hash[bucket]) { + ce = list_entry(l, struct mb_cache_entry, e_block_list); + if (ce->e_dev == dev && ce->e_block == block) { + ce = __mb_cache_entry_read(ce); + goto cleanup; + } + } + ce = NULL; + +cleanup: + mb_cache_unlock(); + return ce; +} + +#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) + +static struct mb_cache_entry * +__mb_cache_entry_find(struct list_head *l, struct list_head *head, + int index, kdev_t dev, unsigned int key) +{ + while (l != head) { + struct mb_cache_entry *ce = + list_entry(l, struct mb_cache_entry, + e_indexes[index].o_list); + if (ce->e_dev == dev && ce->e_indexes[index].o_key == key) { + ce = __mb_cache_entry_read(ce); + if (ce) + return ce; + } + l = l->next; + } + return NULL; +} + + +/* + * mb_cache_entry_find_first() + * + * Find the first cache entry on a given device with a certain key in + * an additional index. Additonal matches can be found with + * mb_cache_entry_find_next(). Returns NULL if no match was found. + * + * @cache: the cache to search + * @index: the number of the additonal index to search (0<=indexc_bucket_count; + struct list_head *l; + struct mb_cache_entry *ce; + + mb_assert(index < mb_cache_indexes(cache)); + mb_cache_lock(); + l = cache->c_indexes_hash[index][bucket].next; + ce = __mb_cache_entry_find(l, &cache->c_indexes_hash[index][bucket], + index, dev, key); + mb_cache_unlock(); + return ce; +} + + +/* + * mb_cache_entry_find_next() + * + * Find the next cache entry on a given device with a certain key in an + * additional index. Returns NULL if no match could be found. The previous + * entry is atomatically released, so that mb_cache_entry_find_next() can + * be called like this: + * + * entry = mb_cache_entry_find_first(); + * while (entry) { + * ... + * entry = mb_cache_entry_find_next(entry, ...); + * } + * + * @prev: The previous match + * @index: the number of the additonal index to search (0<=indexe_cache; + unsigned int bucket = key % cache->c_bucket_count; + struct list_head *l; + struct mb_cache_entry *ce; + + mb_assert(index < mb_cache_indexes(cache)); + mb_cache_lock(); + l = prev->e_indexes[index].o_list.next; + ce = __mb_cache_entry_find(l, &cache->c_indexes_hash[index][bucket], + index, dev, key); + __mb_cache_entry_release_unlock(prev); + return ce; +} + +#endif /* !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) */ diff -Naurp linux-2.4.20-wolk4.1s/fs/pipe.c linux-2.4.20-wolk4.2-fullkernel/fs/pipe.c --- linux-2.4.20-wolk4.1s/fs/pipe.c 2003-05-15 21:52:42.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/pipe.c 2003-06-02 17:23:47.000000000 +0200 @@ -236,8 +236,7 @@ pipe_write(struct file *filp, const char /* Signal readers asynchronously that there is more data. */ wake_up_interruptible(PIPE_WAIT(*inode)); - inode->i_ctime = inode->i_mtime = CURRENT_TIME; - mark_inode_dirty(inode); + update_mctime(inode); out: up(PIPE_SEM(*inode)); diff -Naurp linux-2.4.20-wolk4.1s/fs/proc/array.c linux-2.4.20-wolk4.2-fullkernel/fs/proc/array.c --- linux-2.4.20-wolk4.1s/fs/proc/array.c 2003-05-15 21:52:42.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/proc/array.c 2003-06-02 17:31:54.000000000 +0200 @@ -474,6 +474,10 @@ int proc_pid_stat(struct task_struct *ta wchan = 0; } #endif +#ifdef CONFIG_GRKERNSEC_HIDESYM + eip = 0; + esp = 0; +#endif collect_sigign_sigcatch(task, &sigign, &sigcatch); diff -Naurp linux-2.4.20-wolk4.1s/fs/proc/generic.c linux-2.4.20-wolk4.2-fullkernel/fs/proc/generic.c --- linux-2.4.20-wolk4.1s/fs/proc/generic.c 2003-05-15 21:52:42.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/proc/generic.c 2003-06-02 17:23:44.000000000 +0200 @@ -157,13 +157,14 @@ proc_file_lseek(struct file * file, loff offset += file->f_pos; } retval = -EINVAL; - if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) { + if (offset>=0 && (unsigned long long)offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) { if (offset != file->f_pos) { file->f_pos = offset; file->f_reada = 0; } retval = offset; } + /* RED-PEN user can fake an error here by setting offset to >=-4095 && <0 */ return retval; } diff -Naurp linux-2.4.20-wolk4.1s/fs/proc/inode.c linux-2.4.20-wolk4.2-fullkernel/fs/proc/inode.c --- linux-2.4.20-wolk4.1s/fs/proc/inode.c 2003-05-15 21:52:42.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/proc/inode.c 2003-06-02 17:23:44.000000000 +0200 @@ -190,6 +190,7 @@ struct super_block *proc_read_super(stru s->s_blocksize_bits = 10; s->s_magic = PROC_SUPER_MAGIC; s->s_op = &proc_sops; + s->s_maxbytes = ~0ULL; root_inode = proc_get_inode(s, PROC_ROOT_INO, &proc_root); if (!root_inode) diff -Naurp linux-2.4.20-wolk4.1s/fs/proc/kcore.c linux-2.4.20-wolk4.2-fullkernel/fs/proc/kcore.c --- linux-2.4.20-wolk4.1s/fs/proc/kcore.c 2003-05-15 21:52:42.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/proc/kcore.c 2003-06-02 17:23:44.000000000 +0200 @@ -56,11 +56,14 @@ static int open_kcore(struct inode * ino #endif } +static loff_t lseek_kcore(struct file * file, loff_t offset, int origin); + static ssize_t read_kcore(struct file *, char *, size_t, loff_t *); struct file_operations proc_kcore_operations = { read: read_kcore, open: open_kcore, + llseek: lseek_kcore, }; #ifdef CONFIG_KCORE_AOUT @@ -141,9 +144,9 @@ struct memelfnote extern char saved_command_line[]; -static size_t get_kcore_size(int *num_vma, size_t *elf_buflen) +static unsigned long get_kcore_size(int *num_vma, size_t *elf_buflen) { - size_t try, size; + unsigned long try, size; struct vm_struct *m; *num_vma = 0; @@ -154,7 +157,7 @@ static size_t get_kcore_size(int *num_vm } for (m=vmlist; m; m=m->next) { - try = (size_t)m->addr + m->size; + try = (unsigned long)m->addr + m->size; if (try > size) size = try; *num_vma = *num_vma + 1; @@ -342,14 +345,14 @@ static void elf_kcore_store_hdr(char *bu static ssize_t read_kcore(struct file *file, char *buffer, size_t buflen, loff_t *fpos) { ssize_t acc = 0; - size_t size, tsz; + unsigned long size, tsz; size_t elf_buflen; int num_vma; unsigned long start; read_lock(&vmlist_lock); proc_root_kcore->size = size = get_kcore_size(&num_vma, &elf_buflen); - if (buflen == 0 || *fpos >= size) { + if (buflen == 0 || (unsigned long long)*fpos >= size) { read_unlock(&vmlist_lock); return 0; } @@ -419,9 +422,16 @@ static ssize_t read_kcore(struct file *f start = PAGE_OFFSET + (*fpos - elf_buflen); if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen) tsz = buflen; - while (buflen) { - if ((start >= VMALLOC_START) && (start < VMALLOC_END)) { + int err; + + if ((start > PAGE_OFFSET) && (start < (unsigned long)high_memory)) { + if (kern_addr_valid(start)) { + err = copy_to_user(buffer, (char *)start, tsz); + } else { + err = clear_user(buffer, tsz); + } + } else { char * elf_buf; struct vm_struct *m; unsigned long curstart = start; @@ -461,24 +471,11 @@ static ssize_t read_kcore(struct file *f (char *)vmstart, vmsize); } read_unlock(&vmlist_lock); - if (copy_to_user(buffer, elf_buf, tsz)) { + err = copy_to_user(buffer, elf_buf, tsz); kfree(elf_buf); - return -EFAULT; } - kfree(elf_buf); - } else if ((start > PAGE_OFFSET) && (start < - (unsigned long)high_memory)) { - if (kern_addr_valid(start)) { - if (copy_to_user(buffer, (char *)start, tsz)) + if (err) return -EFAULT; - } else { - if (clear_user(buffer, tsz)) - return -EFAULT; - } - } else { - if (clear_user(buffer, tsz)) - return -EFAULT; - } buflen -= tsz; *fpos += tsz; buffer += tsz; @@ -490,3 +487,17 @@ static ssize_t read_kcore(struct file *f return acc; } #endif /* CONFIG_KCORE_AOUT */ + +static loff_t lseek_kcore(struct file * file, loff_t offset, int origin) +{ + switch (origin) { + case 2: + offset += file->f_dentry->d_inode->i_size; + break; + case 1: + offset += file->f_pos; + } + /* RED-PEN user can fake an error here by setting offset to >=-4095 && <0 */ + file->f_pos = offset; + return offset; +} diff -Naurp linux-2.4.20-wolk4.1s/fs/proc/proc_misc.c linux-2.4.20-wolk4.2-fullkernel/fs/proc/proc_misc.c --- linux-2.4.20-wolk4.1s/fs/proc/proc_misc.c 2003-05-15 21:52:42.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/proc/proc_misc.c 2003-06-02 17:31:54.000000000 +0200 @@ -635,7 +635,8 @@ static ssize_t read_profile(struct file buf++; p++; count--; read++; } pnt = (char *)prof_buffer + p - sizeof(unsigned int); - copy_to_user(buf,(void *)pnt,count); + if (copy_to_user(buf,(void *)pnt,count)) + return -EFAULT; read += count; *ppos += read; return read; diff -Naurp linux-2.4.20-wolk4.1s/fs/super.c linux-2.4.20-wolk4.2-fullkernel/fs/super.c --- linux-2.4.20-wolk4.1s/fs/super.c 2003-05-15 21:52:42.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/fs/super.c 2003-06-05 23:30:57.000000000 +0200 @@ -444,6 +444,7 @@ static void remove_super(struct super_bl up_write(&s->s_umount); put_super(s); put_filesystem(fs); + blk_print_stats(dev); if (bdev) blkdev_put(bdev, BDEV_FS); else @@ -857,6 +858,7 @@ restart: goto Einval; sb_limit_maxbytes(s); s->s_flags |= MS_ACTIVE; + blk_reset_stats(dev); path_release(&nd); return s; diff -Naurp linux-2.4.20-wolk4.1s/grsecurity/Config.in linux-2.4.20-wolk4.2-fullkernel/grsecurity/Config.in --- linux-2.4.20-wolk4.1s/grsecurity/Config.in 2003-05-15 21:52:43.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/grsecurity/Config.in 2003-06-02 17:31:54.000000000 +0200 @@ -222,13 +222,13 @@ if [ "$CONFIG_GRKERNSEC_PAX_NOEXEC" = "y if [ "$CONFIG_X86" = "y" ]; then bool ' Disallow ELF text relocations (DANGEROUS)' CONFIG_GRKERNSEC_PAX_NOELFRELOCS else - if [ "$CONFIG_ALPHA" = "y" ]; then + if [ "$CONFIG_ALPHA" = "y" -o "$CONFIG_PARISC" = "y" ]; then bool ' Allow ELF ET_EXEC text relocations' CONFIG_GRKERNSEC_PAX_ETEXECRELOCS fi if [ "$CONFIG_PPC32" = "y" ]; then define_bool CONFIG_GRKERNSEC_PAX_SYSCALL y fi - if [ "$CONFIG_ALPHA" = "y" -o "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" -o "$CONFIG_PPC32" = "y" ]; then + if [ "$CONFIG_ALPHA" = "y" -o "$CONFIG_PARISC" = "y" -o "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" -o "$CONFIG_PPC32" = "y" ]; then bool ' Automatically emulate ELF PLT' CONFIG_GRKERNSEC_PAX_EMUPLT if [ "$CONFIG_GRKERNSEC_PAX_EMUPLT" = "y" ]; then if [ "$CONFIG_SPARC32" = "y" -o "$CONFIG_SPARC64" = "y" ]; then diff -Naurp linux-2.4.20-wolk4.1s/include/asm-arm/system.h linux-2.4.20-wolk4.2-fullkernel/include/asm-arm/system.h --- linux-2.4.20-wolk4.1s/include/asm-arm/system.h 2003-05-15 21:52:44.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/asm-arm/system.h 2003-06-02 17:21:07.000000000 +0200 @@ -39,6 +39,8 @@ extern asmlinkage void __backtrace(void) #define mb() __asm__ __volatile__ ("" : : : "memory") #define rmb() mb() #define wmb() mb() +#define set_mb(var, value) do { var = value; mb(); } while (0) +#define set_wmb(var, value) do { var = value; wmb(); } while (0) #define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t"); #define prepare_to_switch() do { } while(0) diff -Naurp linux-2.4.20-wolk4.1s/include/asm-cris/system.h linux-2.4.20-wolk4.2-fullkernel/include/asm-cris/system.h --- linux-2.4.20-wolk4.1s/include/asm-cris/system.h 2003-05-15 21:52:44.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/asm-cris/system.h 2003-06-02 17:21:07.000000000 +0200 @@ -152,6 +152,8 @@ static inline unsigned long __xchg(unsig #define mb() __asm__ __volatile__ ("" : : : "memory") #define rmb() mb() #define wmb() mb() +#define set_mb(var, value) do { var = value; mb(); } while (0) +#define set_wmb(var, value) do { var = value; wmb(); } while (0) #ifdef CONFIG_SMP #define smp_mb() mb() diff -Naurp linux-2.4.20-wolk4.1s/include/asm-i386/bugs.h linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/bugs.h --- linux-2.4.20-wolk4.1s/include/asm-i386/bugs.h 2003-05-15 21:52:44.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/bugs.h 2003-06-03 13:09:56.000000000 +0200 @@ -210,6 +210,7 @@ static void __init check_config(void) static void __init check_bugs(void) { extern void __init boot_init_fpu(void); + int x86_cpu; identify_cpu(&boot_cpu_data); boot_init_fpu(); @@ -221,5 +222,13 @@ static void __init check_bugs(void) check_fpu(); check_hlt(); check_popad(); - system_utsname.machine[1] = '0' + (boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86); + + x86_cpu = boot_cpu_data.x86 > 6 ? 6 : boot_cpu_data.x86; + /* VIA C3 and others: report to userland they are i586 since they + don't fully support CMOV instructions. Otherwise, glibc ELF + loader may want to load i686 libraries, which will fail. */ + if (x86_cpu == 6 && + ! test_bit(X86_FEATURE_CMOV, boot_cpu_data.x86_capability)) + x86_cpu = 5; + system_utsname.machine[1] = '0' + x86_cpu; } diff -Naurp linux-2.4.20-wolk4.1s/include/asm-i386/io_apic.h linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/io_apic.h --- linux-2.4.20-wolk4.1s/include/asm-i386/io_apic.h 2003-05-15 21:52:44.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/io_apic.h 2003-06-03 11:39:05.000000000 +0200 @@ -3,6 +3,7 @@ #include #include +#include /* * Intel IO-APIC support for SMP and UP systems. @@ -121,8 +122,11 @@ static inline void io_apic_write(unsigne * Re-write a value: to be used for read-modify-write * cycles where the read already set up the index register. */ -static inline void io_apic_modify(unsigned int apic, unsigned int value) +extern int sis_apic_bug; +static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value) { + if (sis_apic_bug) + *IO_APIC_BASE(apic) = reg; *(IO_APIC_BASE(apic)+4) = value; } diff -Naurp linux-2.4.20-wolk4.1s/include/asm-i386/ioctls.h linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/ioctls.h --- linux-2.4.20-wolk4.1s/include/asm-i386/ioctls.h 2003-05-15 21:52:44.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/ioctls.h 2003-06-02 17:21:08.000000000 +0200 @@ -32,6 +32,7 @@ #define TIOCGSOFTCAR 0x5419 #define TIOCSSOFTCAR 0x541A #define FIONREAD 0x541B +#define FIOFLUSH _IO('F', 1) /* flush a file out of the caches */ #define TIOCINQ FIONREAD #define TIOCLINUX 0x541C #define TIOCCONS 0x541D diff -Naurp linux-2.4.20-wolk4.1s/include/asm-i386/page.h linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/page.h --- linux-2.4.20-wolk4.1s/include/asm-i386/page.h 2003-05-15 21:52:44.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/page.h 2003-06-03 11:39:05.000000000 +0200 @@ -84,7 +84,7 @@ typedef struct { unsigned long pgprot; } * This much address space is reserved for vmalloc() and iomap() * as well as fixmap mappings. */ -#define __VMALLOC_RESERVE (128 << 20) +#define __VMALLOC_RESERVE (192 << 20) #ifndef __ASSEMBLY__ diff -Naurp linux-2.4.20-wolk4.1s/include/asm-i386/page_offset.h linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/page_offset.h --- linux-2.4.20-wolk4.1s/include/asm-i386/page_offset.h 2003-05-15 21:52:44.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/page_offset.h 2003-06-03 11:39:05.000000000 +0200 @@ -1,9 +1,7 @@ #include #include -#ifdef CONFIG_GRKERNSEC_PAX_KERNEXEC #define __KERNEL_TEXT_OFFSET (0xC0400000) -#endif #ifdef CONFIG_GRKERNSEC_PAX_SEGMEXEC #define __PAGE_OFFSET (0xC0000000) diff -Naurp linux-2.4.20-wolk4.1s/include/asm-i386/processor.h linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/processor.h --- linux-2.4.20-wolk4.1s/include/asm-i386/processor.h 2003-05-15 21:52:45.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/processor.h 2003-06-03 11:39:05.000000000 +0200 @@ -300,6 +300,7 @@ extern unsigned int mca_pentium_flag; * Size of io_bitmap in longwords: 32 is ports 0-0x3ff. */ #define IO_BITMAP_SIZE 32 +#define IO_BITMAP_BYTES (IO_BITMAP_SIZE * 4) #define IO_BITMAP_OFFSET offsetof(struct tss_struct,io_bitmap) #define INVALID_IO_BITMAP_OFFSET 0x8000 diff -Naurp linux-2.4.20-wolk4.1s/include/asm-i386/system.h linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/system.h --- linux-2.4.20-wolk4.1s/include/asm-i386/system.h 2003-05-15 21:52:45.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/system.h 2003-06-03 11:39:05.000000000 +0200 @@ -351,13 +351,14 @@ static inline unsigned long __cmpxchg(vo #define smp_mb() mb() #define smp_rmb() rmb() #define smp_wmb() wmb() +#define set_mb(var, value) do { xchg(&var, value); } while (0) #else #define smp_mb() barrier() #define smp_rmb() barrier() #define smp_wmb() barrier() +#define set_mb(var, value) do { var = value; barrier(); } while (0) #endif -#define set_mb(var, value) do { xchg(&var, value); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) /* interrupt control.. */ diff -Naurp linux-2.4.20-wolk4.1s/include/asm-i386/unistd.h linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/unistd.h --- linux-2.4.20-wolk4.1s/include/asm-i386/unistd.h 2003-05-15 21:52:45.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/asm-i386/unistd.h 2003-06-03 11:39:07.000000000 +0200 @@ -257,7 +257,6 @@ #define __NR_alloc_hugepages 250 #define __NR_free_hugepages 251 #define __NR_exit_group 252 -#define __NR_sched_hint 253 #define __NR_epoll_create 254 #define __NR_epoll_ctl 255 #define __NR_epoll_wait 256 diff -Naurp linux-2.4.20-wolk4.1s/include/asm-m68k/system.h linux-2.4.20-wolk4.2-fullkernel/include/asm-m68k/system.h --- linux-2.4.20-wolk4.1s/include/asm-m68k/system.h 2003-05-15 21:52:45.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/asm-m68k/system.h 2003-06-02 17:21:07.000000000 +0200 @@ -83,7 +83,7 @@ asmlinkage void resume(void); #define mb() barrier() #define rmb() barrier() #define wmb() barrier() -#define set_mb(var, value) do { xchg(&var, value); } while (0) +#define set_mb(var, value) do { var = value; mb(); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) #define smp_mb() barrier() diff -Naurp linux-2.4.20-wolk4.1s/include/asm-sh/system.h linux-2.4.20-wolk4.2-fullkernel/include/asm-sh/system.h --- linux-2.4.20-wolk4.1s/include/asm-sh/system.h 2003-05-15 21:52:46.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/asm-sh/system.h 2003-06-02 17:21:07.000000000 +0200 @@ -100,7 +100,7 @@ extern void __xchg_called_with_bad_point #define smp_wmb() barrier() #endif -#define set_mb(var, value) do { xchg(&var, value); } while (0) +#define set_mb(var, value) do { var = value; mb(); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) /* Interrupt Control */ diff -Naurp linux-2.4.20-wolk4.1s/include/linux/agp_backend.h linux-2.4.20-wolk4.2-fullkernel/include/linux/agp_backend.h --- linux-2.4.20-wolk4.1s/include/linux/agp_backend.h 2003-05-15 21:52:46.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/agp_backend.h 2003-06-02 17:21:07.000000000 +0200 @@ -82,8 +82,10 @@ enum chipset_type { SVWRKS_HE, SVWRKS_LE, SVWRKS_GENERIC, + NVIDIA_NFORCE, + NVIDIA_NFORCE2, + NVIDIA_GENERIC, HP_ZX1, - NV_NFORCE_2, }; typedef struct _agp_version { diff -Naurp linux-2.4.20-wolk4.1s/include/linux/binfmts.h linux-2.4.20-wolk4.2-fullkernel/include/linux/binfmts.h --- linux-2.4.20-wolk4.1s/include/linux/binfmts.h 2003-05-15 21:52:46.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/binfmts.h 2003-06-03 11:39:05.000000000 +0200 @@ -1,7 +1,6 @@ #ifndef _LINUX_BINFMTS_H #define _LINUX_BINFMTS_H -#include #include #include diff -Naurp linux-2.4.20-wolk4.1s/include/linux/blkdev.h linux-2.4.20-wolk4.2-fullkernel/include/linux/blkdev.h --- linux-2.4.20-wolk4.1s/include/linux/blkdev.h 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/blkdev.h 2003-06-03 11:39:32.000000000 +0200 @@ -96,6 +96,7 @@ struct request_queue * Together with queue_head for cacheline sharing */ struct list_head queue_head; + struct list_head atomic_head; elevator_t elevator; struct request *last_merge; @@ -115,6 +116,7 @@ struct request_queue * This is used to remove the plug when tq_disk runs. */ struct tq_struct plug_tq; + struct list_head atomic_entry; /* * Boolean that indicates whether this queue is plugged or not. @@ -139,13 +141,30 @@ struct request_queue * Tasks wait here for free read and write requests */ wait_queue_head_t wait_for_requests[2]; + unsigned long max_wait; + unsigned long min_wait; + unsigned long total_wait; + unsigned long num_req; + unsigned long num_wait; + unsigned long deviation[5]; }; +void blk_reset_stats(kdev_t dev); +void blk_print_stats(kdev_t dev); + extern unsigned long blk_max_low_pfn, blk_max_pfn; #define BLK_BOUNCE_HIGH (blk_max_low_pfn << PAGE_SHIFT) #define BLK_BOUNCE_ANY (blk_max_pfn << PAGE_SHIFT) +/* + * max guaranteed atomic I/O size while dealing with bounce buffers. + * highmemio capable devices (pci64 in particular) can go well beyond + * this limit. Must be a multiple of 512bytes obviously. + */ +#define BLK_ATOMIC_BOUNCE_SIZE 32768 +#define BLK_ATOMIC_BOUNCE_ENTRIES (BLK_ATOMIC_BOUNCE_SIZE >> 9) + extern void blk_queue_bounce_limit(request_queue_t *, u64); #ifdef CONFIG_HIGHMEM @@ -202,6 +221,14 @@ extern void register_disk(struct gendisk extern void generic_make_request(int rw, struct buffer_head * bh); extern inline request_queue_t *blk_get_queue(kdev_t dev); extern void blkdev_release_request(struct request *); +extern void blk_print_stats(kdev_t dev); + +extern spinlock_cacheline_t blk_atomic_lock_cacheline; +#define blk_atomic_lock (blk_atomic_lock_cacheline.lock) +extern unsigned int blk_get_atomic_seq(void); +extern spinlock_cacheline_t blk_atomic_queue_lock_cacheline; +#define blk_atomic_queue_lock (blk_atomic_queue_lock_cacheline.lock) +extern void FASTCALL(blk_refile_atomic_queue(int sequence)); /* * Access functions for manipulating queue properties diff -Naurp linux-2.4.20-wolk4.1s/include/linux/cache_def.h linux-2.4.20-wolk4.2-fullkernel/include/linux/cache_def.h --- linux-2.4.20-wolk4.1s/include/linux/cache_def.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/cache_def.h 2003-06-02 17:23:46.000000000 +0200 @@ -0,0 +1,15 @@ +/* + * linux/cache_def.h + * Handling of caches defined in drivers, filesystems, ... + * + * Copyright (C) 2002 by Andreas Gruenbacher, + */ + +struct cache_definition { + const char *name; + void (*shrink)(int, unsigned int); + struct list_head link; +}; + +extern void register_cache(struct cache_definition *); +extern void unregister_cache(struct cache_definition *); diff -Naurp linux-2.4.20-wolk4.1s/include/linux/elevator.h linux-2.4.20-wolk4.2-fullkernel/include/linux/elevator.h --- linux-2.4.20-wolk4.1s/include/linux/elevator.h 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/elevator.h 2003-06-04 01:17:31.000000000 +0200 @@ -68,7 +68,7 @@ static inline int elevator_request_laten ((elevator_t) { \ 0, /* read_latency */ \ 0, /* write_latency */ \ - 0, /* max_bomb_segments */ \ + \ elevator_noop_merge, /* elevator_merge_fn */ \ elevator_noop_merge_req, /* elevator_merge_req_fn */ \ }) @@ -82,6 +82,7 @@ static inline int elevator_request_laten 2048, /* read passovers */ \ 8192, /* write passovers */ \ 6, /* max_bomb_segments */ \ + \ elevator_linus_merge, /* elevator_merge_fn */ \ elevator_linus_merge_req, /* elevator_merge_req_fn */ \ }) @@ -89,25 +90,27 @@ static inline int elevator_request_laten #elif (!defined (CONFIG_BLK_DEV_ELEVATOR_LOWLAT) && defined (CONFIG_SCHED_DESKTOP)) #define ELEVATOR_READ_LATENCY 512 #define ELEVATOR_WRITE_LATENCY 8192 -#define ELEVATOR_MAX_BOMB_SEGMENTS 2 +#define ELEVATOR_MAX_BOMB_SEGMENTS 4 #define ELEVATOR_LINUS \ ((elevator_t) { \ 512, /* read passovers */ \ 8192, /* write passovers */ \ - 2, /* max_bomb_segments */ \ + 4, /* max_bomb_segments */ \ + \ elevator_linus_merge, /* elevator_merge_fn */ \ elevator_linus_merge_req, /* elevator_merge_req_fn */ \ }) #elif defined (CONFIG_BLK_DEV_ELEVATOR_LOWLAT) -#define ELEVATOR_READ_LATENCY 0 -#define ELEVATOR_WRITE_LATENCY 0 -#define ELEVATOR_MAX_BOMB_SEGMENTS 0 +#define ELEVATOR_READ_LATENCY 128 +#define ELEVATOR_WRITE_LATENCY 256 +#define ELEVATOR_MAX_BOMB_SEGMENTS 2 #define ELEVATOR_LINUS \ ((elevator_t) { \ - 0, /* read passovers */ \ - 0, /* write passovers */ \ - 1, /* max_bomb_segments */ \ + 128, /* read passovers */ \ + 256, /* write passovers */ \ + 2, /* max_bomb_segments */ \ + \ elevator_linus_merge, /* elevator_merge_fn */ \ elevator_linus_merge_req, /* elevator_merge_req_fn */ \ }) diff -Naurp linux-2.4.20-wolk4.1s/include/linux/fs.h linux-2.4.20-wolk4.2-fullkernel/include/linux/fs.h --- linux-2.4.20-wolk4.1s/include/linux/fs.h 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/fs.h 2003-06-05 23:30:57.000000000 +0200 @@ -220,6 +220,7 @@ extern int leases_enable, dir_notify_ena #include extern void update_atime (struct inode *); +extern void update_mctime (struct inode *); #define UPDATE_ATIME(inode) update_atime (inode) extern void buffer_init(unsigned long); @@ -242,6 +243,7 @@ enum bh_state_bits { BH_Attached, /* 1 if b_inode_buffers is linked into a list */ BH_JBD, /* 1 if it has an attached journal_head */ BH_Delay, /* 1 if the buffer is delayed allocate */ + BH_Atomic, /* 1 if b_elv_sequence is valid */ BH_PrivateStart,/* not a state bit, but the first bit available * for private allocation by other entities @@ -286,6 +288,7 @@ struct buffer_head { void *b_private; /* reserved for b_end_io */ void *b_journal_head; /* FS journal_heads */ unsigned long b_rsector; /* Real buffer location on disk */ + int b_elv_sequence; /* for atomic blocks */ wait_queue_head_t b_wait; struct list_head b_inode_buffers; /* doubly linked list of inode dirty buffers */ @@ -306,6 +309,7 @@ void init_buffer(struct buffer_head *, b #define buffer_async(bh) __buffer_state(bh,Async) #define buffer_launder(bh) __buffer_state(bh,Launder) #define buffer_delay(bh) __buffer_state(bh,Delay) +#define buffer_atomic(bh) __buffer_state(bh,Atomic) #define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) @@ -313,6 +317,7 @@ extern void set_bh_page(struct buffer_he #define touch_buffer(bh) mark_page_accessed(bh->b_page) +#define bh_elv_seq(bh) (bh)->b_elv_sequence #include #include diff -Naurp linux-2.4.20-wolk4.1s/include/linux/iobuf.h linux-2.4.20-wolk4.2-fullkernel/include/linux/iobuf.h --- linux-2.4.20-wolk4.1s/include/linux/iobuf.h 2003-05-15 21:52:46.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/iobuf.h 2003-06-04 21:14:16.000000000 +0200 @@ -35,7 +35,6 @@ struct kiobuf { - int rw; /* mapped for READ or WRITE */ int nr_pages; /* Pages actually referenced */ int array_len; /* Space in the allocated lists */ int offset; /* Offset to start of valid data */ diff -Naurp linux-2.4.20-wolk4.1s/include/linux/jbd.h linux-2.4.20-wolk4.2-fullkernel/include/linux/jbd.h --- linux-2.4.20-wolk4.1s/include/linux/jbd.h 2003-05-15 21:52:46.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/jbd.h 2003-06-03 11:41:24.000000000 +0200 @@ -280,7 +280,7 @@ static inline struct buffer_head *jh2bh( static inline struct journal_head *bh2jh(struct buffer_head *bh) { - return bh->b_journal_head; + return bh->b_journal_head; } #define HAVE_JOURNAL_CALLBACK_STATUS diff -Naurp linux-2.4.20-wolk4.1s/include/linux/mbcache.h linux-2.4.20-wolk4.2-fullkernel/include/linux/mbcache.h --- linux-2.4.20-wolk4.1s/include/linux/mbcache.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/mbcache.h 2003-06-02 17:23:46.000000000 +0200 @@ -0,0 +1,69 @@ +/* + File: linux/mbcache.h + + (C) 2001 by Andreas Gruenbacher, +*/ + +/* Hardwire the number of additional indexes */ +#define MB_CACHE_INDEXES_COUNT 1 + +struct mb_cache_entry; + +struct mb_cache_op { + void (*free)(struct mb_cache_entry *); +}; + +struct mb_cache { + struct list_head c_cache_list; + const char *c_name; + struct mb_cache_op c_op; + atomic_t c_entry_count; + int c_bucket_count; +#ifndef MB_CACHE_INDEXES_COUNT + int c_indexes_count; +#endif + kmem_cache_t *c_entry_cache; + struct list_head *c_block_hash; + struct list_head *c_indexes_hash[0]; +}; + +struct mb_cache_entry_index { + struct list_head o_list; + unsigned int o_key; +}; + +struct mb_cache_entry { + struct list_head e_lru_list; + struct mb_cache *e_cache; + atomic_t e_used; + kdev_t e_dev; + unsigned long e_block; + struct list_head e_block_list; + struct mb_cache_entry_index e_indexes[0]; +}; + +/* Functions on caches */ + +struct mb_cache * mb_cache_create(const char *, struct mb_cache_op *, size_t, + int, int); +void mb_cache_shrink(struct mb_cache *, kdev_t); +void mb_cache_destroy(struct mb_cache *); + +/* Functions on cache entries */ + +struct mb_cache_entry *mb_cache_entry_alloc(struct mb_cache *); +int mb_cache_entry_insert(struct mb_cache_entry *, kdev_t, unsigned long, + unsigned int[]); +void mb_cache_entry_rehash(struct mb_cache_entry *, unsigned int[]); +void mb_cache_entry_release(struct mb_cache_entry *); +void mb_cache_entry_takeout(struct mb_cache_entry *); +void mb_cache_entry_free(struct mb_cache_entry *); +struct mb_cache_entry *mb_cache_entry_dup(struct mb_cache_entry *); +struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *, kdev_t, + unsigned long); +#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) +struct mb_cache_entry *mb_cache_entry_find_first(struct mb_cache *cache, int, + kdev_t, unsigned int); +struct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache_entry *, int, + kdev_t, unsigned int); +#endif diff -Naurp linux-2.4.20-wolk4.1s/include/linux/pc_keyb.h linux-2.4.20-wolk4.2-fullkernel/include/linux/pc_keyb.h --- linux-2.4.20-wolk4.1s/include/linux/pc_keyb.h 1999-10-11 19:15:40.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/pc_keyb.h 2003-06-02 17:23:42.000000000 +0200 @@ -12,7 +12,7 @@ #undef KBD_REPORT_ERR /* Report keyboard errors */ #define KBD_REPORT_UNKN /* Report unknown scan codes */ -#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ +#undef KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */ #undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */ #undef INITIALIZE_MOUSE /* Define if your PS/2 mouse needs initialization. */ diff -Naurp linux-2.4.20-wolk4.1s/include/linux/pci_ids.h linux-2.4.20-wolk4.2-fullkernel/include/linux/pci_ids.h --- linux-2.4.20-wolk4.1s/include/linux/pci_ids.h 2003-05-15 21:52:47.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/pci_ids.h 2003-06-02 17:21:07.000000000 +0200 @@ -962,6 +962,8 @@ #define PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL 0x017B #define PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL 0x017C #define PCI_DEVICE_ID_NVIDIA_IGEFORCE2 0x01a0 +#define PCI_DEVICE_ID_NVIDIA_NFORCE 0x01a4 +#define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202 diff -Naurp linux-2.4.20-wolk4.1s/include/linux/sched.h linux-2.4.20-wolk4.2-fullkernel/include/linux/sched.h --- linux-2.4.20-wolk4.1s/include/linux/sched.h 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/sched.h 2003-06-03 11:39:05.000000000 +0200 @@ -102,30 +102,13 @@ extern unsigned long nr_uninterruptible( #define __set_task_state(tsk, state_value) \ do { (tsk)->state = (state_value); } while (0) -#ifdef CONFIG_SMP #define set_task_state(tsk, state_value) \ set_mb((tsk)->state, (state_value)) -#else -#define set_task_state(tsk, state_value) \ - __set_task_state((tsk), (state_value)) -#endif #define __set_current_state(state_value) \ do { current->state = (state_value); } while (0) -#ifdef CONFIG_SMP #define set_current_state(state_value) \ set_mb(current->state, (state_value)) -#else -#define set_current_state(state_value) \ - __set_current_state(state_value) -#endif - -/* - * Scheduling Hints - */ -#define HINT_TIME 1 /* increase remaining timeslice */ -#define HINT_INTERACTIVE 2 /* interactive task: prio bonus */ -#define HINT_BATCH 4 /* batch task: prio penalty */ /* * Scheduling policies @@ -788,14 +771,11 @@ extern void FASTCALL(wake_up_forked_proc #define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1) #define wake_up_nr(x, nr) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr) #define wake_up_all(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0) +#define wake_up_all_sync(x) __wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0) #define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE, 1) #define wake_up_interruptible_nr(x, nr) __wake_up((x),TASK_INTERRUPTIBLE, nr) #define wake_up_interruptible_all(x) __wake_up((x),TASK_INTERRUPTIBLE, 0) -#ifdef CONFIG_SMP #define wake_up_interruptible_sync(x) __wake_up_sync((x),TASK_INTERRUPTIBLE, 1) -#else -#define wake_up_interruptible_sync(x) __wake_up((x),TASK_INTERRUPTIBLE, 1) -#endif asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); diff -Naurp linux-2.4.20-wolk4.1s/include/linux/sunrpc/sched.h linux-2.4.20-wolk4.2-fullkernel/include/linux/sunrpc/sched.h --- linux-2.4.20-wolk4.1s/include/linux/sunrpc/sched.h 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/sunrpc/sched.h 2003-06-03 11:39:20.000000000 +0200 @@ -128,12 +128,7 @@ typedef void (*rpc_action)(struct rpc_ #define RPC_IS_RUNNING(t) (test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) #define rpc_set_running(t) (set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) -#define rpc_clear_running(t) \ - do { \ - smp_mb__before_clear_bit(); \ - clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate); \ - smp_mb__after_clear_bit(); \ - } while(0) +#define rpc_clear_running(t) (clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate)) #define rpc_set_sleeping(t) (set_bit(RPC_TASK_SLEEPING, &(t)->tk_runstate)) diff -Naurp linux-2.4.20-wolk4.1s/include/linux/sunrpc/xprt.h linux-2.4.20-wolk4.2-fullkernel/include/linux/sunrpc/xprt.h --- linux-2.4.20-wolk4.1s/include/linux/sunrpc/xprt.h 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/sunrpc/xprt.h 2003-06-03 11:39:20.000000000 +0200 @@ -186,12 +186,7 @@ void xprt_sock_setbufsize(struct rpc_x #define xprt_connected(xp) (!(xp)->stream || test_bit(XPRT_CONNECT, &(xp)->sockstate)) #define xprt_set_connected(xp) (set_bit(XPRT_CONNECT, &(xp)->sockstate)) #define xprt_test_and_set_connected(xp) (test_and_set_bit(XPRT_CONNECT, &(xp)->sockstate)) -#define xprt_clear_connected(xp) \ - do { \ - smp_mb__before_clear_bit(); \ - clear_bit(XPRT_CONNECT, &(xp)->sockstate); \ - smp_mb__after_clear_bit(); \ - } while(0) +#define xprt_clear_connected(xp) (clear_bit(XPRT_CONNECT, &(xp)->sockstate)) #endif /* __KERNEL__*/ diff -Naurp linux-2.4.20-wolk4.1s/include/linux/swap.h linux-2.4.20-wolk4.2-fullkernel/include/linux/swap.h --- linux-2.4.20-wolk4.1s/include/linux/swap.h 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/swap.h 2003-06-03 11:39:05.000000000 +0200 @@ -91,6 +91,7 @@ extern unsigned int nr_active_cache_page extern unsigned int nr_inactive_dirty_pages(void); extern unsigned int nr_inactive_laundry_pages(void); extern unsigned int nr_inactive_clean_pages(void); +extern unsigned int freeable_lowmem(void); extern atomic_t page_cache_size; extern atomic_t buffermem_pages; @@ -147,6 +148,8 @@ extern struct page * FASTCALL(reclaim_pa extern wait_queue_head_t kswapd_wait; extern int FASTCALL(try_to_free_pages(unsigned int gfp_mask)); extern int rebalance_laundry_zone(struct zone_struct *, int, unsigned int); +extern int rebalance_dirty_zone(struct zone_struct *, int, unsigned int); +extern int rebalance_inactive(int); extern void wakeup_kswapd(unsigned int); extern void rss_free_pages(unsigned int); diff -Naurp linux-2.4.20-wolk4.1s/include/linux/sysctl.h linux-2.4.20-wolk4.2-fullkernel/include/linux/sysctl.h --- linux-2.4.20-wolk4.1s/include/linux/sysctl.h 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/sysctl.h 2003-06-03 20:45:38.000000000 +0200 @@ -63,7 +63,8 @@ enum CTL_DEV=7, /* Devices */ CTL_BUS=8, /* Busses */ CTL_ABI=9, /* Binary emulation */ - CTL_CPU=10 /* CPU stuff (speed scaling, etc) */ + CTL_CPU=10, /* CPU stuff (speed scaling, etc) */ + CTL_SCHED=11 /* scheduler tunables */ }; /* CTL_BUS names: */ @@ -157,6 +158,20 @@ enum VM_PAGEBUF=15, /* struct: Control pagebuf parameters */ }; +/* Tunable scheduler parameters in /proc/sys/sched/ */ +enum +{ + SCHED_MIN_TIMESLICE=1, /* minimum process timeslice */ + SCHED_MAX_TIMESLICE=2, /* maximum process timeslice */ + SCHED_CHILD_PENALTY=3, /* penalty on fork to child */ + SCHED_PARENT_PENALTY=4, /* penalty on fork to parent */ + SCHED_EXIT_WEIGHT=5, /* penalty to parent of CPU hog child */ + SCHED_PRIO_BONUS_RATIO=6, /* percent of max prio given as bonus */ + SCHED_INTERACTIVE_DELTA=7, /* delta used to scale interactivity */ + SCHED_MAX_SLEEP_AVG=8, /* maximum sleep avg attainable */ + SCHED_STARVATION_LIMIT=9, /* no re-active if expired is starved */ +}; + /* CTL_NET names: */ enum { diff -Naurp linux-2.4.20-wolk4.1s/include/linux/tty.h linux-2.4.20-wolk4.2-fullkernel/include/linux/tty.h --- linux-2.4.20-wolk4.1s/include/linux/tty.h 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/linux/tty.h 2003-06-03 11:39:11.000000000 +0200 @@ -347,7 +347,6 @@ struct tty_struct { extern void tty_write_flush(struct tty_struct *); extern struct termios tty_std_termios; -extern struct tty_struct * redirect; extern struct tty_ldisc ldiscs[]; extern int fg_console, last_console, want_console; diff -Naurp linux-2.4.20-wolk4.1s/include/net/bluetooth/bluetooth.h linux-2.4.20-wolk4.2-fullkernel/include/net/bluetooth/bluetooth.h --- linux-2.4.20-wolk4.1s/include/net/bluetooth/bluetooth.h 2002-09-27 23:26:11.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/net/bluetooth/bluetooth.h 2003-06-03 20:02:49.000000000 +0200 @@ -155,7 +155,7 @@ void bluez_sock_link(struct bluez_sock_l void bluez_sock_unlink(struct bluez_sock_list *l, struct sock *s); int bluez_sock_recvmsg(struct socket *sock, struct msghdr *msg, int len, int flags, struct scm_cookie *scm); uint bluez_sock_poll(struct file * file, struct socket *sock, poll_table *wait); -int bluez_sock_w4_connect(struct sock *sk, int flags); +int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo); void bluez_accept_enqueue(struct sock *parent, struct sock *sk); struct sock * bluez_accept_dequeue(struct sock *parent, struct socket *newsock); diff -Naurp linux-2.4.20-wolk4.1s/include/net/bluetooth/hci.h linux-2.4.20-wolk4.2-fullkernel/include/net/bluetooth/hci.h --- linux-2.4.20-wolk4.1s/include/net/bluetooth/hci.h 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/include/net/bluetooth/hci.h 2003-06-03 20:02:49.000000000 +0200 @@ -39,6 +39,8 @@ #define HCI_DEV_UNREG 2 #define HCI_DEV_UP 3 #define HCI_DEV_DOWN 4 +#define HCI_DEV_SUSPEND 5 +#define HCI_DEV_RESUME 6 /* HCI device types */ #define HCI_VHCI 0 @@ -46,6 +48,7 @@ #define HCI_PCCARD 2 #define HCI_UART 3 #define HCI_RS232 4 +#define HCI_PCI 5 /* HCI device flags */ enum { @@ -157,6 +160,7 @@ enum { #define HCI_LM_AUTH 0x0002 #define HCI_LM_ENCRYPT 0x0004 #define HCI_LM_TRUSTED 0x0008 +#define HCI_LM_RELIABLE 0x0010 /* ----- HCI Commands ----- */ /* OGF & OCF values */ @@ -436,6 +440,12 @@ typedef struct { /* Status params */ #define OGF_STATUS_PARAM 0x05 +/* Testing commands */ +#define OGF_TESTING_CMD 0x3e + +/* Vendor specific commands */ +#define OGF_VENDOR_CMD 0x3f + /* ---- HCI Events ---- */ #define EVT_INQUIRY_COMPLETE 0x01 @@ -542,7 +552,7 @@ typedef struct { bdaddr_t bdaddr; __u8 role; } __attribute__ ((packed)) evt_role_change; -#define EVT_ROLE_CHANGE_SIZE 1 +#define EVT_ROLE_CHANGE_SIZE 8 #define EVT_PIN_CODE_REQ 0x16 typedef struct { diff -Naurp linux-2.4.20-wolk4.1s/include/net/bluetooth/hci_core.h linux-2.4.20-wolk4.2-fullkernel/include/net/bluetooth/hci_core.h --- linux-2.4.20-wolk4.1s/include/net/bluetooth/hci_core.h 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/include/net/bluetooth/hci_core.h 2003-06-03 20:02:49.000000000 +0200 @@ -281,8 +281,12 @@ static inline void hci_conn_hold(struct static inline void hci_conn_put(struct hci_conn *conn) { - if (atomic_dec_and_test(&conn->refcnt) && conn->out) - hci_conn_set_timer(conn, HCI_DISCONN_TIMEOUT); + if (atomic_dec_and_test(&conn->refcnt)) { + if (conn->type == SCO_LINK) + hci_conn_set_timer(conn, HZ / 100); + else if (conn->out) + hci_conn_set_timer(conn, HCI_DISCONN_TIMEOUT); + } } /* ----- HCI Devices ----- */ @@ -302,6 +306,8 @@ struct hci_dev *hci_dev_get(int index); struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst); int hci_register_dev(struct hci_dev *hdev); int hci_unregister_dev(struct hci_dev *hdev); +int hci_suspend_dev(struct hci_dev *hdev); +int hci_resume_dev(struct hci_dev *hdev); int hci_dev_open(__u16 dev); int hci_dev_close(__u16 dev); int hci_dev_reset(__u16 dev); @@ -429,7 +435,6 @@ int hci_unregister_notifier(struct notif int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param); int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags); int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb); -int hci_send_raw(struct sk_buff *skb); void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf); @@ -447,7 +452,7 @@ struct hci_pinfo { }; /* HCI security filter */ -#define HCI_SFLT_MAX_OGF 4 +#define HCI_SFLT_MAX_OGF 5 struct hci_sec_filter { __u32 type_mask; @@ -455,7 +460,6 @@ struct hci_sec_filter { __u32 ocf_mask[HCI_SFLT_MAX_OGF + 1][4]; }; - /* ----- HCI requests ----- */ #define HCI_REQ_DONE 0 #define HCI_REQ_PEND 1 diff -Naurp linux-2.4.20-wolk4.1s/include/net/bluetooth/l2cap.h linux-2.4.20-wolk4.2-fullkernel/include/net/bluetooth/l2cap.h --- linux-2.4.20-wolk4.1s/include/net/bluetooth/l2cap.h 2002-09-27 23:26:11.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/net/bluetooth/l2cap.h 2003-06-03 20:02:49.000000000 +0200 @@ -60,6 +60,7 @@ struct l2cap_conninfo { #define L2CAP_LM_AUTH 0x0002 #define L2CAP_LM_ENCRYPT 0x0004 #define L2CAP_LM_TRUSTED 0x0008 +#define L2CAP_LM_RELIABLE 0x0010 #define L2CAP_QOS 0x04 struct l2cap_qos { @@ -238,8 +239,8 @@ struct l2cap_pinfo { struct sock *prev_c; }; -#define CONF_REQ_SENT 0x01 -#define CONF_INPUT_DONE 0x02 -#define CONF_OUTPUT_DONE 0x04 +#define L2CAP_CONF_REQ_SENT 0x01 +#define L2CAP_CONF_INPUT_DONE 0x02 +#define L2CAP_CONF_OUTPUT_DONE 0x04 #endif /* __L2CAP_H */ diff -Naurp linux-2.4.20-wolk4.1s/include/net/bluetooth/rfcomm.h linux-2.4.20-wolk4.2-fullkernel/include/net/bluetooth/rfcomm.h --- linux-2.4.20-wolk4.1s/include/net/bluetooth/rfcomm.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/include/net/bluetooth/rfcomm.h 2003-06-03 20:02:49.000000000 +0200 @@ -0,0 +1,356 @@ +/* + RFCOMM implementation for Linux Bluetooth stack (BlueZ). + Copyright (C) 2002 Maxim Krasnyansky + Copyright (C) 2002 Marcel Holtmann + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + RPN support - Dirk Husemann +*/ + +/* + * $Id: rfcomm.h,v 1.31 2002/10/18 20:12:11 maxk Exp $ + */ + +#ifndef __RFCOMM_H +#define __RFCOMM_H + +#define RFCOMM_PSM 3 + +#define RFCOMM_CONN_TIMEOUT (HZ * 30) +#define RFCOMM_DISC_TIMEOUT (HZ * 20) + +#define RFCOMM_DEFAULT_MTU 127 +#define RFCOMM_DEFAULT_CREDITS 7 + +#define RFCOMM_MAX_L2CAP_MTU 1024 +#define RFCOMM_MAX_CREDITS 40 + +#define RFCOMM_SKB_HEAD_RESERVE 8 +#define RFCOMM_SKB_TAIL_RESERVE 2 +#define RFCOMM_SKB_RESERVE (RFCOMM_SKB_HEAD_RESERVE + RFCOMM_SKB_TAIL_RESERVE) + +#define RFCOMM_SABM 0x2f +#define RFCOMM_DISC 0x43 +#define RFCOMM_UA 0x63 +#define RFCOMM_DM 0x0f +#define RFCOMM_UIH 0xef + +#define RFCOMM_TEST 0x08 +#define RFCOMM_FCON 0x28 +#define RFCOMM_FCOFF 0x18 +#define RFCOMM_MSC 0x38 +#define RFCOMM_RPN 0x24 +#define RFCOMM_RLS 0x14 +#define RFCOMM_PN 0x20 +#define RFCOMM_NSC 0x04 + +#define RFCOMM_V24_FC 0x02 +#define RFCOMM_V24_RTC 0x04 +#define RFCOMM_V24_RTR 0x08 +#define RFCOMM_V24_IC 0x40 +#define RFCOMM_V24_DV 0x80 + +#define RFCOMM_RPN_BR_2400 0x0 +#define RFCOMM_RPN_BR_4800 0x1 +#define RFCOMM_RPN_BR_7200 0x2 +#define RFCOMM_RPN_BR_9600 0x3 +#define RFCOMM_RPN_BR_19200 0x4 +#define RFCOMM_RPN_BR_38400 0x5 +#define RFCOMM_RPN_BR_57600 0x6 +#define RFCOMM_RPN_BR_115200 0x7 +#define RFCOMM_RPN_BR_230400 0x8 + +#define RFCOMM_RPN_DATA_5 0x0 +#define RFCOMM_RPN_DATA_6 0x1 +#define RFCOMM_RPN_DATA_7 0x2 +#define RFCOMM_RPN_DATA_8 0x3 + +#define RFCOMM_RPN_STOP_1 0 +#define RFCOMM_RPN_STOP_15 1 + +#define RFCOMM_RPN_PARITY_NONE 0x0 +#define RFCOMM_RPN_PARITY_ODD 0x4 +#define RFCOMM_RPN_PARITY_EVEN 0x5 +#define RFCOMM_RPN_PARITY_MARK 0x6 +#define RFCOMM_RPN_PARITY_SPACE 0x7 + +#define RFCOMM_RPN_FLOW_NONE 0x00 + +#define RFCOMM_RPN_XON_CHAR 0x11 +#define RFCOMM_RPN_XOFF_CHAR 0x13 + +#define RFCOMM_RPN_PM_BITRATE 0x0001 +#define RFCOMM_RPN_PM_DATA 0x0002 +#define RFCOMM_RPN_PM_STOP 0x0004 +#define RFCOMM_RPN_PM_PARITY 0x0008 +#define RFCOMM_RPN_PM_PARITY_TYPE 0x0010 +#define RFCOMM_RPN_PM_XON 0x0020 +#define RFCOMM_RPN_PM_XOFF 0x0040 +#define RFCOMM_RPN_PM_FLOW 0x3F00 + +#define RFCOMM_RPN_PM_ALL 0x3F7F + +struct rfcomm_hdr { + u8 addr; + u8 ctrl; + u8 len; // Actual size can be 2 bytes +} __attribute__ ((packed)); + +struct rfcomm_cmd { + u8 addr; + u8 ctrl; + u8 len; + u8 fcs; +} __attribute__ ((packed)); + +struct rfcomm_mcc { + u8 type; + u8 len; +} __attribute__ ((packed)); + +struct rfcomm_pn { + u8 dlci; + u8 flow_ctrl; + u8 priority; + u8 ack_timer; + u16 mtu; + u8 max_retrans; + u8 credits; +} __attribute__ ((packed)); + +struct rfcomm_rpn { + u8 dlci; + u8 bit_rate; + u8 line_settings; + u8 flow_ctrl; + u8 xon_char; + u8 xoff_char; + u16 param_mask; +} __attribute__ ((packed)); + +struct rfcomm_rls { + u8 dlci; + u8 status; +} __attribute__ ((packed)); + +struct rfcomm_msc { + u8 dlci; + u8 v24_sig; +} __attribute__ ((packed)); + +/* ---- Core structures, flags etc ---- */ + +struct rfcomm_session { + struct list_head list; + struct socket *sock; + unsigned long state; + unsigned long flags; + atomic_t refcnt; + int initiator; + + /* Default DLC parameters */ + uint mtu; + uint credits; + + struct list_head dlcs; +}; + +struct rfcomm_dlc { + struct list_head list; + struct rfcomm_session *session; + struct sk_buff_head tx_queue; + struct timer_list timer; + + spinlock_t lock; + unsigned long state; + unsigned long flags; + atomic_t refcnt; + u8 dlci; + u8 addr; + u8 priority; + u8 v24_sig; + u8 mscex; + + uint mtu; + uint credits; + uint rx_credits; + uint tx_credits; + + void *owner; + + void (*data_ready)(struct rfcomm_dlc *d, struct sk_buff *skb); + void (*state_change)(struct rfcomm_dlc *d, int err); + void (*modem_status)(struct rfcomm_dlc *d, u8 v24_sig); +}; + +/* DLC and session flags */ +#define RFCOMM_RX_THROTTLED 0 +#define RFCOMM_TX_THROTTLED 1 +#define RFCOMM_MSC_PENDING 2 +#define RFCOMM_TIMED_OUT 3 + +/* Scheduling flags and events */ +#define RFCOMM_SCHED_STATE 0 +#define RFCOMM_SCHED_RX 1 +#define RFCOMM_SCHED_TX 2 +#define RFCOMM_SCHED_TIMEO 3 +#define RFCOMM_SCHED_WAKEUP 31 + +/* MSC exchange flags */ +#define RFCOMM_MSCEX_TX 1 +#define RFCOMM_MSCEX_RX 2 +#define RFCOMM_MSCEX_OK (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX) + +extern struct task_struct *rfcomm_thread; +extern unsigned long rfcomm_event; + +static inline void rfcomm_schedule(uint event) +{ + if (!rfcomm_thread) + return; + set_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event); + wake_up_process(rfcomm_thread); +} + +extern struct semaphore rfcomm_sem; +#define rfcomm_lock() down(&rfcomm_sem); +#define rfcomm_unlock() up(&rfcomm_sem); + +/* ---- RFCOMM DLCs (channels) ---- */ +struct rfcomm_dlc *rfcomm_dlc_alloc(int prio); +void rfcomm_dlc_free(struct rfcomm_dlc *d); +int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel); +int rfcomm_dlc_close(struct rfcomm_dlc *d, int reason); +int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb); +int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig); +int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig); + +#define rfcomm_dlc_lock(d) spin_lock(&d->lock) +#define rfcomm_dlc_unlock(d) spin_unlock(&d->lock) + +static inline void rfcomm_dlc_hold(struct rfcomm_dlc *d) +{ + atomic_inc(&d->refcnt); +} + +static inline void rfcomm_dlc_put(struct rfcomm_dlc *d) +{ + if (atomic_dec_and_test(&d->refcnt)) + rfcomm_dlc_free(d); +} + +extern void FASTCALL(__rfcomm_dlc_throttle(struct rfcomm_dlc *d)); +extern void FASTCALL(__rfcomm_dlc_unthrottle(struct rfcomm_dlc *d)); + +static inline void rfcomm_dlc_throttle(struct rfcomm_dlc *d) +{ + if (!test_and_set_bit(RFCOMM_RX_THROTTLED, &d->flags)) + __rfcomm_dlc_throttle(d); +} + +static inline void rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) +{ + if (test_and_clear_bit(RFCOMM_RX_THROTTLED, &d->flags)) + __rfcomm_dlc_unthrottle(d); +} + +/* ---- RFCOMM sessions ---- */ +struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state); +struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst); +struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err); +void rfcomm_session_del(struct rfcomm_session *s); +void rfcomm_session_close(struct rfcomm_session *s, int err); +void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst); + +static inline void rfcomm_session_hold(struct rfcomm_session *s) +{ + atomic_inc(&s->refcnt); +} + +static inline void rfcomm_session_put(struct rfcomm_session *s) +{ + if (atomic_dec_and_test(&s->refcnt)) + rfcomm_session_del(s); +} + +/* ---- RFCOMM chechsum ---- */ +extern u8 rfcomm_crc_table[]; + +/* ---- RFCOMM sockets ---- */ +struct sockaddr_rc { + sa_family_t rc_family; + bdaddr_t rc_bdaddr; + u8 rc_channel; +}; + +#define rfcomm_pi(sk) ((struct rfcomm_pinfo *) &sk->tp_pinfo) + +struct rfcomm_pinfo { + struct rfcomm_dlc *dlc; + u8 channel; +}; + +int rfcomm_init_sockets(void); +void rfcomm_cleanup_sockets(void); + +int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d); + +/* ---- RFCOMM TTY ---- */ +#define RFCOMM_MAX_DEV 256 + +#define RFCOMMCREATEDEV _IOW('R', 200, int) +#define RFCOMMRELEASEDEV _IOW('R', 201, int) +#define RFCOMMGETDEVLIST _IOR('R', 210, int) +#define RFCOMMGETDEVINFO _IOR('R', 211, int) +#define RFCOMMSTEALDLC _IOW('R', 220, int) + +#define RFCOMM_REUSE_DLC 0 +#define RFCOMM_RELEASE_ONHUP 1 +#define RFCOMM_HANGUP_NOW 2 +#define RFCOMM_TTY_ATTACHED 3 + +struct rfcomm_dev_req { + s16 dev_id; + u32 flags; + bdaddr_t src; + bdaddr_t dst; + u8 channel; +}; + +struct rfcomm_dev_info { + s16 id; + u32 flags; + u16 state; + bdaddr_t src; + bdaddr_t dst; + u8 channel; +}; + +struct rfcomm_dev_list_req { + u16 dev_num; + struct rfcomm_dev_info dev_info[0]; +}; + +int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg); +int rfcomm_init_ttys(void); +void rfcomm_cleanup_ttys(void); + +#endif /* __RFCOMM_H */ diff -Naurp linux-2.4.20-wolk4.1s/include/net/ip_vs.h linux-2.4.20-wolk4.2-fullkernel/include/net/ip_vs.h --- linux-2.4.20-wolk4.1s/include/net/ip_vs.h 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/include/net/ip_vs.h 2003-06-03 11:55:34.000000000 +0200 @@ -8,7 +8,7 @@ #include /* For __uXX types */ -#define IP_VS_VERSION_CODE 0x010008 +#define IP_VS_VERSION_CODE 0x010009 #define NVERSION(version) \ (version >> 16) & 0xFF, \ (version >> 8) & 0xFF, \ diff -Naurp linux-2.4.20-wolk4.1s/include/pcmcia/ciscode.h linux-2.4.20-wolk4.2-fullkernel/include/pcmcia/ciscode.h --- linux-2.4.20-wolk4.1s/include/pcmcia/ciscode.h 2001-12-21 18:42:04.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/include/pcmcia/ciscode.h 2003-06-03 20:02:49.000000000 +0200 @@ -1,5 +1,5 @@ /* - * ciscode.h 1.48 2001/08/24 12:16:12 + * ciscode.h 1.57 2002/11/03 20:38:14 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -60,6 +60,10 @@ #define PRODID_INTEL_DUAL_RS232 0x0301 #define PRODID_INTEL_2PLUS 0x8422 +#define MANFID_KME 0x0032 +#define PRODID_KME_KXLC005_A 0x0704 +#define PRODID_KME_KXLC005_B 0x2904 + #define MANFID_LINKSYS 0x0143 #define PRODID_LINKSYS_PCMLM28 0xc0ab #define PRODID_LINKSYS_3400 0x3341 @@ -94,6 +98,8 @@ #define PRODID_OSITECH_JACK_336 0x0007 #define PRODID_OSITECH_SEVEN 0x0008 +#define MANFID_OXSEMI 0x0279 + #define MANFID_PIONEER 0x000b #define MANFID_PSION 0x016c @@ -103,6 +109,7 @@ #define PRODID_QUATECH_SPP100 0x0003 #define PRODID_QUATECH_DUAL_RS232 0x0012 #define PRODID_QUATECH_DUAL_RS232_D1 0x0007 +#define PRODID_QUATECH_DUAL_RS232_D2 0x0052 #define PRODID_QUATECH_QUAD_RS232 0x001b #define PRODID_QUATECH_DUAL_RS422 0x000e #define PRODID_QUATECH_QUAD_RS422 0x0045 @@ -120,9 +127,12 @@ #define MANFID_TDK 0x0105 #define PRODID_TDK_CF010 0x0900 +#define PRODID_TDK_GN3410 0x4815 #define MANFID_TOSHIBA 0x0098 +#define MANFID_UNGERMANN 0x02c0 + #define MANFID_XIRCOM 0x0105 #endif /* _LINUX_CISCODE_H */ diff -Naurp linux-2.4.20-wolk4.1s/include/scsi/scsimon.h linux-2.4.20-wolk4.2-fullkernel/include/scsi/scsimon.h --- linux-2.4.20-wolk4.1s/include/scsi/scsimon.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/include/scsi/scsimon.h 2003-06-02 17:23:43.000000000 +0200 @@ -0,0 +1,136 @@ +#ifndef _SCSI_SCSIMON_H +#define _SCSI_SCSIMON_H + +/* + SCSI upper level driver that permits user applications to monitor + the state of SCSI devices and hosts. The original purpose of this + driver is to support hotplugging notification. + +* Copyright (C) 2001 Douglas Gilbert + + Version: 0.0.92 (20010313) + Initial version + +*/ + +/* Use [c 10 247] ("misc" char device, minor 247) with the device name: + /dev/scsimon [/dev/misc/scsimon under devfs]. This is unofficial, + need allocation in Documentation/devices.txt . [This driver was + called "scsiinfo" < version 0.0.92 and used misc minor number 210 .] */ +#define SCSIMON_MINOR 247 + + +/* Borrow ioctl numbers from sg driver, starting at 0x22a0 */ +/* Third argument of ioctls is "int *" unless otherwise noted */ + +/* Ignored 3rd argument */ +#define SCSIMON_LOCK_MOD 0x22a0 +#define SCSIMON_UNLOCK_MOD 0x22a1 + +#define SCSIMON_GET_VERSION_NUM 0x22a2 + +/* 3rd argument assumed to be pointer to struct scsimon_state object */ +#define SCSIMON_GET_STATE 0x22a3 + +/* Maximum number of elements kept in detached device list [default: 10] */ +#define SCSIMON_SET_MX_DLIST_LEN 0x22a4 +#define SCSIMON_GET_MX_DLIST_LEN 0x22a5 + +/* Major ioctls to access lists of attached devices, detached devices and + hosts. The third argument is a pointer to an object of type + 'struct scsimon_[att | det | host]_list' with enough space to accommodate + 'max_num' elements of the array which is the last member of these structs */ +#define SCSIMON_GET_ATT_LIST 0x22a6 +#define SCSIMON_GET_DET_LIST 0x22a7 +#define SCSIMON_GET_HOST_LIST 0x22a8 + + +struct scsimon_state { + struct timespec init_time; /* time since boot that this driver loaded */ + unsigned int devices_attached; /* which is also device list length */ + unsigned int total_attachs; + unsigned int total_detachs; + unsigned int detach_list_len; + int count_hosts; /* host numbers not necessarily consecutive */ + unsigned int high_host; /* highest host number */ + unsigned long event_count; + int lock_mod_state; /* 0 -> module not locked down */ +}; + +/* Note: the attach event count represents a unique key by which the + "session" of an attached device can be identified */ + +struct scsimon_device { + unsigned int host; + unsigned int bus; + unsigned int target; + unsigned int lun; + char vendor[8]; /* from INQUIRY during mid level scan */ + char model[16]; + char rev[4]; + char scsi_type; + char scsi_level; + char removable; + char emulated; + /* more here ?? */ + char dummy[16]; +}; + +struct scsimon_host { + unsigned int host; + int host_scsi_id; + char host_name[16]; + char host_info[80]; + char emulated; + char is_module; + /* more here ?? */ + char dummy[16]; +}; + +struct scsimon_att_dev { /* attached device info */ + struct timespec att_time; /* time since boot that this device attached */ + unsigned long att_event; /* event count of attach */ + struct scsimon_device d; +}; + +struct scsimon_det_dev { /* detached device info */ + struct timespec det_time; /* time since boot that this device attached */ + unsigned long det_event; + unsigned long att_event; + char host_name[12]; + char host_info[80]; + struct scsimon_device d; +}; + +struct scsimon_att_list { + unsigned long match_event; /* [i] 0 -> get max_num, otherwise get match */ + int flags; /* [i] 0 at the moment */ + int max_num; /* [i] app must allocate enough space ... */ + unsigned long curr_event; /* [o] event number at time of call */ + int num_out; /* [o] actual number output */ + struct scsimon_att_dev arr[1]; /* [o] must be space for max_num elems */ +}; + +struct scsimon_det_list { + unsigned long match_event; /* [i] 0 -> get max_num, otherwise get */ + /* match (on att_event) */ + int flags; /* [i] 0 at the moment */ + int max_num; /* [i] app must allocate enough space ... */ + unsigned long curr_event; /* [o] event number at time of call */ + int num_out; /* [o] actual number output */ + struct scsimon_det_dev arr[1]; /* [o] must be space for max_num elems */ +}; + +#define SCSIMON_HOST_FLAG_ALL 0 /* fetch up to max_num hosts */ +#define SCSIMON_HOST_FLAG_MATCH 1 /* fetch 'host' (when max_num >= 1) */ + +struct scsimon_host_list { + unsigned int host; /* [i] used if SCSIMON_HOST_FLAG_MATCH set */ + int flags; /* [i] see SCSIMON_HOST_FLAG... values */ + int max_num; /* [i] app must allocate enough space ... */ + unsigned long curr_event; /* [o] event number at time of call */ + int num_out; /* [o] actual number output */ + struct scsimon_host arr[1]; /* [o] must be space for max_num elems */ +}; + +#endif diff -Naurp linux-2.4.20-wolk4.1s/include/scsi/sg.h linux-2.4.20-wolk4.2-fullkernel/include/scsi/sg.h --- linux-2.4.20-wolk4.1s/include/scsi/sg.h 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/include/scsi/sg.h 2003-06-02 17:23:46.000000000 +0200 @@ -9,11 +9,13 @@ Original driver (sg.h): * Copyright (C) 1992 Lawrence Foard Version 2 and 3 extensions to driver: -* Copyright (C) 1998 - 2002 Douglas Gilbert +* Copyright (C) 1998 - 2003 Douglas Gilbert - Version: 3.1.24 (20020505) + Version: 3.1.25 (20030529) This version is for 2.4 series kernels. + Changes since 3.1.24 (20020505) + - fix side effect introduced by last "off by one" fix Changes since 3.1.23 (20020318) - off by one fix for last scatter gather element - zero buffer obtained for non-root users diff -Naurp linux-2.4.20-wolk4.1s/init/do_mounts.c linux-2.4.20-wolk4.2-fullkernel/init/do_mounts.c --- linux-2.4.20-wolk4.1s/init/do_mounts.c 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/init/do_mounts.c 2003-06-02 17:19:16.000000000 +0200 @@ -383,13 +383,11 @@ retry: * Allow the user to distinguish between failed open * and bad superblock on root device. */ - printk ("VFS: Cannot open root device \"%s\" or %s, retrying in 1s.\n", + printk ("VFS: Cannot open root device \"%s\" or %s\n", root_device_name, kdevname (ROOT_DEV)); - - /* wait 1 second and try again */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(HZ); - goto retry; + printk ("Please append a correct \"root=\" boot option\n"); + panic("VFS: Unable to mount root fs on %s", + kdevname(ROOT_DEV)); } panic("VFS: Unable to mount root fs on %s", kdevname(ROOT_DEV)); out: diff -Naurp linux-2.4.20-wolk4.1s/init/main.c linux-2.4.20-wolk4.2-fullkernel/init/main.c --- linux-2.4.20-wolk4.1s/init/main.c 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/init/main.c 2003-06-02 17:24:46.000000000 +0200 @@ -160,7 +160,9 @@ extern void softirq_init(void); int rows, cols; -static char * argv_init[MAX_INIT_ARGS+2] = { NULL, NULL }; +char *execute_command; + +static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; static int __init profile_setup(char *str) @@ -302,7 +304,7 @@ static void __init parse_options(char *l if (!*line) return; - args = 1; + args = 0; envs = 1; /* TERM is set to 'linux' by default */ oenvs = envs; next = line; @@ -353,13 +355,13 @@ static void __init parse_options(char *l #endif /* CONFIG_KDB */ if (!strncmp(line,"init=",5)) { line += 5; - argv_init[0] = line; + execute_command = line; /* In case LILO is going to boot us with default command line, * it prepends "auto" before the whole cmdline which makes * the shell think it should execute a script with such name. * So we ignore all arguments entered _before_ init=... [MJ] */ - args = 1; + args = 0; continue; } if (checksetup(line)) @@ -575,7 +577,7 @@ asmlinkage void __init start_kernel(void /* * We want to tell the user we are RMAPed. */ - printk("RMAP: reverse mapping based VM v15i initialized. (C) 2003, Rik van Riel.\n"); + printk("RMAP: reverse mapping based VM v15j initialized. (C) 2003, Rik van Riel.\n"); /* * We want to tell the user that we are doing lowlatency.. @@ -756,12 +758,6 @@ static void __init do_basic_setup(void) extern void prepare_namespace(void); -static void run_init_process(char *execute_command) -{ - argv_init[0] = execute_command; - execve(execute_command, argv_init, envp_init); -} - static int init(void * unused) { lock_kernel(); @@ -809,13 +805,11 @@ static int init(void * unused) * trying to recover a really broken machine. */ - if (argv_init[0]) { - run_init_process(argv_init[0]); - } - run_init_process("/sbin/init"); - run_init_process("/etc/init"); - run_init_process("/bin/init"); - run_init_process("/bin/sh"); - run_init_process("/sbin/sash"); + if (execute_command) + execve(execute_command,argv_init,envp_init); + execve("/sbin/init",argv_init,envp_init); + execve("/etc/init",argv_init,envp_init); + execve("/bin/init",argv_init,envp_init); + execve("/bin/sh",argv_init,envp_init); panic("No init found. Try passing init= option to kernel."); } diff -Naurp linux-2.4.20-wolk4.1s/init/version.c linux-2.4.20-wolk4.2-fullkernel/init/version.c --- linux-2.4.20-wolk4.1s/init/version.c 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/init/version.c 2003-06-04 11:30:25.000000000 +0200 @@ -26,7 +26,7 @@ struct new_utsname system_utsname = { }; const char *wolk_banner = - "WOLK - Working Overloaded Linux Kernel - v4.0 - Server Edition""\n\n"; + "WOLK - Working Overloaded Linux Kernel - v4.2 - Server Edition""\n\n"; const char *linux_banner = "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" diff -Naurp linux-2.4.20-wolk4.1s/kernel/exit.c linux-2.4.20-wolk4.2-fullkernel/kernel/exit.c --- linux-2.4.20-wolk4.1s/kernel/exit.c 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/kernel/exit.c 2003-06-02 17:36:21.000000000 +0200 @@ -167,14 +167,12 @@ static inline int has_stopped_jobs(int p */ void reparent_to_init(void) { - struct task_struct *this_task = current; - write_lock_irq(&tasklist_lock); #ifdef CONFIG_GRKERNSEC - if (this_task->exec_file) { - fput(this_task->exec_file); - this_task->exec_file = NULL; + if (current->exec_file) { + fput(current->exec_file); + current->exec_file = NULL; } #endif @@ -184,7 +182,7 @@ void reparent_to_init(void) current->p_opptr = child_reaper; SET_LINKS(current); - gr_set_kernel_label(this_task); + gr_set_kernel_label(current); /* Set the exit signal to SIGCHLD so we signal init on exit */ current->exit_signal = SIGCHLD; diff -Naurp linux-2.4.20-wolk4.1s/kernel/ksyms.c linux-2.4.20-wolk4.2-fullkernel/kernel/ksyms.c --- linux-2.4.20-wolk4.1s/kernel/ksyms.c 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/kernel/ksyms.c 2003-06-05 23:30:57.000000000 +0200 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -128,6 +129,8 @@ EXPORT_SYMBOL(kmem_cache_shrink); EXPORT_SYMBOL(kmem_cache_alloc); EXPORT_SYMBOL(kmem_cache_free); EXPORT_SYMBOL(kmem_cache_size); +EXPORT_SYMBOL_GPL(register_cache); +EXPORT_SYMBOL_GPL(unregister_cache); EXPORT_SYMBOL(kmalloc); EXPORT_SYMBOL(kfree); EXPORT_SYMBOL(vfree); diff -Naurp linux-2.4.20-wolk4.1s/kernel/module.c linux-2.4.20-wolk4.2-fullkernel/kernel/module.c --- linux-2.4.20-wolk4.1s/kernel/module.c 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/kernel/module.c 2003-06-02 17:23:44.000000000 +0200 @@ -382,10 +382,10 @@ err0: asmlinkage long sys_init_module(const char *name_user, struct module *mod_user) { - struct module mod_tmp, *mod; + struct module mod_tmp, *mod, *mod2 = NULL; char *name, *n_name, *name_tmp = NULL; long namelen, n_namelen, i, error; - unsigned long mod_user_size; + unsigned long mod_user_size, flags; struct module_ref *dep; /* RSBAC */ @@ -431,11 +431,23 @@ sys_init_module(const char *name_user, s } strcpy(name_tmp, mod->name); - error = copy_from_user(mod, mod_user, mod_user_size); + /* Copying mod_user directly over mod breaks the module_list chain and + * races against search_exception_table. copy_from_user may sleep so it + * cannot be under modlist_lock, do the copy in two stages. + */ + if (!(mod2 = vmalloc(mod_user_size))) { + error = -ENOMEM; + goto err2; + } + error = copy_from_user(mod2, mod_user, mod_user_size); if (error) { error = -EFAULT; goto err2; } + spin_lock_irqsave(&modlist_lock, flags); + memcpy(mod, mod2, mod_user_size); + mod->next = mod_tmp.next; + spin_unlock_irqrestore(&modlist_lock, flags); /* Sanity check the size of the module. */ error = -EINVAL; @@ -571,7 +583,6 @@ sys_init_module(const char *name_user, s to make the I and D caches consistent. */ flush_icache_range((unsigned long)mod, (unsigned long)mod + mod->size); - mod->next = mod_tmp.next; mod->refs = NULL; /* Sanity check the module's dependents */ @@ -635,6 +646,8 @@ sys_init_module(const char *name_user, s err3: put_mod_name(n_name); err2: + if (mod2) + vfree(mod2); *mod = mod_tmp; strcpy((char *)mod->name, name_tmp); /* We know there is room for this */ err1: diff -Naurp linux-2.4.20-wolk4.1s/kernel/ptrace.c linux-2.4.20-wolk4.2-fullkernel/kernel/ptrace.c --- linux-2.4.20-wolk4.1s/kernel/ptrace.c 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/kernel/ptrace.c 2003-06-02 17:04:28.000000000 +0200 @@ -21,7 +21,6 @@ */ int ptrace_check_attach(struct task_struct *child, int kill) { - if (!(child->ptrace & PT_PTRACED)) return -ESRCH; diff -Naurp linux-2.4.20-wolk4.1s/kernel/sched.c linux-2.4.20-wolk4.2-fullkernel/kernel/sched.c --- linux-2.4.20-wolk4.1s/kernel/sched.c 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/kernel/sched.c 2003-06-03 20:45:38.000000000 +0200 @@ -59,29 +59,41 @@ #if defined (CONFIG_SCHED_DESKTOP) #warning INFO: Desktop Scheduler Tweaks will be used. -#define MIN_TIMESLICE ( 10 * HZ / 1000) -#define MAX_TIMESLICE ( 10 * HZ / 1000) -#define CHILD_PENALTY 95 -#define PARENT_PENALTY 100 -#define PRIO_BONUS_RATIO 25 -#define INTERACTIVE_DELTA 2 -#define MAX_SLEEP_AVG (2*HZ) -#define STARVATION_LIMIT (2*HZ) +int min_timeslice = (( 10 * HZ) / 1000 ?: 1); +int max_timeslice = ( 40 * HZ) / 1000; +int child_penalty = 95; +int parent_penalty = 100; +int exit_weight = 3; +int prio_bonus_ratio = 25; +int interactive_delta = 2; +int max_sleep_avg = 2 * HZ; +int starvation_limit = 2 * HZ; #elif defined (CONFIG_SCHED_SERVER) || (!defined (CONFIG_SCHED_DESKTOP) && !defined (CONFIG_SCHED_SERVER)) #warning INFO: Server Scheduler Tweaks will be used. -#define MIN_TIMESLICE ( 10 * HZ / 1000) -#define MAX_TIMESLICE (200 * HZ / 1000) -#define CHILD_PENALTY 50 -#define PARENT_PENALTY 100 -#define PRIO_BONUS_RATIO 25 -#define INTERACTIVE_DELTA 2 -#define MAX_SLEEP_AVG (2*HZ) -#define STARVATION_LIMIT (2*HZ) +int min_timeslice = (( 10 * HZ) / 1000 ?: 1); +int max_timeslice = ( 200 * HZ) / 1000; +int child_penalty = 50; +int parent_penalty = 100; +int exit_weight = 3; +int prio_bonus_ratio = 25; +int interactive_delta = 2; +int max_sleep_avg = 2 * HZ; +int starvation_limit = 2 * HZ; #endif /* CONFIG_SCHED_SERVER */ +#define MIN_TIMESLICE (min_timeslice) +#define MAX_TIMESLICE (max_timeslice) +#define CHILD_PENALTY (child_penalty) +#define PARENT_PENALTY (parent_penalty) +#define EXIT_WEIGHT (exit_weight) +#define PRIO_BONUS_RATIO (prio_bonus_ratio) +#define INTERACTIVE_DELTA (interactive_delta) +#define MAX_SLEEP_AVG (max_sleep_avg) +#define STARVATION_LIMIT (starvation_limit) + /* * If a task is 'interactive' then we reinsert it in the active * array after it has expired its current timeslice. (it will not @@ -560,7 +572,7 @@ inline int idle_cpu(int cpu) return cpu_curr(cpu) == cpu_rq(cpu)->idle; } -#if CONFIG_SMP +#ifdef CONFIG_SMP /* * Lock the busiest runqueue as well, this_rq is locked already. * Recalculate nr_running if we have to drop the runqueue lock. @@ -847,7 +859,7 @@ void scheduler_tick(int user_tick, int s if (p == rq->idle) { if (local_bh_count(cpu) || local_irq_count(cpu) > 1) kstat.per_cpu_system[cpu] += system; -#if CONFIG_SMP +#ifdef CONFIG_SMP idle_tick(); #endif return; @@ -924,7 +936,7 @@ void scheduler_tick(int user_tick, int s enqueue_task(p, rq->active); } out: -#if CONFIG_SMP +#ifdef CONFIG_SMP if (unlikely(time_before_eq(this_rq()->last_jiffy + BUSY_REBALANCE_TICK, jiffies))) { load_balance(rq, 0); rq->last_jiffy = jiffies; @@ -978,7 +990,7 @@ need_resched: } pick_next_task: if (unlikely(!rq->nr_running)) { -#if CONFIG_SMP +#ifdef CONFIG_SMP load_balance(rq, 2); rq->last_jiffy = jiffies; if (rq->nr_running) @@ -1159,8 +1171,6 @@ void __wake_up(wait_queue_head_t *q, uns wq_read_unlock_irqrestore(&q->lock, flags); } -#if CONFIG_SMP - void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) { unsigned long flags; @@ -1175,8 +1185,6 @@ void __wake_up_sync(wait_queue_head_t *q __wake_up_common(q, mode, nr_exclusive, 0); wq_read_unlock_irqrestore(&q->lock, flags); } - -#endif void complete(struct completion *x) { @@ -1385,6 +1393,7 @@ static int setscheduler(pid_t pid, int p runqueue_t *rq; int retval; task_t *p; + int oldprio; retval = -EINVAL; if (!param || pid < 0) @@ -1444,12 +1453,20 @@ static int setscheduler(pid_t pid, int p retval = 0; p->policy = policy; p->rt_priority = lp.sched_priority; + oldprio = p->prio; if (policy != SCHED_OTHER) p->prio = MAX_RT_PRIO-1 - p->rt_priority; else p->prio = p->static_prio; - if (array) + if (array) { activate_task(p, task_rq(p)); + /* + * Reschedule if on a CPU and the priority dropped, or not on + * a CPU and the priority rose above the currently running task. + */ + if ((rq->curr == p) ? (p->prio > oldprio) : (p->prio < rq->curr->prio)) + resched_task(rq->curr); + } out_unlock: task_rq_unlock(rq, &flags); @@ -1632,72 +1649,6 @@ int sysctl_sched_yield_scale = 0; int sysctl_sched_yield_scale = 1; #endif -/* - * sys_sched_hint - give the scheduler a hint to (hopefully) provide - * better scheduling behavior. For example, if a task is about - * to acquire a highly contended resource, it would be wise to - * increase its remaining timeslice to ensure it could drop the - * resource before being preempted. - * - * `hint' is the hint to the scheduler, defined in include/linux/sched.h - */ -asmlinkage int sys_sched_hint(unsigned long hint) -{ - int ret = -EINVAL; - unsigned long flags; - runqueue_t *rq; - - /* - * Requiring CAP_SYS_NICE is an issue: we really want any task - * to be able to give the scheduler a `hint' but we have no - * way of ensuring fairness. The compromise is to require - * some sort of permission... you may want to get rid of this. - * - * Also allow users within a special GID to change their nice - * value to a negative value. -mcp- - */ - -#ifndef CONFIG_RENICE_USER - if (!capable(CAP_SYS_NICE)) -#else - if (!capable(CAP_SYS_NICE) && !in_group_p(renice_gid)) -#endif - return -EPERM; - - rq = task_rq_lock(current, &flags); - - if (hint & HINT_TIME) { - current->time_slice = MAX_TIMESLICE; - /* - * we may have run out of timeslice and have been - * put on the expired runqueue: if so, fix that. - */ - if (unlikely(current->array != rq->active)) { - dequeue_task(current, current->array); - enqueue_task(current, rq->active); - } - ret = 0; - } - - if (hint & HINT_INTERACTIVE) { - dequeue_task(current, current->array); - current->sleep_avg = MAX_SLEEP_AVG; - current->prio = effective_prio(current); - enqueue_task(current, rq->active); - ret = 0; - } else if (hint & HINT_BATCH) { - dequeue_task(current, current->array); - current->sleep_avg = 0; - current->prio = effective_prio(current); - enqueue_task(current, rq->active); - ret = 0; - } - - task_rq_unlock(rq, &flags); - - return ret; -} - asmlinkage long sys_sched_yield(void) { runqueue_t *rq = this_rq(); @@ -2033,7 +1984,7 @@ static int kdog_thread(void * data) sigfillset(¤t->blocked); set_fs(KERNEL_DS); -#if CONFIG_SMP +#ifdef CONFIG_SMP /* * Either we are running on the right CPU, or there's a * a migration thread on the target CPU, guaranteed. @@ -2117,7 +2068,7 @@ void __init sched_init(void) enter_lazy_tlb(&init_mm, current, smp_processor_id()); } -#if CONFIG_SMP +#ifdef CONFIG_SMP /* * This is how migration works: @@ -2220,7 +2171,7 @@ static int migration_thread(void * bind_ rq = this_rq(); rq->migration_thread = current; - sprintf(current->comm, "migration_CPU%d", smp_processor_id()); + sprintf(current->comm, "migration/%d", smp_processor_id()); for (;;) { runqueue_t *rq_src, *rq_dest; diff -Naurp linux-2.4.20-wolk4.1s/kernel/signal.c linux-2.4.20-wolk4.2-fullkernel/kernel/signal.c --- linux-2.4.20-wolk4.1s/kernel/signal.c 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/kernel/signal.c 2003-06-02 17:23:44.000000000 +0200 @@ -967,11 +967,13 @@ sys_rt_sigprocmask(int how, sigset_t *se break; } + if (error) { + spin_unlock_irq(¤t->sigmask_lock); + goto out; + } current->blocked = new_set; recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); - if (error) - goto out; if (oset) goto set_old; } else if (oset) { diff -Naurp linux-2.4.20-wolk4.1s/kernel/softirq.c linux-2.4.20-wolk4.2-fullkernel/kernel/softirq.c --- linux-2.4.20-wolk4.1s/kernel/softirq.c 2003-05-20 09:56:54.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/kernel/softirq.c 2003-06-02 17:23:42.000000000 +0200 @@ -58,12 +58,32 @@ static inline void wakeup_softirqd(unsig wake_up_process(tsk); } +static inline int softirqd_is_waken(unsigned cpu) +{ + struct task_struct * tsk = ksoftirqd_task(cpu); + + return tsk && tsk->state == TASK_RUNNING; +} + +/* + * the higher this number the less likely ksoftirqd will be waken by + * a short irq flood peak, but the higher unfariness the softirq load + * will generate against the regular scheduler tasks. + * Each loop will allow one more block to pass through to the + * higher layer. If further blocks keeps arriving we giveup and we + * offload the work in a scheduler friendly way. After ksoftirqd + * is started we will stop wasting time here, so under attack + * we're still competely fair. + */ +#define MAX_SOFTIRQ_LOOPS 8 + asmlinkage void do_softirq() { int cpu; __u32 pending; unsigned long flags; __u32 mask; + int loops; if (in_interrupt()) return; @@ -74,6 +94,7 @@ asmlinkage void do_softirq() pending = softirq_pending(cpu); + loops = 0; if (pending) { struct softirq_action *h; @@ -103,8 +124,16 @@ restart: } __local_bh_enable(); - if (pending) - wakeup_softirqd(cpu); + if (!softirqd_is_waken(cpu)) { + if (unlikely(++loops >= MAX_SOFTIRQ_LOOPS)) { + if (pending) + wakeup_softirqd(cpu); + } else { + mask = ~pending; + local_bh_disable(); + goto restart; + } + } } local_irq_restore(flags); @@ -374,8 +403,7 @@ static int ksoftirqd(void * __bind_cpu) /* Migrate to the right CPU */ set_cpus_allowed(current, 1UL << cpu); - if (cpu() != cpu) - BUG(); + BUG_ON(cpu() != cpu); sprintf(current->comm, "ksoftirqd/%d", bind_cpu); diff -Naurp linux-2.4.20-wolk4.1s/kernel/sysctl.c linux-2.4.20-wolk4.2-fullkernel/kernel/sysctl.c --- linux-2.4.20-wolk4.1s/kernel/sysctl.c 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/kernel/sysctl.c 2003-06-03 20:45:38.000000000 +0200 @@ -75,6 +75,17 @@ extern int cad_pid; extern int sysctl_sched_yield_scale; extern int allow_setid_core; +/* Tunable scheduler parameters */ +extern int min_timeslice; +extern int max_timeslice; +extern int child_penalty; +extern int parent_penalty; +extern int exit_weight; +extern int prio_bonus_ratio; +extern int interactive_delta; +extern int max_sleep_avg; +extern int starvation_limit; + /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ static int maxolduid = 65535; static int minolduid; @@ -146,6 +157,7 @@ static struct ctl_table_header root_tabl static ctl_table kern_table[]; static ctl_table vm_table[]; +static ctl_table sched_table[]; #ifdef CONFIG_NET extern ctl_table net_table[]; #endif @@ -192,6 +204,7 @@ static ctl_table root_table[] = { {CTL_FS, "fs", NULL, 0, 0555, fs_table}, {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table}, {CTL_DEV, "dev", NULL, 0, 0555, dev_table}, + {CTL_SCHED, "sched", NULL, 0, 0555, sched_table}, {0} }; @@ -593,6 +606,40 @@ static ctl_table dev_table[] = { {0} }; +static int zero = 0; +static int one = 1; + +static ctl_table sched_table[] = { + {SCHED_MAX_TIMESLICE, "max_timeslice", &max_timeslice, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &one, NULL}, + {SCHED_MIN_TIMESLICE, "min_timeslice", &min_timeslice, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &one, NULL}, + {SCHED_CHILD_PENALTY, "child_penalty", &child_penalty, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &zero, NULL}, + {SCHED_PARENT_PENALTY, "parent_penalty", &parent_penalty, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &zero, NULL}, + {SCHED_EXIT_WEIGHT, "exit_weight", &exit_weight, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &zero, NULL}, + {SCHED_PRIO_BONUS_RATIO, "prio_bonus_ratio", &prio_bonus_ratio, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &zero, NULL}, + {SCHED_INTERACTIVE_DELTA, "interactive_delta", &interactive_delta, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &zero, NULL}, + {SCHED_MAX_SLEEP_AVG, "max_sleep_avg", &max_sleep_avg, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &one, NULL}, + {SCHED_STARVATION_LIMIT, "starvation_limit", &starvation_limit, + sizeof(int), 0644, NULL, &proc_dointvec_minmax, + &sysctl_intvec, NULL, &zero, NULL}, + {0} +}; + extern void init_irq_proc (void); void __init sysctl_init(void) diff -Naurp linux-2.4.20-wolk4.1s/mm/Makefile linux-2.4.20-wolk4.2-fullkernel/mm/Makefile --- linux-2.4.20-wolk4.1s/mm/Makefile 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/mm/Makefile 2003-06-02 17:31:54.000000000 +0200 @@ -23,13 +23,13 @@ endif obj-$(CONFIG_HIGHMEM) += highmem.o obj-$(CONFIG_BIGPHYS_AREA) += bigphysarea.o -obj-y += wtd.o - ifeq ($(CONFIG_MEMORYPOOL),y) obj-y += mempool.o export-objs += mempool.o endif +obj-y += wtd.o + ifeq ($(CONFIG_BADMEM),y) ifeq ($(CONFIG_BADMEM_PROCFS),y) ifeq ($(CONFIG_PROC_FS),y) diff -Naurp linux-2.4.20-wolk4.1s/mm/highmem.c linux-2.4.20-wolk4.2-fullkernel/mm/highmem.c --- linux-2.4.20-wolk4.1s/mm/highmem.c 2003-05-20 09:56:55.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/mm/highmem.c 2003-06-02 17:14:08.000000000 +0200 @@ -21,6 +21,7 @@ #include #include #include +#include /* * Virtual_count is not a pure "count". @@ -211,6 +212,14 @@ static LIST_HEAD(emergency_pages); int nr_emergency_bhs; static LIST_HEAD(emergency_bhs); +int nr_atomic_emergency_pages; +static LIST_HEAD(atomic_emergency_pages); + +int nr_atomic_emergency_bhs; +static LIST_HEAD(atomic_emergency_bhs); + +int atomic_emergency_owner; + /* * Simple bounce buffer support for highmem pages. * This will be moved to the block layer in 2.5. @@ -250,35 +259,66 @@ static inline void bounce_end_io (struct struct page *page; struct buffer_head *bh_orig = (struct buffer_head *)(bh->b_private); unsigned long flags; + int atomic = bh_elv_seq(bh); bh_orig->b_end_io(bh_orig, uptodate); page = bh->b_page; spin_lock_irqsave(&emergency_lock, flags); - if (nr_emergency_pages >= POOL_SIZE) - __free_page(page); - else { - /* - * We are abusing page->list to manage - * the highmem emergency pool: - */ - list_add(&page->list, &emergency_pages); - nr_emergency_pages++; - } - - if (nr_emergency_bhs >= POOL_SIZE) { + if (!atomic) { + if (nr_emergency_pages >= POOL_SIZE) + __free_page(page); + else { + /* + * We are abusing page->list to manage + * the highmem emergency pool: + */ + list_add(&page->list, &emergency_pages); + nr_emergency_pages++; + } + + if (nr_emergency_bhs >= POOL_SIZE) { #ifdef HIGHMEM_DEBUG - /* Don't clobber the constructed slab cache */ - init_waitqueue_head(&bh->b_wait); + /* Don't clobber the constructed slab cache */ + init_waitqueue_head(&bh->b_wait); #endif - kmem_cache_free(bh_cachep, bh); + kmem_cache_free(bh_cachep, bh); + } else { + /* + * Ditto in the bh case, here we abuse b_inode_buffers: + */ + list_add(&bh->b_inode_buffers, &emergency_bhs); + nr_emergency_bhs++; + } } else { - /* - * Ditto in the bh case, here we abuse b_inode_buffers: - */ - list_add(&bh->b_inode_buffers, &emergency_bhs); - nr_emergency_bhs++; + if (nr_atomic_emergency_pages >= BLK_ATOMIC_BOUNCE_ENTRIES) + __free_page(page); + else { + /* + * We are abusing page->list to manage + * the highmem emergency pool: + */ + list_add(&page->list, &atomic_emergency_pages); + nr_atomic_emergency_pages++; + } + + if (nr_atomic_emergency_bhs >= BLK_ATOMIC_BOUNCE_ENTRIES) { +#ifdef HIGHMEM_DEBUG + /* Don't clobber the constructed slab cache */ + init_waitqueue_head(&bh->b_wait); +#endif + kmem_cache_free(bh_cachep, bh); + } else { + /* + * Ditto in the bh case, here we abuse b_inode_buffers: + */ + list_add(&bh->b_inode_buffers, &atomic_emergency_bhs); + nr_atomic_emergency_bhs++; + } + BUG_ON(nr_atomic_emergency_pages != nr_atomic_emergency_bhs); + if (nr_atomic_emergency_pages >= BLK_ATOMIC_BOUNCE_ENTRIES) + atomic_emergency_owner = 0; } spin_unlock_irqrestore(&emergency_lock, flags); } @@ -311,6 +351,24 @@ static __init int init_emergency_pool(vo list_add(&bh->b_inode_buffers, &emergency_bhs); nr_emergency_bhs++; } + while (nr_atomic_emergency_pages < BLK_ATOMIC_BOUNCE_ENTRIES) { + struct page * page = alloc_page(GFP_ATOMIC); + if (!page) { + printk("couldn't refill highmem emergency pages"); + break; + } + list_add(&page->list, &atomic_emergency_pages); + nr_atomic_emergency_pages++; + } + while (nr_atomic_emergency_bhs < BLK_ATOMIC_BOUNCE_ENTRIES) { + struct buffer_head * bh = kmem_cache_alloc(bh_cachep, SLAB_ATOMIC); + if (!bh) { + printk("couldn't refill highmem emergency bhs"); + break; + } + list_add(&bh->b_inode_buffers, &atomic_emergency_bhs); + nr_atomic_emergency_bhs++; + } spin_unlock_irq(&emergency_lock); printk("allocated %d pages and %d bhs reserved for the highmem bounces\n", nr_emergency_pages, nr_emergency_bhs); @@ -334,7 +392,7 @@ static void bounce_end_io_read (struct b bounce_end_io(bh, uptodate); } -struct page *alloc_bounce_page (void) +struct page *alloc_bounce_page (int atomic) { struct list_head *tmp; struct page *page = NULL; @@ -366,17 +424,30 @@ repeat_alloc: /* * Try to allocate from the emergency pool. */ - tmp = &emergency_pages; spin_lock_irq(&emergency_lock); - if (!list_empty(tmp)) { - page = list_entry(tmp->next, struct page, list); - list_del(tmp->next); - nr_emergency_pages--; + if (!atomic) { + tmp = &emergency_pages; + if (!list_empty(tmp)) { + page = list_entry(tmp->next, struct page, list); + list_del(tmp->next); + nr_emergency_pages--; + } + } else { + tmp = &atomic_emergency_pages; + if ((!atomic_emergency_owner || atomic_emergency_owner == atomic) && + !list_empty(tmp)) { + page = list_entry(tmp->next, struct page, list); + list_del(tmp->next); + nr_atomic_emergency_pages--; + atomic_emergency_owner = atomic; + } } spin_unlock_irq(&emergency_lock); if (page) return page; + if (atomic) + blk_refile_atomic_queue(atomic); /* we need to wait I/O completion */ run_task_queue(&tq_disk); @@ -385,7 +456,7 @@ repeat_alloc: goto repeat_alloc; } -struct buffer_head *alloc_bounce_bh (void) +struct buffer_head *alloc_bounce_bh (int atomic) { struct list_head *tmp; struct buffer_head *bh = NULL; @@ -417,17 +488,31 @@ repeat_alloc: /* * Try to allocate from the emergency pool. */ - tmp = &emergency_bhs; spin_lock_irq(&emergency_lock); - if (!list_empty(tmp)) { - bh = list_entry(tmp->next, struct buffer_head, b_inode_buffers); - list_del(tmp->next); - nr_emergency_bhs--; + if (!atomic) { + tmp = &emergency_bhs; + if (!list_empty(tmp)) { + bh = list_entry(tmp->next, struct buffer_head, b_inode_buffers); + list_del(tmp->next); + nr_emergency_bhs--; + } + } else { + tmp = &atomic_emergency_bhs; + if ((!atomic_emergency_owner || atomic_emergency_owner == atomic) && + !list_empty(tmp)) { + bh = list_entry(tmp->next, struct buffer_head, b_inode_buffers); + list_del(tmp->next); + nr_atomic_emergency_bhs--; + atomic_emergency_owner = atomic; + } + } spin_unlock_irq(&emergency_lock); if (bh) return bh; + if (atomic) + blk_refile_atomic_queue(atomic); /* we need to wait I/O completion */ run_task_queue(&tq_disk); @@ -444,14 +529,14 @@ struct buffer_head * create_bounce(int r if (!PageHighMem(bh_orig->b_page)) return bh_orig; - bh = alloc_bounce_bh(); + bh = alloc_bounce_bh(bh_elv_seq(bh_orig)); /* * This is wasteful for 1k buffers, but this is a stopgap measure * and we are being ineffective anyway. This approach simplifies * things immensly. On boxes with more than 4GB RAM this should * not be an issue anyway. */ - page = alloc_bounce_page(); + page = alloc_bounce_page(bh_elv_seq(bh_orig)); set_bh_page(bh, page, 0); @@ -479,6 +564,7 @@ struct buffer_head * create_bounce(int r bh->b_end_io = bounce_end_io_read; bh->b_private = (void *)bh_orig; bh->b_rsector = bh_orig->b_rsector; + bh_elv_seq(bh) = bh_elv_seq(bh_orig); #ifdef HIGHMEM_DEBUG memset(&bh->b_wait, -1, sizeof(bh->b_wait)); #endif diff -Naurp linux-2.4.20-wolk4.1s/mm/memory.c linux-2.4.20-wolk4.2-fullkernel/mm/memory.c --- linux-2.4.20-wolk4.1s/mm/memory.c 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/mm/memory.c 2003-06-04 21:14:16.000000000 +0200 @@ -750,7 +750,6 @@ int map_user_kiobuf(int rw, struct kiobu if (err) return err; - iobuf->rw = rw; iobuf->locked = 0; iobuf->offset = va & (PAGE_SIZE-1); iobuf->length = len; @@ -767,10 +766,11 @@ int map_user_kiobuf(int rw, struct kiobu return err; } iobuf->nr_pages = err; - /* if rw==WRITE, get updated data before writing them to disk */ - if (rw==WRITE) { - while (pgcount--) - flush_dcache_page(iobuf->maplist[pgcount]); + while (pgcount--) { + /* FIXME: flush superflous for rw==READ, + * probably wrong function for rw==WRITE + */ + flush_dcache_page(iobuf->maplist[pgcount]); } dprintk ("map_user_kiobuf: end OK\n"); return 0; @@ -825,10 +825,9 @@ void unmap_kiobuf (struct kiobuf *iobuf) if (map) { if (iobuf->locked) UnlockPage(map); - /* if rw==READ, flush dcache before user uses data */ - if (iobuf->rw==READ) { - flush_dcache_page(iobuf->maplist[i]); - } + /* FIXME: cache flush missing for rw==READ + * FIXME: call the correct reference counting function + */ page_cache_release(map); } } diff -Naurp linux-2.4.20-wolk4.1s/mm/mmap.c linux-2.4.20-wolk4.2-fullkernel/mm/mmap.c --- linux-2.4.20-wolk4.1s/mm/mmap.c 2003-05-20 09:56:55.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/mm/mmap.c 2003-06-02 17:31:54.000000000 +0200 @@ -1130,6 +1130,8 @@ static void free_pgtables(struct mm_stru break; } no_mmaps: + if (last < first) + return; /* * If the PGD bits are not consecutive in the virtual address, the * old method of shifting the VA >> by PGDIR_SHIFT doesn't work. diff -Naurp linux-2.4.20-wolk4.1s/mm/page_alloc.c linux-2.4.20-wolk4.2-fullkernel/mm/page_alloc.c --- linux-2.4.20-wolk4.1s/mm/page_alloc.c 2003-05-20 09:56:55.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/mm/page_alloc.c 2003-06-02 17:31:54.000000000 +0200 @@ -627,9 +627,10 @@ defragment: { int try_harder = 0; unsigned int mask = 0; - int numpages; + int numpages, freed; defragment_again: zone = zonelist->zones; + freed = 0; for (;;) { zone_t *z = *(zone++); if (!z) @@ -644,12 +645,13 @@ defragment_again: */ numpages = z->inactive_laundry_pages; if (try_harder) { - numpages /= 2; - mask = gfp_mask; + numpages = 64; + rebalance_inactive(20); + freed += rebalance_dirty_zone(z, numpages, mask); } current->flags |= PF_MEMALLOC; - rebalance_laundry_zone(z, numpages, mask); + freed += rebalance_laundry_zone(z, numpages, mask); current->flags &= ~PF_MEMALLOC; while (z->inactive_clean_pages) { @@ -667,9 +669,15 @@ defragment_again: } /* If we can wait for IO to complete, we wait... */ - if (!try_harder && (gfp_mask & __GFP_FS)) { - try_harder = 1; - goto defragment_again; + if (gfp_mask & __GFP_FS) { + if (!try_harder) { + mask = gfp_mask; + try_harder = 1; + goto defragment_again; + } + /* Try smaller allocations indefinately. */ + if (order <= 2 && freed) + goto defragment_again; } } @@ -863,6 +871,29 @@ unsigned int nr_free_highpages (void) return pages; } + +unsigned int freeable_lowmem(void) +{ + unsigned int pages = 0; + pg_data_t *pgdat; + + for_each_pgdat(pgdat) { + pages += pgdat->node_zones[ZONE_DMA].free_pages; + pages += pgdat->node_zones[ZONE_DMA].inactive_clean_pages; + pages += pgdat->node_zones[ZONE_DMA].inactive_laundry_pages; + pages += pgdat->node_zones[ZONE_DMA].inactive_dirty_pages; + pages += pgdat->node_zones[ZONE_DMA].active_cache_pages; + pages += pgdat->node_zones[ZONE_DMA].active_anon_pages; + pages += pgdat->node_zones[ZONE_NORMAL].free_pages; + pages += pgdat->node_zones[ZONE_NORMAL].inactive_clean_pages; + pages += pgdat->node_zones[ZONE_NORMAL].inactive_laundry_pages; + pages += pgdat->node_zones[ZONE_NORMAL].inactive_dirty_pages; + pages += pgdat->node_zones[ZONE_NORMAL].active_cache_pages; + pages += pgdat->node_zones[ZONE_NORMAL].active_anon_pages; + } + + return pages; +} #endif /* CONFIG_HIGHMEM */ #define K(x) ((x) << (PAGE_SHIFT-10)) diff -Naurp linux-2.4.20-wolk4.1s/mm/rmap.c linux-2.4.20-wolk4.2-fullkernel/mm/rmap.c --- linux-2.4.20-wolk4.1s/mm/rmap.c 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/mm/rmap.c 2003-06-01 18:15:45.000000000 +0200 @@ -218,7 +218,7 @@ page_add_rmap(struct page * page, pte_t BUG(); #endif - if (!pfn_valid(page_to_pfn(page)) || PageReserved(page)) + if (!VALID_PAGE(page) || PageReserved(page)) return pte_chain; pte_chain_lock(page); @@ -302,13 +302,17 @@ void page_remove_rmap(struct page * page if (!page || !ptep) BUG(); - if (!pfn_valid(page_to_pfn(page)) || PageReserved(page)) + if (!VALID_PAGE(page)) return; - if (!page_mapped(page)) - return; /* remap_page_range() from a driver? */ pte_chain_lock(page); + if (!page_mapped(page)) + goto out; /* remap_page_range() from a driver? */ + + if (PageReserved(page)) + printk("page_remove_rmap: reserved page with rmap...\n"); + if (PageDirect(page)) { if (page->pte.direct == pte_paddr) { page->pte.direct = 0; diff -Naurp linux-2.4.20-wolk4.1s/mm/slab.c linux-2.4.20-wolk4.2-fullkernel/mm/slab.c --- linux-2.4.20-wolk4.1s/mm/slab.c 2003-05-15 21:52:48.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/mm/slab.c 2003-06-05 23:16:53.000000000 +0200 @@ -1789,8 +1789,9 @@ int kmem_cache_reap (int gfp_mask) full_free = 0; p = searchp->slabs_free.next; while (p != &searchp->slabs_free) { - slabp = list_entry(p, slab_t, list); #if DEBUG + slabp = list_entry(p, slab_t, list); + if (slabp->inuse) BUG(); #endif diff -Naurp linux-2.4.20-wolk4.1s/mm/vmscan.c linux-2.4.20-wolk4.2-fullkernel/mm/vmscan.c --- linux-2.4.20-wolk4.1s/mm/vmscan.c 2003-05-20 09:56:55.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/mm/vmscan.c 2003-06-03 13:09:29.000000000 +0200 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,54 @@ static void wakeup_memwaiters(void); */ #define DEF_PRIORITY (6) + +/* + * Handling of caches defined in drivers, filesystems, ... + * + * The cache definition contains a callback for shrinking + * the cache. + * + * The [un]register_cache() functions may only be called when + * the kernel lock is held. The shrink() functions are also + * called with the kernel lock held. + */ +static DECLARE_MUTEX(other_caches_sem); +static LIST_HEAD(cache_definitions); + + +void register_cache(struct cache_definition *cache) +{ + down(&other_caches_sem); + list_add(&cache->link, &cache_definitions); + up(&other_caches_sem); +} + +void unregister_cache(struct cache_definition *cache) +{ + down(&other_caches_sem); + list_del(&cache->link); + up(&other_caches_sem); +} + +static int shrink_other_caches(unsigned int priority, int gfp_mask) +{ + struct list_head *p; + + if (down_trylock(&other_caches_sem)) + return 0; + + list_for_each_prev(p, &cache_definitions) { + struct cache_definition *cache = + list_entry(p, struct cache_definition, link); + + cache->shrink(priority, gfp_mask); + } + up(&other_caches_sem); + + return 0; +} + + static inline void age_page_up_nolock(struct page *page, int old_age) { int new_age; @@ -715,7 +764,7 @@ int rebalance_laundry_zone(struct zone_s * be the best page to wait on; move it to * the head of the dirty list. */ - if (timed_out & PageInactiveLaundry(page)) { + if (timed_out && PageInactiveLaundry(page)) { unsigned char now; now = (jiffies/HZ)&255; if (now - page->age > 30) { @@ -735,6 +784,31 @@ int rebalance_laundry_zone(struct zone_s /* No dice, we can't wait for IO */ break; } + + if (page->buffers) { + page_cache_get(page); + lru_unlock(zone); + try_to_release_page(page, 0); + UnlockPage(page); + page_cache_release(page); + lru_lock(zone); + if (unlikely(page->buffers) && + PageInactiveLaundry(page)) { + del_page_from_inactive_laundry_list(page); + add_page_to_inactive_dirty_list(page); + } + continue; + } + + /* Check if the page is still clean or is accessed. */ + if (unlikely(page->pte.direct || page->buffers || + PageReferenced(page) || PageDirty(page) || + page_count(page) > 1)) { + del_page_from_inactive_laundry_list(page); + add_page_to_inactive_dirty_list(page); + UnlockPage(page); + continue; + } UnlockPage(page); /* @@ -742,9 +816,6 @@ int rebalance_laundry_zone(struct zone_s * IO never happened because it was clean. Either way * move it to the inactive clean list. */ - - /* FIXME: check if the page is still clean or is accessed ? */ - del_page_from_inactive_laundry_list(page); add_page_to_inactive_clean_list(page); work_done++; @@ -938,12 +1009,11 @@ static int do_try_to_free_pages_kswapd(u if (free_low(zone + ZONE_DMA) > 0 || free_low(zone + ZONE_NORMAL) > 0) { ret += shrink_dcache_memory(DEF_PRIORITY, gfp_mask); ret += shrink_icache_memory(DEF_PRIORITY, gfp_mask); -#ifdef CONFIG_RMAP_BUFFER_RECLAIM - ret += try_to_reclaim_buffers(DEF_PRIORITY, gfp_mask); -#endif + try_to_reclaim_buffers(DEF_PRIORITY, gfp_mask); #ifdef CONFIG_QUOTA ret += shrink_dqcache_memory(DEF_PRIORITY, gfp_mask); #endif + ret += kmem_cache_reap(gfp_mask); break; } } @@ -953,7 +1023,7 @@ static int do_try_to_free_pages_kswapd(u /* * Mhwahahhaha! This is the part I really like. Giggle. */ - if (!ret && free_min(ANY_ZONE)) + if (ret < free_min(ANY_ZONE)) out_of_memory(); return ret; diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/Config.in linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/Config.in --- linux-2.4.20-wolk4.1s/net/bluetooth/Config.in 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/Config.in 2003-06-03 20:02:49.000000000 +0200 @@ -1,8 +1,9 @@ # -# Bluetooth configuration +# Bluetooth subsystem configuration # if [ "$CONFIG_NET" != "n" ]; then + mainmenu_option next_comment comment 'Bluetooth support' dep_tristate 'Bluetooth subsystem support' CONFIG_BLUEZ $CONFIG_NET @@ -10,9 +11,11 @@ if [ "$CONFIG_NET" != "n" ]; then if [ "$CONFIG_BLUEZ" != "n" ]; then dep_tristate 'L2CAP protocol support' CONFIG_BLUEZ_L2CAP $CONFIG_BLUEZ dep_tristate 'SCO links support' CONFIG_BLUEZ_SCO $CONFIG_BLUEZ + source net/bluetooth/rfcomm/Config.in source net/bluetooth/bnep/Config.in source drivers/bluetooth/Config.in fi + endmenu fi diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/Makefile linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/Makefile --- linux-2.4.20-wolk4.1s/net/bluetooth/Makefile 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/Makefile 2003-06-03 20:02:49.000000000 +0200 @@ -1,6 +1,7 @@ # -# Makefile for the Bluetooth subsystem +# Makefile for the Linux Bluetooth subsystem # + O_TARGET := bluetooth.o list-multi := bluez.o @@ -12,8 +13,13 @@ obj-$(CONFIG_BLUEZ) += bluez.o obj-$(CONFIG_BLUEZ_L2CAP) += l2cap.o obj-$(CONFIG_BLUEZ_SCO) += sco.o +subdir-$(CONFIG_BLUEZ_RFCOMM) += rfcomm subdir-$(CONFIG_BLUEZ_BNEP) += bnep +ifeq ($(CONFIG_BLUEZ_RFCOMM),y) +obj-y += rfcomm/rfcomm.o +endif + ifeq ($(CONFIG_BLUEZ_BNEP),y) obj-y += bnep/bnep.o endif diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/af_bluetooth.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/af_bluetooth.c --- linux-2.4.20-wolk4.1s/net/bluetooth/af_bluetooth.c 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/af_bluetooth.c 2003-06-03 20:02:49.000000000 +0200 @@ -27,7 +27,7 @@ * * $Id: af_bluetooth.c,v 1.8 2002/07/22 20:32:54 maxk Exp $ */ -#define VERSION "2.2" +#define VERSION "2.3" #include #include @@ -57,7 +57,7 @@ #endif /* Bluetooth sockets */ -#define BLUEZ_MAX_PROTO 5 +#define BLUEZ_MAX_PROTO 6 static struct net_proto_family *bluez_proto[BLUEZ_MAX_PROTO]; int bluez_sock_register(int proto, struct net_proto_family *ops) @@ -253,39 +253,35 @@ unsigned int bluez_sock_poll(struct file return mask; } -int bluez_sock_w4_connect(struct sock *sk, int flags) +int bluez_sock_wait_state(struct sock *sk, int state, unsigned long timeo) { DECLARE_WAITQUEUE(wait, current); - long timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); int err = 0; BT_DBG("sk %p", sk); add_wait_queue(sk->sleep, &wait); - while (sk->state != BT_CONNECTED) { + while (sk->state != state) { set_current_state(TASK_INTERRUPTIBLE); + if (!timeo) { err = -EAGAIN; break; } + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + release_sock(sk); timeo = schedule_timeout(timeo); lock_sock(sk); - err = 0; - if (sk->state == BT_CONNECTED) - break; - if (sk->err) { err = sock_error(sk); break; } - - if (signal_pending(current)) { - err = sock_intr_errno(timeo); - break; - } } set_current_state(TASK_RUNNING); remove_wait_queue(sk->sleep, &wait); diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/bnep/Config.in linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/bnep/Config.in --- linux-2.4.20-wolk4.1s/net/bluetooth/bnep/Config.in 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/bnep/Config.in 2003-06-03 20:02:49.000000000 +0200 @@ -1,6 +1,11 @@ +# +# Bluetooth BNEP layer configuration +# dep_tristate 'BNEP protocol support' CONFIG_BLUEZ_BNEP $CONFIG_BLUEZ_L2CAP + if [ "$CONFIG_BLUEZ_BNEP" != "n" ]; then - bool ' Multicast filter support' CONFIG_BNEP_MC_FILTER - bool ' Protocol filter support' CONFIG_BNEP_PROTO_FILTER + bool ' Multicast filter support' CONFIG_BLUEZ_BNEP_MC_FILTER + bool ' Protocol filter support' CONFIG_BLUEZ_BNEP_PROTO_FILTER fi + diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/bnep/Makefile linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/bnep/Makefile --- linux-2.4.20-wolk4.1s/net/bluetooth/bnep/Makefile 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/bnep/Makefile 2003-06-03 20:02:49.000000000 +0200 @@ -1,5 +1,5 @@ # -# Makefile for BNEP protocol +# Makefile for the Linux Bluetooth BNEP layer # O_TARGET := bnep.o diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/bnep/bnep.h linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/bnep/bnep.h --- linux-2.4.20-wolk4.1s/net/bluetooth/bnep/bnep.h 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/bnep/bnep.h 2003-06-03 20:02:49.000000000 +0200 @@ -112,25 +112,25 @@ struct bnep_ext_hdr { __u8 data[0]; } __attribute__((packed)); -// Ioctl interface -#define BNEPCONADD 1 -#define BNEPCONDEL 2 -#define BNEPGETCONLIST 3 -#define BNEPGETCONINFO 4 +/* BNEP ioctl defines */ +#define BNEPCONNADD _IOW('B', 200, int) +#define BNEPCONNDEL _IOW('B', 201, int) +#define BNEPGETCONNLIST _IOR('B', 210, int) +#define BNEPGETCONNINFO _IOR('B', 211, int) -struct bnep_conadd_req { +struct bnep_connadd_req { int sock; // Connected socket __u32 flags; __u16 role; char device[16]; // Name of the Ethernet device }; -struct bnep_condel_req { +struct bnep_conndel_req { __u32 flags; __u8 dst[ETH_ALEN]; }; -struct bnep_coninfo { +struct bnep_conninfo { __u32 flags; __u16 role; __u16 state; @@ -138,9 +138,9 @@ struct bnep_coninfo { char device[16]; }; -struct bnep_conlist_req { +struct bnep_connlist_req { __u32 cnum; - struct bnep_coninfo *ci; + struct bnep_conninfo *ci; }; struct bnep_proto_filter { @@ -148,10 +148,10 @@ struct bnep_proto_filter { __u16 end; }; -int bnep_add_connection(struct bnep_conadd_req *req, struct socket *sock); -int bnep_del_connection(struct bnep_condel_req *req); -int bnep_get_conlist(struct bnep_conlist_req *req); -int bnep_get_coninfo(struct bnep_coninfo *ci); +int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock); +int bnep_del_connection(struct bnep_conndel_req *req); +int bnep_get_connlist(struct bnep_connlist_req *req); +int bnep_get_conninfo(struct bnep_conninfo *ci); // BNEP sessions struct bnep_session { diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/bnep/core.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/bnep/core.c --- linux-2.4.20-wolk4.1s/net/bluetooth/bnep/core.c 2003-05-15 21:52:49.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/bnep/core.c 2003-06-03 20:02:49.000000000 +0200 @@ -58,17 +58,17 @@ #include "bnep.h" -#ifndef CONFIG_BNEP_DEBUG +#ifndef CONFIG_BLUEZ_BNEP_DEBUG #undef BT_DBG #define BT_DBG(D...) #endif -#define VERSION "1.0" +#define VERSION "1.1" static LIST_HEAD(bnep_session_list); static DECLARE_RWSEM(bnep_session_sem); -static struct bnep_session *__bnep_get_session(__u8 *dst) +static struct bnep_session *__bnep_get_session(u8 *dst) { struct bnep_session *s; struct list_head *p; @@ -104,7 +104,7 @@ static int bnep_send(struct bnep_session return sock->ops->sendmsg(sock, &s->msg, len, NULL); } -static int bnep_send_rsp(struct bnep_session *s, __u8 ctrl, __u16 resp) +static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp) { struct bnep_control_rsp rsp; rsp.type = BNEP_CONTROL; @@ -113,23 +113,22 @@ static int bnep_send_rsp(struct bnep_ses return bnep_send(s, &rsp, sizeof(rsp)); } -static int bnep_ctrl_set_netfilter(struct bnep_session *s, struct sk_buff *skb) +static int bnep_ctrl_set_netfilter(struct bnep_session *s, u16 *data, int len) { - __u16 *data; int n; - - data = (void *) skb->data; - if (!skb_pull(skb, 2)) + + if (len < 2) return -EILSEQ; + n = ntohs(get_unaligned(data)); + data++; len -= 2; - data = (void *) skb->data; - if (!skb_pull(skb, n)) + if (len < n) return -EILSEQ; BT_DBG("filter len %d", n); -#ifdef CONFIG_BNEP_PROTO_FILTER +#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER n /= 4; if (n <= BNEP_MAX_PROTO_FILTERS) { struct bnep_proto_filter *f = s->proto_filter; @@ -155,23 +154,22 @@ static int bnep_ctrl_set_netfilter(struc return 0; } -static int bnep_ctrl_set_mcfilter(struct bnep_session *s, struct sk_buff *skb) +static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) { - u8 *data; int n; - - data = (void *) skb->data; - if (!skb_pull(skb, 2)) + + if (len < 2) return -EILSEQ; - n = ntohs(get_unaligned((u16 *) data)); + + n = ntohs(get_unaligned((u16 *) data)); + data += 2; len -= 2; - data = (void *) skb->data; - if (!skb_pull(skb, n)) + if (len < n) return -EILSEQ; BT_DBG("filter len %d", n); -#ifdef CONFIG_BNEP_MC_FILTER +#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER n /= (ETH_ALEN * 2); if (n > 0) { @@ -210,11 +208,12 @@ static int bnep_ctrl_set_mcfilter(struct return 0; } -static int bnep_rx_control(struct bnep_session *s, struct sk_buff *skb) +static int bnep_rx_control(struct bnep_session *s, void *data, int len) { + u8 cmd = *(u8 *)data; int err = 0; - __u8 cmd = *(__u8 *) skb->data; - skb_pull(skb, 1); + + data++; len--; switch (cmd) { case BNEP_CMD_NOT_UNDERSTOOD: @@ -226,15 +225,15 @@ static int bnep_rx_control(struct bnep_s break; case BNEP_FILTER_NET_TYPE_SET: - err = bnep_ctrl_set_netfilter(s, skb); + err = bnep_ctrl_set_netfilter(s, data, len); break; case BNEP_FILTER_MULTI_ADDR_SET: - err = bnep_ctrl_set_mcfilter(s, skb); + err = bnep_ctrl_set_mcfilter(s, data, len); break; default: { - __u8 pkt[3]; + u8 pkt[3]; pkt[0] = BNEP_CONTROL; pkt[1] = BNEP_CMD_NOT_UNDERSTOOD; pkt[2] = cmd; @@ -262,13 +261,16 @@ static int bnep_rx_extension(struct bnep switch (h->type & BNEP_TYPE_MASK) { case BNEP_EXT_CONTROL: - err = bnep_rx_control(s, skb); + bnep_rx_control(s, skb->data, skb->len); break; default: - /* Unknown extension */ - if (!skb_pull(skb, h->len)) - err = -EILSEQ; + /* Unknown extension, skip it. */ + break; + } + + if (!skb_pull(skb, h->len)) { + err = -EILSEQ; break; } } while (!err && (h->type & BNEP_EXT_HEADER)); @@ -276,7 +278,7 @@ static int bnep_rx_extension(struct bnep return err; } -static __u8 __bnep_rx_hlen[] = { +static u8 __bnep_rx_hlen[] = { ETH_HLEN, /* BNEP_GENERAL */ 0, /* BNEP_CONTROL */ 2, /* BNEP_COMPRESSED */ @@ -289,18 +291,18 @@ static inline int bnep_rx_frame(struct b { struct net_device *dev = &s->dev; struct sk_buff *nskb; - __u8 type; + u8 type; dev->last_rx = jiffies; s->stats.rx_bytes += skb->len; - type = *(__u8 *) skb->data; skb_pull(skb, 1); + type = *(u8 *) skb->data; skb_pull(skb, 1); if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES) goto badframe; if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { - bnep_rx_control(s, skb); + bnep_rx_control(s, skb->data, skb->len); kfree_skb(skb); return 0; } @@ -311,7 +313,7 @@ static inline int bnep_rx_frame(struct b if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK])) goto badframe; - s->eh.h_proto = get_unaligned((__u16 *) (skb->data - 2)); + s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2)); if (type & BNEP_EXT_HEADER) { if (bnep_rx_extension(s, skb) < 0) @@ -322,7 +324,7 @@ static inline int bnep_rx_frame(struct b if (ntohs(s->eh.h_proto) == 0x8100) { if (!skb_pull(skb, 4)) goto badframe; - s->eh.h_proto = get_unaligned((__u16 *) (skb->data - 2)); + s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2)); } /* We have to alloc new skb and copy data here :(. Because original skb @@ -344,7 +346,7 @@ static inline int bnep_rx_frame(struct b case BNEP_COMPRESSED_SRC_ONLY: memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN); memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN); - put_unaligned(s->eh.h_proto, (__u16 *) __skb_put(nskb, 2)); + put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2)); break; case BNEP_COMPRESSED_DST_ONLY: @@ -354,7 +356,7 @@ static inline int bnep_rx_frame(struct b case BNEP_GENERAL: memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2); - put_unaligned(s->eh.h_proto, (__u16 *) __skb_put(nskb, 2)); + put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2)); break; } @@ -374,7 +376,7 @@ badframe: return 0; } -static __u8 __bnep_tx_types[] = { +static u8 __bnep_tx_types[] = { BNEP_GENERAL, BNEP_COMPRESSED_SRC_ONLY, BNEP_COMPRESSED_DST_ONLY, @@ -387,7 +389,7 @@ static inline int bnep_tx_frame(struct b struct socket *sock = s->sock; struct iovec iv[3]; int len = 0, il = 0; - __u8 type = 0; + u8 type = 0; BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type); @@ -503,11 +505,11 @@ static int bnep_session(void *arg) return 0; } -int bnep_add_connection(struct bnep_conadd_req *req, struct socket *sock) +int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) { struct net_device *dev; struct bnep_session *s, *ss; - __u8 dst[ETH_ALEN], src[ETH_ALEN]; + u8 dst[ETH_ALEN], src[ETH_ALEN]; int err; BT_DBG(""); @@ -535,6 +537,8 @@ int bnep_add_connection(struct bnep_cona else strcpy(dev->name, "bnep%d"); + memset(dev->broadcast, 0xff, ETH_ALEN); + /* This is rx header therefor addresses are swaped. * ie eh.h_dest is our local address. */ memcpy(s->eh.h_dest, &src, ETH_ALEN); @@ -546,12 +550,12 @@ int bnep_add_connection(struct bnep_cona s->msg.msg_flags = MSG_NOSIGNAL; -#ifdef CONFIG_BNEP_MC_FILTER +#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER /* Set default mc filter */ set_bit(bnep_mc_hash(dev->broadcast), &s->mc_filter); #endif -#ifdef CONFIG_BNEP_PROTO_FILTER +#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER /* Set default protocol filter */ /* (IPv4, ARP) */ @@ -592,7 +596,7 @@ failed: return err; } -int bnep_del_connection(struct bnep_condel_req *req) +int bnep_del_connection(struct bnep_conndel_req *req) { struct bnep_session *s; int err = 0; @@ -617,7 +621,7 @@ int bnep_del_connection(struct bnep_cond return err; } -static void __bnep_copy_ci(struct bnep_coninfo *ci, struct bnep_session *s) +static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s) { memcpy(ci->dst, s->eh.h_source, ETH_ALEN); strcpy(ci->device, s->dev.name); @@ -626,7 +630,7 @@ static void __bnep_copy_ci(struct bnep_c ci->role = s->role; } -int bnep_get_conlist(struct bnep_conlist_req *req) +int bnep_get_connlist(struct bnep_connlist_req *req) { struct list_head *p; int err = 0, n = 0; @@ -635,7 +639,7 @@ int bnep_get_conlist(struct bnep_conlist list_for_each(p, &bnep_session_list) { struct bnep_session *s; - struct bnep_coninfo ci; + struct bnep_conninfo ci; s = list_entry(p, struct bnep_session, list); @@ -657,7 +661,7 @@ int bnep_get_conlist(struct bnep_conlist return err; } -int bnep_get_coninfo(struct bnep_coninfo *ci) +int bnep_get_conninfo(struct bnep_conninfo *ci) { struct bnep_session *s; int err = 0; @@ -676,17 +680,14 @@ int bnep_get_coninfo(struct bnep_coninfo static int __init bnep_init_module(void) { - BT_INFO("BNEP: BNEP2 ver %s\n" - "BNEP: Copyright (C) 2002 Inventel\n" - "BNEP: Written 2001,2002 by\n" - "BNEP: \tClement Moreau " - "David Libault \n" - "BNEP: Copyright (C) 2002 Maxim Krasnyanskiy ", - VERSION); - + bnep_crc32_init(); bnep_sock_init(); - bnep_crc32_init(); + BT_INFO("BlueZ BNEP ver %s", VERSION); + BT_INFO("Copyright (C) 2001,2002 Inventel Systemes"); + BT_INFO("Written 2001,2002 by Clement Moreau "); + BT_INFO("Written 2001,2002 by David Libault "); + BT_INFO("Copyright (C) 2002 Maxim Krasnyanskiy "); return 0; } @@ -694,13 +695,12 @@ static int __init bnep_init_module(void) static void __exit bnep_cleanup_module(void) { bnep_sock_cleanup(); - bnep_crc32_cleanup(); } module_init(bnep_init_module); module_exit(bnep_cleanup_module); -MODULE_DESCRIPTION("BNEP2 ver " VERSION); -MODULE_AUTHOR("David Libault Maxim Krasnyanskiy "); +MODULE_DESCRIPTION("BlueZ BNEP ver " VERSION); +MODULE_AUTHOR("David Libault , Maxim Krasnyanskiy "); MODULE_LICENSE("GPL"); diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/bnep/netdev.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/bnep/netdev.c --- linux-2.4.20-wolk4.1s/net/bluetooth/bnep/netdev.c 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/bnep/netdev.c 2003-06-03 20:02:49.000000000 +0200 @@ -46,7 +46,7 @@ #include "bnep.h" -#ifndef CONFIG_BNEP_DEBUG +#ifndef CONFIG_BLUEZ_BNEP_DEBUG #undef BT_DBG #define BT_DBG( A... ) #endif @@ -73,7 +73,7 @@ static struct net_device_stats *bnep_net static void bnep_net_set_mc_list(struct net_device *dev) { -#ifdef CONFIG_BNEP_MC_FILTER +#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER struct bnep_session *s = dev->priv; struct sock *sk = s->sock->sk; struct bnep_set_filter_req *r; @@ -143,27 +143,31 @@ static int bnep_net_ioctl(struct net_dev return -EINVAL; } -#ifdef CONFIG_BNEP_MC_FILTER +#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s) { struct ethhdr *eh = (void *) skb->data; - if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter)) + if ((eh->h_dest[0] & 1) && !test_bit(bnep_mc_hash(eh->h_dest), &s->mc_filter)) { + BT_DBG("BNEP: filtered skb %p, dst %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", skb, + eh->h_dest[0], eh->h_dest[1], eh->h_dest[2], + eh->h_dest[3], eh->h_dest[4], eh->h_dest[5]); return 1; + } return 0; } #endif -#ifdef CONFIG_BNEP_PROTO_FILTER +#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER /* Determine ether protocol. Based on eth_type_trans. */ -static inline __u16 bnep_net_eth_proto(struct sk_buff *skb) +static inline u16 bnep_net_eth_proto(struct sk_buff *skb) { struct ethhdr *eh = (void *) skb->data; if (ntohs(eh->h_proto) >= 1536) return eh->h_proto; - if (get_unaligned((__u16 *) skb->data) == 0xFFFF) + if (get_unaligned((u16 *) skb->data) == 0xFFFF) return htons(ETH_P_802_3); return htons(ETH_P_802_2); @@ -171,7 +175,7 @@ static inline __u16 bnep_net_eth_proto(s static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s) { - __u16 proto = bnep_net_eth_proto(skb); + u16 proto = bnep_net_eth_proto(skb); struct bnep_proto_filter *f = s->proto_filter; int i; @@ -192,14 +196,14 @@ static int bnep_net_xmit(struct sk_buff BT_DBG("skb %p, dev %p", skb, dev); -#ifdef CONFIG_BNEP_MC_FILTER +#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER if (bnep_net_mc_filter(skb, s)) { kfree_skb(skb); return 0; } #endif -#ifdef CONFIG_BNEP_PROTO_FILTER +#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER if (bnep_net_proto_filter(skb, s)) { kfree_skb(skb); return 0; diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/bnep/sock.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/bnep/sock.c --- linux-2.4.20-wolk4.1s/net/bluetooth/bnep/sock.c 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/bnep/sock.c 2003-06-03 20:02:49.000000000 +0200 @@ -50,7 +50,7 @@ #include "bnep.h" -#ifndef CONFIG_BNEP_DEBUG +#ifndef CONFIG_BLUEZ_BNEP_DEBUG #undef BT_DBG #define BT_DBG( A... ) #endif @@ -103,17 +103,17 @@ static int bnep_sock_release(struct sock static int bnep_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { - struct bnep_conlist_req cl; - struct bnep_conadd_req ca; - struct bnep_condel_req cd; - struct bnep_coninfo ci; + struct bnep_connlist_req cl; + struct bnep_connadd_req ca; + struct bnep_conndel_req cd; + struct bnep_conninfo ci; struct socket *nsock; int err; BT_DBG("cmd %x arg %lx", cmd, arg); switch (cmd) { - case BNEPCONADD: + case BNEPCONNADD: if (!capable(CAP_NET_ADMIN)) return -EACCES; @@ -136,7 +136,7 @@ static int bnep_sock_ioctl(struct socket return err; - case BNEPCONDEL: + case BNEPCONNDEL: if (!capable(CAP_NET_ADMIN)) return -EACCES; @@ -145,24 +145,24 @@ static int bnep_sock_ioctl(struct socket return bnep_del_connection(&cd); - case BNEPGETCONLIST: + case BNEPGETCONNLIST: if (copy_from_user(&cl, (void *) arg, sizeof(cl))) return -EFAULT; if (cl.cnum <= 0) return -EINVAL; - err = bnep_get_conlist(&cl); + err = bnep_get_connlist(&cl); if (!err && copy_to_user((void *) arg, &cl, sizeof(cl))) return -EFAULT; return err; - case BNEPGETCONINFO: + case BNEPGETCONNINFO: if (copy_from_user(&ci, (void *) arg, sizeof(ci))) return -EFAULT; - err = bnep_get_coninfo(&ci); + err = bnep_get_conninfo(&ci); if (!err && copy_to_user((void *) arg, &ci, sizeof(ci))) return -EFAULT; diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/hci_conn.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/hci_conn.c --- linux-2.4.20-wolk4.1s/net/bluetooth/hci_conn.c 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/hci_conn.c 2003-06-03 20:02:49.000000000 +0200 @@ -71,6 +71,7 @@ void hci_acl_connect(struct hci_conn *co memset(&cp, 0, sizeof(cp)); bacpy(&cp.bdaddr, &conn->dst); + cp.pscan_rep_mode = 0x01; if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) && inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) { diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/hci_core.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/hci_core.c --- linux-2.4.20-wolk4.1s/net/bluetooth/hci_core.c 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/hci_core.c 2003-06-03 20:02:49.000000000 +0200 @@ -717,7 +717,7 @@ int hci_get_dev_list(unsigned long arg) if (!dev_num) return -EINVAL; - size = dev_num * sizeof(struct hci_dev_req) + sizeof(__u16); + size = dev_num * sizeof(*dr) + sizeof(*dl); if (verify_area(VERIFY_WRITE, (void *) arg, size)) return -EFAULT; @@ -738,7 +738,7 @@ int hci_get_dev_list(unsigned long arg) read_unlock_bh(&hdev_list_lock); dl->dev_num = n; - size = n * sizeof(struct hci_dev_req) + sizeof(__u16); + size = n * sizeof(*dr) + sizeof(*dl); copy_to_user((void *) arg, dl, size); kfree(dl); @@ -864,6 +864,22 @@ int hci_unregister_dev(struct hci_dev *h return 0; } +/* Suspend HCI device */ +int hci_suspend_dev(struct hci_dev *hdev) +{ + hci_notify(hdev, HCI_DEV_SUSPEND); + hci_run_hotplug(hdev->name, "suspend"); + return 0; +} + +/* Resume HCI device */ +int hci_resume_dev(struct hci_dev *hdev) +{ + hci_notify(hdev, HCI_DEV_RESUME); + hci_run_hotplug(hdev->name, "resume"); + return 0; +} + /* Receive frame from HCI drivers */ int hci_recv_frame(struct sk_buff *skb) { @@ -959,40 +975,6 @@ static int hci_send_frame(struct sk_buff return hdev->send(skb); } -/* Send raw HCI frame */ -int hci_send_raw(struct sk_buff *skb) -{ - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - - if (!hdev) { - kfree_skb(skb); - return -ENODEV; - } - - BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len); - - if (!test_bit(HCI_RAW, &hdev->flags)) { - /* Queue frame according it's type */ - switch (skb->pkt_type) { - case HCI_COMMAND_PKT: - skb_queue_tail(&hdev->cmd_q, skb); - hci_sched_cmd(hdev); - return 0; - - case HCI_ACLDATA_PKT: - case HCI_SCODATA_PKT: - /* FIXME: - * Check header here and queue to apropriate connection. - */ - break; - } - } - - skb_queue_tail(&hdev->raw_q, skb); - hci_sched_tx(hdev); - return 0; -} - /* Send HCI command */ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *param) { diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/hci_sock.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/hci_sock.c --- linux-2.4.20-wolk4.1s/net/bluetooth/hci_sock.c 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/hci_sock.c 2003-06-03 20:02:49.000000000 +0200 @@ -49,6 +49,7 @@ #include #include +#include #include #include @@ -68,14 +69,17 @@ static struct hci_sec_filter hci_sec_fil { 0xd9fe, 0x0 }, /* Commands */ { + { 0x0 }, /* OGF_LINK_CTL */ - { 0x2a000002, 0x0, 0x0, 0x0 }, + { 0x2a000002, 0x0, 0x0, 0x0 }, /* OGF_LINK_POLICY */ - { 0x1200, 0x0, 0x0, 0x0 }, + { 0x1200, 0x0, 0x0, 0x0 }, /* OGF_HOST_CTL */ - { 0x80100000, 0xa, 0x0, 0x0 }, + { 0x80100000, 0x2a, 0x0, 0x0 }, /* OGF_INFO_PARAM */ - { 0x22a, 0x0, 0x0, 0x0 } + { 0x22a, 0x0, 0x0, 0x0 }, + /* OGF_STATUS_PARAM */ + { 0x2e, 0x0, 0x0, 0x0 } } }; @@ -387,25 +391,37 @@ static int hci_sock_sendmsg(struct socke skb->pkt_type = *((unsigned char *) skb->data); skb_pull(skb, 1); + skb->dev = (void *) hdev; - if (!capable(CAP_NET_RAW)) { - err = -EPERM; + if (skb->pkt_type == HCI_COMMAND_PKT) { + u16 opcode = __le16_to_cpu(get_unaligned((u16 *)skb->data)); + u16 ogf = cmd_opcode_ogf(opcode); + u16 ocf = cmd_opcode_ocf(opcode); + + if (((ogf > HCI_SFLT_MAX_OGF) || + !hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) && + !capable(CAP_NET_RAW)) { + err = -EPERM; + goto drop; + } - if (skb->pkt_type == HCI_COMMAND_PKT) { - __u16 opcode = __le16_to_cpu(*(__u16 *)skb->data); - __u16 ogf = cmd_opcode_ogf(opcode) - 1; - __u16 ocf = cmd_opcode_ocf(opcode) & HCI_FLT_OCF_BITS; - - if (ogf > HCI_SFLT_MAX_OGF || - !hci_test_bit(ocf, &hci_sec_filter.ocf_mask[ogf])) - goto drop; - } else + if (test_bit(HCI_RAW, &hdev->flags) || (ogf == OGF_VENDOR_CMD)) { + skb_queue_tail(&hdev->raw_q, skb); + hci_sched_tx(hdev); + } else { + skb_queue_tail(&hdev->cmd_q, skb); + hci_sched_cmd(hdev); + } + } else { + if (!capable(CAP_NET_RAW)) { + err = -EPERM; goto drop; + } + + skb_queue_tail(&hdev->raw_q, skb); + hci_sched_tx(hdev); } - - /* Send frame to HCI core */ - skb->dev = (void *) hdev; - hci_send_raw(skb); + err = len; done: diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/l2cap.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/l2cap.c --- linux-2.4.20-wolk4.1s/net/bluetooth/l2cap.c 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/l2cap.c 2003-06-03 20:02:49.000000000 +0200 @@ -27,7 +27,7 @@ * * $Id: l2cap.c,v 1.15 2002/09/09 01:14:52 maxk Exp $ */ -#define VERSION "2.1" +#define VERSION "2.3" #include #include @@ -178,69 +178,12 @@ static int l2cap_conn_del(struct hci_con return 0; } -int l2cap_connect(struct sock *sk) -{ - bdaddr_t *src = &bluez_pi(sk)->src; - bdaddr_t *dst = &bluez_pi(sk)->dst; - struct l2cap_conn *conn; - struct hci_conn *hcon; - struct hci_dev *hdev; - int err = 0; - - BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm); - - if (!(hdev = hci_get_route(dst, src))) - return -EHOSTUNREACH; - - hci_dev_lock_bh(hdev); - - err = -ENOMEM; - - hcon = hci_connect(hdev, ACL_LINK, dst); - if (!hcon) - goto done; - - conn = l2cap_conn_add(hcon, 0); - if (!conn) { - hci_conn_put(hcon); - goto done; - } - - err = 0; - - /* Update source addr of the socket */ - bacpy(src, conn->src); - - l2cap_chan_add(conn, sk, NULL); - - sk->state = BT_CONNECT; - l2cap_sock_set_timer(sk, sk->sndtimeo); - - if (hcon->state == BT_CONNECTED) { - if (sk->type == SOCK_SEQPACKET) { - l2cap_conn_req req; - req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; - l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); - } else { - l2cap_sock_clear_timer(sk); - sk->state = BT_CONNECTED; - } - } - -done: - hci_dev_unlock_bh(hdev); - hci_dev_put(hdev); - return err; -} - /* -------- Socket interface ---------- */ static struct sock *__l2cap_get_sock_by_addr(__u16 psm, bdaddr_t *src) { struct sock *sk; for (sk = l2cap_sk_list.head; sk; sk = sk->next) { - if (l2cap_pi(sk)->psm == psm && - !bacmp(&bluez_pi(sk)->src, src)) + if (sk->sport == psm && !bacmp(&bluez_pi(sk)->src, src)) break; } return sk; @@ -341,7 +284,7 @@ static void __l2cap_sock_close(struct so l2cap_disconn_req req; sk->state = BT_DISCONN; - l2cap_sock_set_timer(sk, HZ * 5); + l2cap_sock_set_timer(sk, sk->sndtimeo); req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); @@ -366,11 +309,9 @@ static void __l2cap_sock_close(struct so static void l2cap_sock_close(struct sock *sk) { l2cap_sock_clear_timer(sk); - lock_sock(sk); __l2cap_sock_close(sk, ECONNRESET); release_sock(sk); - l2cap_sock_kill(sk); } @@ -432,6 +373,9 @@ static int l2cap_sock_create(struct sock if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) return -ESOCKTNOSUPPORT; + if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW)) + return -EPERM; + sock->ops = &l2cap_sock_ops; if (!(sk = l2cap_sock_alloc(sock, protocol, GFP_KERNEL))) @@ -466,9 +410,9 @@ static int l2cap_sock_bind(struct socket /* Save source address */ bacpy(&bluez_pi(sk)->src, &la->l2_bdaddr); l2cap_pi(sk)->psm = la->l2_psm; + sk->sport = la->l2_psm; sk->state = BT_BOUND; } - write_unlock_bh(&l2cap_sk_list.lock); done: @@ -476,6 +420,62 @@ done: return err; } +static int l2cap_do_connect(struct sock *sk) +{ + bdaddr_t *src = &bluez_pi(sk)->src; + bdaddr_t *dst = &bluez_pi(sk)->dst; + struct l2cap_conn *conn; + struct hci_conn *hcon; + struct hci_dev *hdev; + int err = 0; + + BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm); + + if (!(hdev = hci_get_route(dst, src))) + return -EHOSTUNREACH; + + hci_dev_lock_bh(hdev); + + err = -ENOMEM; + + hcon = hci_connect(hdev, ACL_LINK, dst); + if (!hcon) + goto done; + + conn = l2cap_conn_add(hcon, 0); + if (!conn) { + hci_conn_put(hcon); + goto done; + } + + err = 0; + + /* Update source addr of the socket */ + bacpy(src, conn->src); + + l2cap_chan_add(conn, sk, NULL); + + sk->state = BT_CONNECT; + l2cap_sock_set_timer(sk, sk->sndtimeo); + + if (hcon->state == BT_CONNECTED) { + if (sk->type == SOCK_SEQPACKET) { + l2cap_conn_req req; + req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); + req.psm = l2cap_pi(sk)->psm; + l2cap_send_req(conn, L2CAP_CONN_REQ, L2CAP_CONN_REQ_SIZE, &req); + } else { + l2cap_sock_clear_timer(sk); + sk->state = BT_CONNECTED; + } + } + +done: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + return err; +} + static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; @@ -521,11 +521,12 @@ static int l2cap_sock_connect(struct soc bacpy(&bluez_pi(sk)->dst, &la->l2_bdaddr); l2cap_pi(sk)->psm = la->l2_psm; - if ((err = l2cap_connect(sk))) + if ((err = l2cap_do_connect(sk))) goto done; wait: - err = bluez_sock_w4_connect(sk, flags); + err = bluez_sock_wait_state(sk, BT_CONNECTED, + sock_sndtimeo(sk, flags & O_NONBLOCK)); done: release_sock(sk); @@ -758,32 +759,39 @@ static int l2cap_sock_getsockopt(struct static int l2cap_sock_shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; + int err = 0; BT_DBG("sock %p, sk %p", sock, sk); if (!sk) return 0; - l2cap_sock_clear_timer(sk); - lock_sock(sk); - sk->shutdown = SHUTDOWN_MASK; - __l2cap_sock_close(sk, ECONNRESET); - release_sock(sk); + if (!sk->shutdown) { + sk->shutdown = SHUTDOWN_MASK; + l2cap_sock_clear_timer(sk); + __l2cap_sock_close(sk, 0); - return 0; + if (sk->linger) + err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime); + } + release_sock(sk); + return err; } static int l2cap_sock_release(struct socket *sock) { struct sock *sk = sock->sk; + int err; BT_DBG("sock %p, sk %p", sock, sk); if (!sk) return 0; + err = l2cap_sock_shutdown(sock, 2); + sock_orphan(sk); - l2cap_sock_close(sk); - return 0; + l2cap_sock_kill(sk); + return err; } /* --------- L2CAP channels --------- */ @@ -954,6 +962,22 @@ static void l2cap_conn_ready(struct l2ca read_unlock(&l->lock); } +/* Notify sockets that we cannot guaranty reliability anymore */ +static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) +{ + struct l2cap_chan_list *l = &conn->chan_list; + struct sock *sk; + + BT_DBG("conn %p", conn); + + read_lock(&l->lock); + for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE) + sk->err = err; + } + read_unlock(&l->lock); +} + static void l2cap_chan_ready(struct sock *sk) { struct sock *parent = bluez_pi(sk)->parent; @@ -1318,15 +1342,18 @@ static int l2cap_build_conf_rsp(struct s { l2cap_conf_rsp *rsp = (l2cap_conf_rsp *) data; void *ptr = rsp->data; + u16 flags = 0; BT_DBG("sk %p complete %d", sk, result ? 1 : 0); if (result) *result = l2cap_conf_output(sk, &ptr); + else + flags |= 0x0001; rsp->scid = __cpu_to_le16(l2cap_pi(sk)->dcid); rsp->result = __cpu_to_le16(result ? *result : 0); - rsp->flags = __cpu_to_le16(0); + rsp->flags = __cpu_to_le16(flags); return ptr - data; } @@ -1439,7 +1466,7 @@ static inline int l2cap_connect_rsp(stru case L2CAP_CR_SUCCESS: sk->state = BT_CONFIG; l2cap_pi(sk)->dcid = dcid; - l2cap_pi(sk)->conf_state |= CONF_REQ_SENT; + l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); break; @@ -1474,7 +1501,7 @@ static inline int l2cap_config_req(struc l2cap_parse_conf_req(sk, req->data, cmd->len - L2CAP_CONF_REQ_SIZE); - if (flags & 0x01) { + if (flags & 0x0001) { /* Incomplete config. Send empty response. */ l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp); goto unlock; @@ -1487,12 +1514,12 @@ static inline int l2cap_config_req(struc goto unlock; /* Output config done */ - l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE; + l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE; - if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) { + if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { sk->state = BT_CONNECTED; l2cap_chan_ready(sk); - } else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) { + } else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { char req[64]; l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req); } @@ -1537,9 +1564,9 @@ static inline int l2cap_config_rsp(struc goto done; /* Input config done */ - l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE; + l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE; - if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) { + if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) { sk->state = BT_CONNECTED; l2cap_chan_ready(sk); } @@ -1590,7 +1617,7 @@ static inline int l2cap_disconnect_rsp(s if (!(sk = l2cap_get_chan_by_scid(&conn->chan_list, scid))) return 0; - l2cap_chan_del(sk, ECONNABORTED); + l2cap_chan_del(sk, 0); bh_unlock_sock(sk); l2cap_sock_kill(sk); @@ -1787,7 +1814,7 @@ static int l2cap_connect_ind(struct hci_ if (sk->state != BT_LISTEN) continue; - if (!bacmp(&bluez_pi(sk)->src, bdaddr)) { + if (!bacmp(&bluez_pi(sk)->src, &hdev->bdaddr)) { lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode); exact++; } else if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY)) @@ -1941,26 +1968,36 @@ static int l2cap_recv_acldata(struct hci kfree_skb(conn->rx_skb); conn->rx_skb = NULL; conn->rx_len = 0; + l2cap_conn_unreliable(conn, ECOMM); } if (skb->len < 2) { - BT_ERR("Frame is too small (len %d)", skb->len); + BT_ERR("Frame is too short (len %d)", skb->len); + l2cap_conn_unreliable(conn, ECOMM); goto drop; } hdr = (l2cap_hdr *) skb->data; len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE; - BT_DBG("Start: total len %d, frag len %d", len, skb->len); - if (len == skb->len) { /* Complete frame received */ l2cap_recv_frame(conn, skb); return 0; } - /* Allocate skb for the complete frame (with header) */ - if (!(conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC))) + BT_DBG("Start: total len %d, frag len %d", len, skb->len); + + if (skb->len > len) { + BT_ERR("Frame is too long (len %d, expected len %d)", + skb->len, len); + l2cap_conn_unreliable(conn, ECOMM); + goto drop; + } + + /* Allocate skb for the complete frame including header */ + conn->rx_skb = bluez_skb_alloc(len, GFP_ATOMIC); + if (!conn->rx_skb) goto drop; memcpy(skb_put(conn->rx_skb, skb->len), skb->data, skb->len); @@ -1970,15 +2007,17 @@ static int l2cap_recv_acldata(struct hci if (!conn->rx_len) { BT_ERR("Unexpected continuation frame (len %d)", skb->len); + l2cap_conn_unreliable(conn, ECOMM); goto drop; } if (skb->len > conn->rx_len) { - BT_ERR("Fragment is too large (len %d, expect %d)", + BT_ERR("Fragment is too long (len %d, expected %d)", skb->len, conn->rx_len); kfree_skb(conn->rx_skb); conn->rx_skb = NULL; conn->rx_len = 0; + l2cap_conn_unreliable(conn, ECOMM); goto drop; } diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/rfcomm/Config.in linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/rfcomm/Config.in --- linux-2.4.20-wolk4.1s/net/bluetooth/rfcomm/Config.in 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/rfcomm/Config.in 2003-06-03 20:02:49.000000000 +0200 @@ -0,0 +1,10 @@ +# +# Bluetooth RFCOMM layer configuration +# + +dep_tristate 'RFCOMM protocol support' CONFIG_BLUEZ_RFCOMM $CONFIG_BLUEZ_L2CAP + +if [ "$CONFIG_BLUEZ_RFCOMM" != "n" ]; then + bool ' RFCOMM TTY support' CONFIG_BLUEZ_RFCOMM_TTY +fi + diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/rfcomm/Makefile linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/rfcomm/Makefile --- linux-2.4.20-wolk4.1s/net/bluetooth/rfcomm/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/rfcomm/Makefile 2003-06-03 20:02:49.000000000 +0200 @@ -0,0 +1,11 @@ +# +# Makefile for the Linux Bluetooth RFCOMM layer +# + +O_TARGET := rfcomm.o + +obj-y := core.o sock.o crc.o +obj-$(CONFIG_BLUEZ_RFCOMM_TTY) += tty.o +obj-m += $(O_TARGET) + +include $(TOPDIR)/Rules.make diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/rfcomm/core.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/rfcomm/core.c --- linux-2.4.20-wolk4.1s/net/bluetooth/rfcomm/core.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/rfcomm/core.c 2003-06-03 20:02:49.000000000 +0200 @@ -0,0 +1,1878 @@ +/* + RFCOMM implementation for Linux Bluetooth stack (BlueZ). + Copyright (C) 2002 Maxim Krasnyansky + Copyright (C) 2002 Marcel Holtmann + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + RPN support - Dirk Husemann +*/ + +/* + * RFCOMM core. + * + * $Id: core.c,v 1.46 2002/10/18 20:12:12 maxk Exp $ + */ + +#define __KERNEL_SYSCALLS__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define VERSION "1.0" + +#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG +#undef BT_DBG +#define BT_DBG(D...) +#endif + +struct task_struct *rfcomm_thread; +DECLARE_MUTEX(rfcomm_sem); +unsigned long rfcomm_event; + +static LIST_HEAD(session_list); +static atomic_t terminate, running; + +static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len); +static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci); +static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci); +static int rfcomm_queue_disc(struct rfcomm_dlc *d); +static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type); +static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d); +static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig); +static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len); +static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits); +static void rfcomm_make_uih(struct sk_buff *skb, u8 addr); + +static void rfcomm_process_connect(struct rfcomm_session *s); + +/* ---- RFCOMM frame parsing macros ---- */ +#define __get_dlci(b) ((b & 0xfc) >> 2) +#define __get_channel(b) ((b & 0xf8) >> 3) +#define __get_dir(b) ((b & 0x04) >> 2) +#define __get_type(b) ((b & 0xef)) + +#define __test_ea(b) ((b & 0x01)) +#define __test_cr(b) ((b & 0x02)) +#define __test_pf(b) ((b & 0x10)) + +#define __addr(cr, dlci) (((dlci & 0x3f) << 2) | (cr << 1) | 0x01) +#define __ctrl(type, pf) (((type & 0xef) | (pf << 4))) +#define __dlci(dir, chn) (((chn & 0x1f) << 1) | dir) +#define __srv_channel(dlci) (dlci >> 1) +#define __dir(dlci) (dlci & 0x01) + +#define __len8(len) (((len) << 1) | 1) +#define __len16(len) ((len) << 1) + +/* MCC macros */ +#define __mcc_type(cr, type) (((type << 2) | (cr << 1) | 0x01)) +#define __get_mcc_type(b) ((b & 0xfc) >> 2) +#define __get_mcc_len(b) ((b & 0xfe) >> 1) + +/* RPN macros */ +#define __rpn_line_settings(data, stop, parity) ((data & 0x3) | ((stop & 0x1) << 2) | ((parity & 0x3) << 3)) +#define __get_rpn_data_bits(line) ((line) & 0x3) +#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1) +#define __get_rpn_parity(line) (((line) >> 3) & 0x3) + +/* ---- RFCOMM FCS computation ---- */ + +/* CRC on 2 bytes */ +#define __crc(data) (rfcomm_crc_table[rfcomm_crc_table[0xff ^ data[0]] ^ data[1]]) + +/* FCS on 2 bytes */ +static inline u8 __fcs(u8 *data) +{ + return (0xff - __crc(data)); +} + +/* FCS on 3 bytes */ +static inline u8 __fcs2(u8 *data) +{ + return (0xff - rfcomm_crc_table[__crc(data) ^ data[2]]); +} + +/* Check FCS */ +static inline int __check_fcs(u8 *data, int type, u8 fcs) +{ + u8 f = __crc(data); + + if (type != RFCOMM_UIH) + f = rfcomm_crc_table[f ^ data[2]]; + + return rfcomm_crc_table[f ^ fcs] != 0xcf; +} + +/* ---- L2CAP callbacks ---- */ +static void rfcomm_l2state_change(struct sock *sk) +{ + BT_DBG("%p state %d", sk, sk->state); + rfcomm_schedule(RFCOMM_SCHED_STATE); +} + +static void rfcomm_l2data_ready(struct sock *sk, int bytes) +{ + BT_DBG("%p bytes %d", sk, bytes); + rfcomm_schedule(RFCOMM_SCHED_RX); +} + +static int rfcomm_l2sock_create(struct socket **sock) +{ + int err; + + BT_DBG(""); + + err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock); + if (!err) { + struct sock *sk = (*sock)->sk; + sk->data_ready = rfcomm_l2data_ready; + sk->state_change = rfcomm_l2state_change; + } + return err; +} + +/* ---- RFCOMM DLCs ---- */ +static void rfcomm_dlc_timeout(unsigned long arg) +{ + struct rfcomm_dlc *d = (void *) arg; + + BT_DBG("dlc %p state %ld", d, d->state); + + set_bit(RFCOMM_TIMED_OUT, &d->flags); + rfcomm_dlc_put(d); + rfcomm_schedule(RFCOMM_SCHED_TIMEO); +} + +static void rfcomm_dlc_set_timer(struct rfcomm_dlc *d, long timeout) +{ + BT_DBG("dlc %p state %ld timeout %ld", d, d->state, timeout); + + if (!mod_timer(&d->timer, jiffies + timeout)) + rfcomm_dlc_hold(d); +} + +static void rfcomm_dlc_clear_timer(struct rfcomm_dlc *d) +{ + BT_DBG("dlc %p state %ld", d, d->state); + + if (timer_pending(&d->timer) && del_timer(&d->timer)) + rfcomm_dlc_put(d); +} + +static void rfcomm_dlc_clear_state(struct rfcomm_dlc *d) +{ + BT_DBG("%p", d); + + d->state = BT_OPEN; + d->flags = 0; + d->mscex = 0; + d->mtu = RFCOMM_DEFAULT_MTU; + d->v24_sig = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV; + + d->credits = RFCOMM_MAX_CREDITS; + d->rx_credits = RFCOMM_DEFAULT_CREDITS; +} + +struct rfcomm_dlc *rfcomm_dlc_alloc(int prio) +{ + struct rfcomm_dlc *d = kmalloc(sizeof(*d), prio); + if (!d) + return NULL; + memset(d, 0, sizeof(*d)); + + init_timer(&d->timer); + d->timer.function = rfcomm_dlc_timeout; + d->timer.data = (unsigned long) d; + + skb_queue_head_init(&d->tx_queue); + spin_lock_init(&d->lock); + atomic_set(&d->refcnt, 1); + + rfcomm_dlc_clear_state(d); + + BT_DBG("%p", d); + return d; +} + +void rfcomm_dlc_free(struct rfcomm_dlc *d) +{ + BT_DBG("%p", d); + + skb_queue_purge(&d->tx_queue); + kfree(d); +} + +static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d) +{ + BT_DBG("dlc %p session %p", d, s); + + rfcomm_session_hold(s); + + rfcomm_dlc_hold(d); + list_add(&d->list, &s->dlcs); + d->session = s; +} + +static void rfcomm_dlc_unlink(struct rfcomm_dlc *d) +{ + struct rfcomm_session *s = d->session; + + BT_DBG("dlc %p refcnt %d session %p", d, atomic_read(&d->refcnt), s); + + list_del(&d->list); + d->session = NULL; + rfcomm_dlc_put(d); + + rfcomm_session_put(s); +} + +static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci) +{ + struct rfcomm_dlc *d; + struct list_head *p; + + list_for_each(p, &s->dlcs) { + d = list_entry(p, struct rfcomm_dlc, list); + if (d->dlci == dlci) + return d; + } + return NULL; +} + +static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel) +{ + struct rfcomm_session *s; + u8 dlci = __dlci(0, channel); + int err = 0; + + BT_DBG("dlc %p state %ld %s %s channel %d dlci %d", + d, d->state, batostr(src), batostr(dst), channel, dlci); + + if (dlci < 1 || dlci > 62) + return -EINVAL; + + if (d->state != BT_OPEN && d->state != BT_CLOSED) + return 0; + + s = rfcomm_session_get(src, dst); + if (!s) { + s = rfcomm_session_create(src, dst, &err); + if (!s) + return err; + } + + /* Check if DLCI already exists */ + if (rfcomm_dlc_get(s, dlci)) + return -EBUSY; + + rfcomm_dlc_clear_state(d); + + d->dlci = dlci; + d->addr = __addr(s->initiator, dlci); + d->priority = 7; + + d->state = BT_CONFIG; + rfcomm_dlc_link(s, d); + + d->mtu = s->mtu; + d->credits = s->credits; + + if (s->state == BT_CONNECTED) + rfcomm_send_pn(s, 1, d); + rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT); + return 0; +} + +int rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, u8 channel) +{ + mm_segment_t fs; + int r; + + rfcomm_lock(); + + fs = get_fs(); set_fs(KERNEL_DS); + r = __rfcomm_dlc_open(d, src, dst, channel); + set_fs(fs); + + rfcomm_unlock(); + return r; +} + +static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err) +{ + struct rfcomm_session *s = d->session; + if (!s) + return 0; + + BT_DBG("dlc %p state %ld dlci %d err %d session %p", + d, d->state, d->dlci, err, s); + + switch (d->state) { + case BT_CONNECTED: + case BT_CONFIG: + case BT_CONNECT: + d->state = BT_DISCONN; + if (skb_queue_empty(&d->tx_queue)) { + rfcomm_send_disc(s, d->dlci); + rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT); + } else { + rfcomm_queue_disc(d); + rfcomm_dlc_set_timer(d, RFCOMM_DISC_TIMEOUT * 2); + } + break; + + default: + rfcomm_dlc_clear_timer(d); + + rfcomm_dlc_lock(d); + d->state = BT_CLOSED; + d->state_change(d, err); + rfcomm_dlc_unlock(d); + + skb_queue_purge(&d->tx_queue); + rfcomm_dlc_unlink(d); + } + + return 0; +} + +int rfcomm_dlc_close(struct rfcomm_dlc *d, int err) +{ + mm_segment_t fs; + int r; + + rfcomm_lock(); + + fs = get_fs(); set_fs(KERNEL_DS); + r = __rfcomm_dlc_close(d, err); + set_fs(fs); + + rfcomm_unlock(); + return r; +} + +int rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb) +{ + int len = skb->len; + + if (d->state != BT_CONNECTED) + return -ENOTCONN; + + BT_DBG("dlc %p mtu %d len %d", d, d->mtu, len); + + if (len > d->mtu) + return -EINVAL; + + rfcomm_make_uih(skb, d->addr); + skb_queue_tail(&d->tx_queue, skb); + + if (!test_bit(RFCOMM_TX_THROTTLED, &d->flags)) + rfcomm_schedule(RFCOMM_SCHED_TX); + return len; +} + +void __rfcomm_dlc_throttle(struct rfcomm_dlc *d) +{ + BT_DBG("dlc %p state %ld", d, d->state); + + if (!d->credits) { + d->v24_sig |= RFCOMM_V24_FC; + set_bit(RFCOMM_MSC_PENDING, &d->flags); + } + rfcomm_schedule(RFCOMM_SCHED_TX); +} + +void __rfcomm_dlc_unthrottle(struct rfcomm_dlc *d) +{ + BT_DBG("dlc %p state %ld", d, d->state); + + if (!d->credits) { + d->v24_sig &= ~RFCOMM_V24_FC; + set_bit(RFCOMM_MSC_PENDING, &d->flags); + } + rfcomm_schedule(RFCOMM_SCHED_TX); +} + +/* + Set/get modem status functions use _local_ status i.e. what we report + to the other side. + Remote status is provided by dlc->modem_status() callback. + */ +int rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig) +{ + BT_DBG("dlc %p state %ld v24_sig 0x%x", + d, d->state, v24_sig); + + if (test_bit(RFCOMM_RX_THROTTLED, &d->flags)) + v24_sig |= RFCOMM_V24_FC; + else + v24_sig &= ~RFCOMM_V24_FC; + + d->v24_sig = v24_sig; + + if (!test_and_set_bit(RFCOMM_MSC_PENDING, &d->flags)) + rfcomm_schedule(RFCOMM_SCHED_TX); + + return 0; +} + +int rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig) +{ + BT_DBG("dlc %p state %ld v24_sig 0x%x", + d, d->state, d->v24_sig); + + *v24_sig = d->v24_sig; + return 0; +} + +/* ---- RFCOMM sessions ---- */ +struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state) +{ + struct rfcomm_session *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (!s) + return NULL; + memset(s, 0, sizeof(*s)); + + BT_DBG("session %p sock %p", s, sock); + + INIT_LIST_HEAD(&s->dlcs); + s->state = state; + s->sock = sock; + + s->mtu = RFCOMM_DEFAULT_MTU; + s->credits = RFCOMM_MAX_CREDITS; + + list_add(&s->list, &session_list); + + /* Do not increment module usage count for listeting sessions. + * Otherwise we won't be able to unload the module. */ + if (state != BT_LISTEN) + MOD_INC_USE_COUNT; + return s; +} + +void rfcomm_session_del(struct rfcomm_session *s) +{ + int state = s->state; + + BT_DBG("session %p state %ld", s, s->state); + + list_del(&s->list); + + if (state == BT_CONNECTED) + rfcomm_send_disc(s, 0); + + sock_release(s->sock); + kfree(s); + + if (state != BT_LISTEN) + MOD_DEC_USE_COUNT; +} + +struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst) +{ + struct rfcomm_session *s; + struct list_head *p, *n; + struct bluez_pinfo *pi; + list_for_each_safe(p, n, &session_list) { + s = list_entry(p, struct rfcomm_session, list); + pi = bluez_pi(s->sock->sk); + + if ((!bacmp(src, BDADDR_ANY) || !bacmp(&pi->src, src)) && + !bacmp(&pi->dst, dst)) + return s; + } + return NULL; +} + +void rfcomm_session_close(struct rfcomm_session *s, int err) +{ + struct rfcomm_dlc *d; + struct list_head *p, *n; + + BT_DBG("session %p state %ld err %d", s, s->state, err); + + rfcomm_session_hold(s); + + s->state = BT_CLOSED; + + /* Close all dlcs */ + list_for_each_safe(p, n, &s->dlcs) { + d = list_entry(p, struct rfcomm_dlc, list); + d->state = BT_CLOSED; + __rfcomm_dlc_close(d, err); + } + + rfcomm_session_put(s); +} + +struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst, int *err) +{ + struct rfcomm_session *s = NULL; + struct sockaddr_l2 addr; + struct l2cap_options opts; + struct socket *sock; + int size; + + BT_DBG("%s %s", batostr(src), batostr(dst)); + + *err = rfcomm_l2sock_create(&sock); + if (*err < 0) + return NULL; + + bacpy(&addr.l2_bdaddr, src); + addr.l2_family = AF_BLUETOOTH; + addr.l2_psm = 0; + *err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr)); + if (*err < 0) + goto failed; + + /* Set L2CAP options */ + size = sizeof(opts); + sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size); + + opts.imtu = RFCOMM_MAX_L2CAP_MTU; + sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size); + + s = rfcomm_session_add(sock, BT_BOUND); + if (!s) { + *err = -ENOMEM; + goto failed; + } + + s->initiator = 1; + + bacpy(&addr.l2_bdaddr, dst); + addr.l2_family = AF_BLUETOOTH; + addr.l2_psm = htobs(RFCOMM_PSM); + *err = sock->ops->connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK); + if (*err == 0 || *err == -EAGAIN) + return s; + + rfcomm_session_del(s); + return NULL; + +failed: + sock_release(sock); + return NULL; +} + +void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *dst) +{ + struct sock *sk = s->sock->sk; + if (src) + bacpy(src, &bluez_pi(sk)->src); + if (dst) + bacpy(dst, &bluez_pi(sk)->dst); +} + +/* ---- RFCOMM frame sending ---- */ +static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len) +{ + struct socket *sock = s->sock; + struct iovec iv = { data, len }; + struct msghdr msg; + int err; + + BT_DBG("session %p len %d", s, len); + + memset(&msg, 0, sizeof(msg)); + msg.msg_iovlen = 1; + msg.msg_iov = &iv; + + err = sock->ops->sendmsg(sock, &msg, len, 0); + return err; +} + +static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci) +{ + struct rfcomm_cmd cmd; + + BT_DBG("%p dlci %d", s, dlci); + + cmd.addr = __addr(s->initiator, dlci); + cmd.ctrl = __ctrl(RFCOMM_SABM, 1); + cmd.len = __len8(0); + cmd.fcs = __fcs2((u8 *) &cmd); + + return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd)); +} + +static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci) +{ + struct rfcomm_cmd cmd; + + BT_DBG("%p dlci %d", s, dlci); + + cmd.addr = __addr(!s->initiator, dlci); + cmd.ctrl = __ctrl(RFCOMM_UA, 1); + cmd.len = __len8(0); + cmd.fcs = __fcs2((u8 *) &cmd); + + return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd)); +} + +static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci) +{ + struct rfcomm_cmd cmd; + + BT_DBG("%p dlci %d", s, dlci); + + cmd.addr = __addr(s->initiator, dlci); + cmd.ctrl = __ctrl(RFCOMM_DISC, 1); + cmd.len = __len8(0); + cmd.fcs = __fcs2((u8 *) &cmd); + + return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd)); +} + +static int rfcomm_queue_disc(struct rfcomm_dlc *d) +{ + struct rfcomm_cmd *cmd; + struct sk_buff *skb; + + BT_DBG("dlc %p dlci %d", d, d->dlci); + + skb = alloc_skb(sizeof(*cmd), GFP_KERNEL); + if (!skb) + return -ENOMEM; + + cmd = (void *) __skb_put(skb, sizeof(*cmd)); + cmd->addr = d->addr; + cmd->ctrl = __ctrl(RFCOMM_DISC, 1); + cmd->len = __len8(0); + cmd->fcs = __fcs2((u8 *) cmd); + + skb_queue_tail(&d->tx_queue, skb); + rfcomm_schedule(RFCOMM_SCHED_TX); + return 0; +} + +static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci) +{ + struct rfcomm_cmd cmd; + + BT_DBG("%p dlci %d", s, dlci); + + cmd.addr = __addr(!s->initiator, dlci); + cmd.ctrl = __ctrl(RFCOMM_DM, 1); + cmd.len = __len8(0); + cmd.fcs = __fcs2((u8 *) &cmd); + + return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd)); +} + +static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type) +{ + struct rfcomm_hdr *hdr; + struct rfcomm_mcc *mcc; + u8 buf[16], *ptr = buf; + + BT_DBG("%p cr %d type %d", s, cr, type); + + hdr = (void *) ptr; ptr += sizeof(*hdr); + hdr->addr = __addr(s->initiator, 0); + hdr->ctrl = __ctrl(RFCOMM_UIH, 0); + hdr->len = __len8(sizeof(*mcc) + 1); + + mcc = (void *) ptr; ptr += sizeof(*mcc); + mcc->type = __mcc_type(s->initiator, RFCOMM_NSC); + mcc->len = __len8(1); + + /* Type that we didn't like */ + *ptr = __mcc_type(cr, type); ptr++; + + *ptr = __fcs(buf); ptr++; + + return rfcomm_send_frame(s, buf, ptr - buf); +} + +static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d) +{ + struct rfcomm_hdr *hdr; + struct rfcomm_mcc *mcc; + struct rfcomm_pn *pn; + u8 buf[16], *ptr = buf; + + BT_DBG("%p cr %d dlci %d mtu %d", s, cr, d->dlci, d->mtu); + + hdr = (void *) ptr; ptr += sizeof(*hdr); + hdr->addr = __addr(s->initiator, 0); + hdr->ctrl = __ctrl(RFCOMM_UIH, 0); + hdr->len = __len8(sizeof(*mcc) + sizeof(*pn)); + + mcc = (void *) ptr; ptr += sizeof(*mcc); + mcc->type = __mcc_type(s->initiator, RFCOMM_PN); + mcc->len = __len8(sizeof(*pn)); + + pn = (void *) ptr; ptr += sizeof(*pn); + pn->dlci = d->dlci; + pn->priority = d->priority; + pn->ack_timer = 0; + pn->max_retrans = 0; + + if (d->credits) { + pn->flow_ctrl = cr ? 0xf0 : 0xe0; + pn->credits = RFCOMM_DEFAULT_CREDITS; + } else { + pn->flow_ctrl = 0; + pn->credits = 0; + } + + pn->mtu = htobs(d->mtu); + + *ptr = __fcs(buf); ptr++; + + return rfcomm_send_frame(s, buf, ptr - buf); +} + +static int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci, + u8 bit_rate, u8 data_bits, u8 stop_bits, + u8 parity, u8 flow_ctrl_settings, + u8 xon_char, u8 xoff_char, u16 param_mask) +{ + struct rfcomm_hdr *hdr; + struct rfcomm_mcc *mcc; + struct rfcomm_rpn *rpn; + u8 buf[16], *ptr = buf; + + BT_DBG("%p cr %d dlci %d bit_r 0x%x data_b 0x%x stop_b 0x%x parity 0x%x" + "flwc_s 0x%x xon_c 0x%x xoff_c 0x%x p_mask 0x%x", + s, cr, dlci, bit_rate, data_bits, stop_bits, parity, + flow_ctrl_settings, xon_char, xoff_char, param_mask); + + hdr = (void *) ptr; ptr += sizeof(*hdr); + hdr->addr = __addr(s->initiator, 0); + hdr->ctrl = __ctrl(RFCOMM_UIH, 0); + hdr->len = __len8(sizeof(*mcc) + sizeof(*rpn)); + + mcc = (void *) ptr; ptr += sizeof(*mcc); + mcc->type = __mcc_type(cr, RFCOMM_RPN); + mcc->len = __len8(sizeof(*rpn)); + + rpn = (void *) ptr; ptr += sizeof(*rpn); + rpn->dlci = __addr(1, dlci); + rpn->bit_rate = bit_rate; + rpn->line_settings = __rpn_line_settings(data_bits, stop_bits, parity); + rpn->flow_ctrl = flow_ctrl_settings; + rpn->xon_char = xon_char; + rpn->xoff_char = xoff_char; + rpn->param_mask = param_mask; + + *ptr = __fcs(buf); ptr++; + + return rfcomm_send_frame(s, buf, ptr - buf); +} + +static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status) +{ + struct rfcomm_hdr *hdr; + struct rfcomm_mcc *mcc; + struct rfcomm_rls *rls; + u8 buf[16], *ptr = buf; + + BT_DBG("%p cr %d status 0x%x", s, cr, status); + + hdr = (void *) ptr; ptr += sizeof(*hdr); + hdr->addr = __addr(s->initiator, 0); + hdr->ctrl = __ctrl(RFCOMM_UIH, 0); + hdr->len = __len8(sizeof(*mcc) + sizeof(*rls)); + + mcc = (void *) ptr; ptr += sizeof(*mcc); + mcc->type = __mcc_type(cr, RFCOMM_RLS); + mcc->len = __len8(sizeof(*rls)); + + rls = (void *) ptr; ptr += sizeof(*rls); + rls->dlci = __addr(1, dlci); + rls->status = status; + + *ptr = __fcs(buf); ptr++; + + return rfcomm_send_frame(s, buf, ptr - buf); +} + +static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig) +{ + struct rfcomm_hdr *hdr; + struct rfcomm_mcc *mcc; + struct rfcomm_msc *msc; + u8 buf[16], *ptr = buf; + + BT_DBG("%p cr %d v24 0x%x", s, cr, v24_sig); + + hdr = (void *) ptr; ptr += sizeof(*hdr); + hdr->addr = __addr(s->initiator, 0); + hdr->ctrl = __ctrl(RFCOMM_UIH, 0); + hdr->len = __len8(sizeof(*mcc) + sizeof(*msc)); + + mcc = (void *) ptr; ptr += sizeof(*mcc); + mcc->type = __mcc_type(cr, RFCOMM_MSC); + mcc->len = __len8(sizeof(*msc)); + + msc = (void *) ptr; ptr += sizeof(*msc); + msc->dlci = __addr(1, dlci); + msc->v24_sig = v24_sig | 0x01; + + *ptr = __fcs(buf); ptr++; + + return rfcomm_send_frame(s, buf, ptr - buf); +} + +static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len) +{ + struct socket *sock = s->sock; + struct iovec iv[3]; + struct msghdr msg; + unsigned char hdr[5], crc[1]; + + if (len > 125) + return -EINVAL; + + BT_DBG("%p cr %d", s, cr); + + hdr[0] = __addr(s->initiator, 0); + hdr[1] = __ctrl(RFCOMM_UIH, 0); + hdr[2] = 0x01 | ((len + 2) << 1); + hdr[3] = 0x01 | ((cr & 0x01) << 1) | (RFCOMM_TEST << 2); + hdr[4] = 0x01 | (len << 1); + + crc[0] = __fcs(hdr); + + iv[0].iov_base = hdr; + iv[0].iov_len = 5; + iv[1].iov_base = pattern; + iv[1].iov_len = len; + iv[2].iov_base = crc; + iv[2].iov_len = 1; + + memset(&msg, 0, sizeof(msg)); + msg.msg_iovlen = 3; + msg.msg_iov = iv; + return sock->ops->sendmsg(sock, &msg, 6 + len, 0); +} + +static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits) +{ + struct rfcomm_hdr *hdr; + u8 buf[16], *ptr = buf; + + BT_DBG("%p addr %d credits %d", s, addr, credits); + + hdr = (void *) ptr; ptr += sizeof(*hdr); + hdr->addr = addr; + hdr->ctrl = __ctrl(RFCOMM_UIH, 1); + hdr->len = __len8(0); + + *ptr = credits; ptr++; + + *ptr = __fcs(buf); ptr++; + + return rfcomm_send_frame(s, buf, ptr - buf); +} + +static void rfcomm_make_uih(struct sk_buff *skb, u8 addr) +{ + struct rfcomm_hdr *hdr; + int len = skb->len; + u8 *crc; + + if (len > 127) { + hdr = (void *) skb_push(skb, 4); + put_unaligned(htobs(__len16(len)), (u16 *) &hdr->len); + } else { + hdr = (void *) skb_push(skb, 3); + hdr->len = __len8(len); + } + hdr->addr = addr; + hdr->ctrl = __ctrl(RFCOMM_UIH, 0); + + crc = skb_put(skb, 1); + *crc = __fcs((void *) hdr); +} + +/* ---- RFCOMM frame reception ---- */ +static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci) +{ + BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); + + if (dlci) { + /* Data channel */ + struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci); + if (!d) { + rfcomm_send_dm(s, dlci); + return 0; + } + + switch (d->state) { + case BT_CONNECT: + rfcomm_dlc_clear_timer(d); + + rfcomm_dlc_lock(d); + d->state = BT_CONNECTED; + d->state_change(d, 0); + rfcomm_dlc_unlock(d); + + rfcomm_send_msc(s, 1, dlci, d->v24_sig); + break; + + case BT_DISCONN: + d->state = BT_CLOSED; + __rfcomm_dlc_close(d, 0); + break; + } + } else { + /* Control channel */ + switch (s->state) { + case BT_CONNECT: + s->state = BT_CONNECTED; + rfcomm_process_connect(s); + break; + } + } + return 0; +} + +static int rfcomm_recv_dm(struct rfcomm_session *s, u8 dlci) +{ + int err = 0; + + BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); + + if (dlci) { + /* Data DLC */ + struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci); + if (d) { + if (d->state == BT_CONNECT || d->state == BT_CONFIG) + err = ECONNREFUSED; + else + err = ECONNRESET; + + d->state = BT_CLOSED; + __rfcomm_dlc_close(d, err); + } + } else { + if (s->state == BT_CONNECT) + err = ECONNREFUSED; + else + err = ECONNRESET; + + s->state = BT_CLOSED; + rfcomm_session_close(s, err); + } + return 0; +} + +static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) +{ + int err = 0; + + BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); + + if (dlci) { + struct rfcomm_dlc *d = rfcomm_dlc_get(s, dlci); + if (d) { + rfcomm_send_ua(s, dlci); + + if (d->state == BT_CONNECT || d->state == BT_CONFIG) + err = ECONNREFUSED; + else + err = ECONNRESET; + + d->state = BT_CLOSED; + __rfcomm_dlc_close(d, err); + } else + rfcomm_send_dm(s, dlci); + + } else { + rfcomm_send_ua(s, 0); + + if (s->state == BT_CONNECT) + err = ECONNREFUSED; + else + err = ECONNRESET; + + s->state = BT_CLOSED; + rfcomm_session_close(s, err); + } + + return 0; +} + +static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci) +{ + struct rfcomm_dlc *d; + u8 channel; + + BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); + + if (!dlci) { + rfcomm_send_ua(s, 0); + + if (s->state == BT_OPEN) { + s->state = BT_CONNECTED; + rfcomm_process_connect(s); + } + return 0; + } + + /* Check if DLC exists */ + d = rfcomm_dlc_get(s, dlci); + if (d) { + if (d->state == BT_OPEN) { + /* DLC was previously opened by PN request */ + rfcomm_send_ua(s, dlci); + + rfcomm_dlc_lock(d); + d->state = BT_CONNECTED; + d->state_change(d, 0); + rfcomm_dlc_unlock(d); + + rfcomm_send_msc(s, 1, dlci, d->v24_sig); + } + return 0; + } + + /* Notify socket layer about incomming connection */ + channel = __srv_channel(dlci); + if (rfcomm_connect_ind(s, channel, &d)) { + d->dlci = dlci; + d->addr = __addr(s->initiator, dlci); + rfcomm_dlc_link(s, d); + + rfcomm_send_ua(s, dlci); + + rfcomm_dlc_lock(d); + d->state = BT_CONNECTED; + d->state_change(d, 0); + rfcomm_dlc_unlock(d); + } else { + rfcomm_send_dm(s, dlci); + } + + return 0; +} + +static int rfcomm_apply_pn(struct rfcomm_dlc *d, int cr, struct rfcomm_pn *pn) +{ + BT_DBG("dlc %p state %ld dlci %d mtu %d fc 0x%x credits %d", + d, d->state, d->dlci, pn->mtu, pn->flow_ctrl, pn->credits); + + if (cr) { + if (pn->flow_ctrl == 0xf0) { + d->tx_credits = pn->credits; + } else { + set_bit(RFCOMM_TX_THROTTLED, &d->flags); + d->credits = 0; + } + } else { + if (pn->flow_ctrl == 0xe0) { + d->tx_credits = pn->credits; + } else { + set_bit(RFCOMM_TX_THROTTLED, &d->flags); + d->credits = 0; + } + } + + d->priority = pn->priority; + + d->mtu = btohs(pn->mtu); + + return 0; +} + +static int rfcomm_recv_pn(struct rfcomm_session *s, int cr, struct sk_buff *skb) +{ + struct rfcomm_pn *pn = (void *) skb->data; + struct rfcomm_dlc *d; + u8 dlci = pn->dlci; + + BT_DBG("session %p state %ld dlci %d", s, s->state, dlci); + + if (!dlci) + return 0; + + d = rfcomm_dlc_get(s, dlci); + if (d) { + if (cr) { + /* PN request */ + rfcomm_apply_pn(d, cr, pn); + rfcomm_send_pn(s, 0, d); + } else { + /* PN response */ + switch (d->state) { + case BT_CONFIG: + rfcomm_apply_pn(d, cr, pn); + + d->state = BT_CONNECT; + rfcomm_send_sabm(s, d->dlci); + break; + } + } + } else { + u8 channel = __srv_channel(dlci); + + if (!cr) + return 0; + + /* PN request for non existing DLC. + * Assume incomming connection. */ + if (rfcomm_connect_ind(s, channel, &d)) { + d->dlci = dlci; + d->addr = __addr(s->initiator, dlci); + rfcomm_dlc_link(s, d); + + rfcomm_apply_pn(d, cr, pn); + + d->state = BT_OPEN; + rfcomm_send_pn(s, 0, d); + } else { + rfcomm_send_dm(s, dlci); + } + } + return 0; +} + +static int rfcomm_recv_rpn(struct rfcomm_session *s, int cr, int len, struct sk_buff *skb) +{ + struct rfcomm_rpn *rpn = (void *) skb->data; + u8 dlci = __get_dlci(rpn->dlci); + + u8 bit_rate = 0; + u8 data_bits = 0; + u8 stop_bits = 0; + u8 parity = 0; + u8 flow_ctrl = 0; + u8 xon_char = 0; + u8 xoff_char = 0; + u16 rpn_mask = RFCOMM_RPN_PM_ALL; + + BT_DBG("dlci %d cr %d len 0x%x bitr 0x%x line 0x%x flow 0x%x xonc 0x%x xoffc 0x%x pm 0x%x", + dlci, cr, len, rpn->bit_rate, rpn->line_settings, rpn->flow_ctrl, + rpn->xon_char, rpn->xoff_char, rpn->param_mask); + + if (!cr) + return 0; + + if (len == 1) { + /* request: return default setting */ + bit_rate = RFCOMM_RPN_BR_115200; + data_bits = RFCOMM_RPN_DATA_8; + stop_bits = RFCOMM_RPN_STOP_1; + parity = RFCOMM_RPN_PARITY_NONE; + flow_ctrl = RFCOMM_RPN_FLOW_NONE; + xon_char = RFCOMM_RPN_XON_CHAR; + xoff_char = RFCOMM_RPN_XOFF_CHAR; + + goto rpn_out; + } + /* check for sane values: ignore/accept bit_rate, 8 bits, 1 stop bit, no parity, + no flow control lines, normal XON/XOFF chars */ + if (rpn->param_mask & RFCOMM_RPN_PM_BITRATE) { + bit_rate = rpn->bit_rate; + if (bit_rate != RFCOMM_RPN_BR_115200) { + BT_DBG("RPN bit rate mismatch 0x%x", bit_rate); + bit_rate = RFCOMM_RPN_BR_115200; + rpn_mask ^= RFCOMM_RPN_PM_BITRATE; + } + } + if (rpn->param_mask & RFCOMM_RPN_PM_DATA) { + data_bits = __get_rpn_data_bits(rpn->line_settings); + if (data_bits != RFCOMM_RPN_DATA_8) { + BT_DBG("RPN data bits mismatch 0x%x", data_bits); + data_bits = RFCOMM_RPN_DATA_8; + rpn_mask ^= RFCOMM_RPN_PM_DATA; + } + } + if (rpn->param_mask & RFCOMM_RPN_PM_STOP) { + stop_bits = __get_rpn_stop_bits(rpn->line_settings); + if (stop_bits != RFCOMM_RPN_STOP_1) { + BT_DBG("RPN stop bits mismatch 0x%x", stop_bits); + stop_bits = RFCOMM_RPN_STOP_1; + rpn_mask ^= RFCOMM_RPN_PM_STOP; + } + } + if (rpn->param_mask & RFCOMM_RPN_PM_PARITY) { + parity = __get_rpn_parity(rpn->line_settings); + if (parity != RFCOMM_RPN_PARITY_NONE) { + BT_DBG("RPN parity mismatch 0x%x", parity); + parity = RFCOMM_RPN_PARITY_NONE; + rpn_mask ^= RFCOMM_RPN_PM_PARITY; + } + } + if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) { + flow_ctrl = rpn->flow_ctrl; + if (flow_ctrl != RFCOMM_RPN_FLOW_NONE) { + BT_DBG("RPN flow ctrl mismatch 0x%x", flow_ctrl); + flow_ctrl = RFCOMM_RPN_FLOW_NONE; + rpn_mask ^= RFCOMM_RPN_PM_FLOW; + } + } + if (rpn->param_mask & RFCOMM_RPN_PM_XON) { + xon_char = rpn->xon_char; + if (xon_char != RFCOMM_RPN_XON_CHAR) { + BT_DBG("RPN XON char mismatch 0x%x", xon_char); + xon_char = RFCOMM_RPN_XON_CHAR; + rpn_mask ^= RFCOMM_RPN_PM_XON; + } + } + if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) { + xoff_char = rpn->xoff_char; + if (xoff_char != RFCOMM_RPN_XOFF_CHAR) { + BT_DBG("RPN XOFF char mismatch 0x%x", xoff_char); + xoff_char = RFCOMM_RPN_XOFF_CHAR; + rpn_mask ^= RFCOMM_RPN_PM_XOFF; + } + } + +rpn_out: + rfcomm_send_rpn(s, 0, dlci, + bit_rate, data_bits, stop_bits, parity, flow_ctrl, + xon_char, xoff_char, rpn_mask); + + return 0; +} + +static int rfcomm_recv_rls(struct rfcomm_session *s, int cr, struct sk_buff *skb) +{ + struct rfcomm_rls *rls = (void *) skb->data; + u8 dlci = __get_dlci(rls->dlci); + + BT_DBG("dlci %d cr %d status 0x%x", dlci, cr, rls->status); + + if (!cr) + return 0; + + /* FIXME: We should probably do something with this + information here. But for now it's sufficient just + to reply -- Bluetooth 1.1 says it's mandatory to + recognise and respond to RLS */ + + rfcomm_send_rls(s, 0, dlci, rls->status); + + return 0; +} + +static int rfcomm_recv_msc(struct rfcomm_session *s, int cr, struct sk_buff *skb) +{ + struct rfcomm_msc *msc = (void *) skb->data; + struct rfcomm_dlc *d; + u8 dlci = __get_dlci(msc->dlci); + + BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig); + + d = rfcomm_dlc_get(s, dlci); + if (!d) + return 0; + + if (cr) { + if (msc->v24_sig & RFCOMM_V24_FC && !d->credits) + set_bit(RFCOMM_TX_THROTTLED, &d->flags); + else + clear_bit(RFCOMM_TX_THROTTLED, &d->flags); + + rfcomm_dlc_lock(d); + if (d->modem_status) + d->modem_status(d, msc->v24_sig); + rfcomm_dlc_unlock(d); + + rfcomm_send_msc(s, 0, dlci, msc->v24_sig); + + d->mscex |= RFCOMM_MSCEX_RX; + } else + d->mscex |= RFCOMM_MSCEX_TX; + + return 0; +} + +static int rfcomm_recv_mcc(struct rfcomm_session *s, struct sk_buff *skb) +{ + struct rfcomm_mcc *mcc = (void *) skb->data; + u8 type, cr, len; + + cr = __test_cr(mcc->type); + type = __get_mcc_type(mcc->type); + len = __get_mcc_len(mcc->len); + + BT_DBG("%p type 0x%x cr %d", s, type, cr); + + skb_pull(skb, 2); + + switch (type) { + case RFCOMM_PN: + rfcomm_recv_pn(s, cr, skb); + break; + + case RFCOMM_RPN: + rfcomm_recv_rpn(s, cr, len, skb); + break; + + case RFCOMM_RLS: + rfcomm_recv_rls(s, cr, skb); + break; + + case RFCOMM_MSC: + rfcomm_recv_msc(s, cr, skb); + break; + + case RFCOMM_TEST: + if (cr) + rfcomm_send_test(s, 0, skb->data, skb->len); + break; + + case RFCOMM_NSC: + break; + + default: + BT_ERR("Unknown control type 0x%02x", type); + rfcomm_send_nsc(s, cr, type); + break; + } + return 0; +} + +static int rfcomm_recv_data(struct rfcomm_session *s, u8 dlci, int pf, struct sk_buff *skb) +{ + struct rfcomm_dlc *d; + + BT_DBG("session %p state %ld dlci %d pf %d", s, s->state, dlci, pf); + + d = rfcomm_dlc_get(s, dlci); + if (!d) { + rfcomm_send_dm(s, dlci); + goto drop; + } + + if (pf && d->credits) { + u8 credits = *(u8 *) skb->data; skb_pull(skb, 1); + + d->tx_credits += credits; + if (d->tx_credits) + clear_bit(RFCOMM_TX_THROTTLED, &d->flags); + } + + if (skb->len && d->state == BT_CONNECTED) { + rfcomm_dlc_lock(d); + d->rx_credits--; + d->data_ready(d, skb); + rfcomm_dlc_unlock(d); + return 0; + } + +drop: + kfree_skb(skb); + return 0; +} + +static int rfcomm_recv_frame(struct rfcomm_session *s, struct sk_buff *skb) +{ + struct rfcomm_hdr *hdr = (void *) skb->data; + u8 type, dlci, fcs; + + dlci = __get_dlci(hdr->addr); + type = __get_type(hdr->ctrl); + + /* Trim FCS */ + skb->len--; skb->tail--; + fcs = *(u8 *) skb->tail; + + if (__check_fcs(skb->data, type, fcs)) { + BT_ERR("bad checksum in packet"); + kfree_skb(skb); + return -EILSEQ; + } + + if (__test_ea(hdr->len)) + skb_pull(skb, 3); + else + skb_pull(skb, 4); + + switch (type) { + case RFCOMM_SABM: + if (__test_pf(hdr->ctrl)) + rfcomm_recv_sabm(s, dlci); + break; + + case RFCOMM_DISC: + if (__test_pf(hdr->ctrl)) + rfcomm_recv_disc(s, dlci); + break; + + case RFCOMM_UA: + if (__test_pf(hdr->ctrl)) + rfcomm_recv_ua(s, dlci); + break; + + case RFCOMM_DM: + rfcomm_recv_dm(s, dlci); + break; + + case RFCOMM_UIH: + if (dlci) + return rfcomm_recv_data(s, dlci, __test_pf(hdr->ctrl), skb); + + rfcomm_recv_mcc(s, skb); + break; + + default: + BT_ERR("Unknown packet type 0x%02x\n", type); + break; + } + kfree_skb(skb); + return 0; +} + +/* ---- Connection and data processing ---- */ + +static void rfcomm_process_connect(struct rfcomm_session *s) +{ + struct rfcomm_dlc *d; + struct list_head *p, *n; + + BT_DBG("session %p state %ld", s, s->state); + + list_for_each_safe(p, n, &s->dlcs) { + d = list_entry(p, struct rfcomm_dlc, list); + if (d->state == BT_CONFIG) { + d->mtu = s->mtu; + rfcomm_send_pn(s, 1, d); + } + } +} + +/* Send data queued for the DLC. + * Return number of frames left in the queue. + */ +static inline int rfcomm_process_tx(struct rfcomm_dlc *d) +{ + struct sk_buff *skb; + int err; + + BT_DBG("dlc %p state %ld credits %d rx_credits %d tx_credits %d", + d, d->state, d->credits, d->rx_credits, d->tx_credits); + + /* Send pending MSC */ + if (test_and_clear_bit(RFCOMM_MSC_PENDING, &d->flags)) + rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); + + if (d->credits) { + /* CFC enabled. + * Give them some credits */ + if (!test_bit(RFCOMM_RX_THROTTLED, &d->flags) && + d->rx_credits <= (d->credits >> 2)) { + rfcomm_send_credits(d->session, d->addr, d->credits - d->rx_credits); + d->rx_credits = d->credits; + } + } else { + /* CFC disabled. + * Give ourselves some credits */ + d->tx_credits = 5; + } + + if (test_bit(RFCOMM_TX_THROTTLED, &d->flags)) + return skb_queue_len(&d->tx_queue); + + while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) { + err = rfcomm_send_frame(d->session, skb->data, skb->len); + if (err < 0) { + skb_queue_head(&d->tx_queue, skb); + break; + } + kfree_skb(skb); + d->tx_credits--; + } + + if (d->credits && !d->tx_credits) { + /* We're out of TX credits. + * Set TX_THROTTLED flag to avoid unnesary wakeups by dlc_send. */ + set_bit(RFCOMM_TX_THROTTLED, &d->flags); + } + + return skb_queue_len(&d->tx_queue); +} + +static inline void rfcomm_process_dlcs(struct rfcomm_session *s) +{ + struct rfcomm_dlc *d; + struct list_head *p, *n; + + BT_DBG("session %p state %ld", s, s->state); + + list_for_each_safe(p, n, &s->dlcs) { + d = list_entry(p, struct rfcomm_dlc, list); + if (test_bit(RFCOMM_TIMED_OUT, &d->flags)) { + __rfcomm_dlc_close(d, ETIMEDOUT); + continue; + } + + if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) && + d->mscex == RFCOMM_MSCEX_OK) + rfcomm_process_tx(d); + } +} + +static inline void rfcomm_process_rx(struct rfcomm_session *s) +{ + struct socket *sock = s->sock; + struct sock *sk = sock->sk; + struct sk_buff *skb; + + BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->receive_queue)); + + /* Get data directly from socket receive queue without copying it. */ + while ((skb = skb_dequeue(&sk->receive_queue))) { + skb_orphan(skb); + rfcomm_recv_frame(s, skb); + } + + if (sk->state == BT_CLOSED) { + if (!s->initiator) + rfcomm_session_put(s); + + rfcomm_session_close(s, sk->err); + } +} + +static inline void rfcomm_accept_connection(struct rfcomm_session *s) +{ + struct socket *sock = s->sock, *nsock; + int err; + + /* Fast check for a new connection. + * Avoids unnesesary socket allocations. */ + if (list_empty(&bluez_pi(sock->sk)->accept_q)) + return; + + BT_DBG("session %p", s); + + nsock = sock_alloc(); + if (!nsock) + return; + + nsock->type = sock->type; + nsock->ops = sock->ops; + + err = sock->ops->accept(sock, nsock, O_NONBLOCK); + if (err < 0) { + sock_release(nsock); + return; + } + + /* Set our callbacks */ + nsock->sk->data_ready = rfcomm_l2data_ready; + nsock->sk->state_change = rfcomm_l2state_change; + + s = rfcomm_session_add(nsock, BT_OPEN); + if (s) + rfcomm_session_hold(s); + else + sock_release(nsock); +} + +static inline void rfcomm_check_connection(struct rfcomm_session *s) +{ + struct sock *sk = s->sock->sk; + + BT_DBG("%p state %ld", s, s->state); + + switch(sk->state) { + case BT_CONNECTED: + s->state = BT_CONNECT; + + /* We can adjust MTU on outgoing sessions. + * L2CAP MTU minus UIH header and FCS. */ + s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5; + + rfcomm_send_sabm(s, 0); + break; + + case BT_CLOSED: + s->state = BT_CLOSED; + rfcomm_session_close(s, sk->err); + break; + } +} + +static inline void rfcomm_process_sessions(void) +{ + struct list_head *p, *n; + + rfcomm_lock(); + + list_for_each_safe(p, n, &session_list) { + struct rfcomm_session *s; + s = list_entry(p, struct rfcomm_session, list); + + if (s->state == BT_LISTEN) { + rfcomm_accept_connection(s); + continue; + } + + rfcomm_session_hold(s); + + switch (s->state) { + case BT_BOUND: + rfcomm_check_connection(s); + break; + + default: + rfcomm_process_rx(s); + break; + } + + rfcomm_process_dlcs(s); + + rfcomm_session_put(s); + } + + rfcomm_unlock(); +} + +static void rfcomm_worker(void) +{ + BT_DBG(""); + + daemonize(); reparent_to_init(); + set_fs(KERNEL_DS); + + while (!atomic_read(&terminate)) { + BT_DBG("worker loop event 0x%lx", rfcomm_event); + + if (!test_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event)) { + /* No pending events. Let's sleep. + * Incomming connections and data will wake us up. */ + set_current_state(TASK_INTERRUPTIBLE); + schedule(); + } + + /* Process stuff */ + clear_bit(RFCOMM_SCHED_WAKEUP, &rfcomm_event); + rfcomm_process_sessions(); + } + set_current_state(TASK_RUNNING); + return; +} + +static int rfcomm_add_listener(bdaddr_t *ba) +{ + struct sockaddr_l2 addr; + struct l2cap_options opts; + struct socket *sock; + struct rfcomm_session *s; + int size, err = 0; + + /* Create socket */ + err = rfcomm_l2sock_create(&sock); + if (err < 0) { + BT_ERR("Create socket failed %d", err); + return err; + } + + /* Bind socket */ + bacpy(&addr.l2_bdaddr, ba); + addr.l2_family = AF_BLUETOOTH; + addr.l2_psm = htobs(RFCOMM_PSM); + err = sock->ops->bind(sock, (struct sockaddr *) &addr, sizeof(addr)); + if (err < 0) { + BT_ERR("Bind failed %d", err); + goto failed; + } + + /* Set L2CAP options */ + size = sizeof(opts); + sock->ops->getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, &size); + + opts.imtu = RFCOMM_MAX_L2CAP_MTU; + sock->ops->setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, (void *)&opts, size); + + /* Start listening on the socket */ + err = sock->ops->listen(sock, 10); + if (err) { + BT_ERR("Listen failed %d", err); + goto failed; + } + + /* Add listening session */ + s = rfcomm_session_add(sock, BT_LISTEN); + if (!s) + goto failed; + + rfcomm_session_hold(s); + return 0; +failed: + sock_release(sock); + return err; +} + +static void rfcomm_kill_listener(void) +{ + struct rfcomm_session *s; + struct list_head *p, *n; + + BT_DBG(""); + + list_for_each_safe(p, n, &session_list) { + s = list_entry(p, struct rfcomm_session, list); + rfcomm_session_del(s); + } +} + +static int rfcomm_run(void *unused) +{ + rfcomm_thread = current; + + atomic_inc(&running); + + daemonize(); reparent_to_init(); + + sigfillset(¤t->blocked); + set_fs(KERNEL_DS); + + sprintf(current->comm, "krfcommd"); + + BT_DBG(""); + + rfcomm_add_listener(BDADDR_ANY); + + rfcomm_worker(); + + rfcomm_kill_listener(); + + atomic_dec(&running); + return 0; +} + +/* ---- Proc fs support ---- */ +static int rfcomm_dlc_dump(char *buf) +{ + struct rfcomm_session *s; + struct sock *sk; + struct list_head *p, *pp; + char *ptr = buf; + + rfcomm_lock(); + + list_for_each(p, &session_list) { + s = list_entry(p, struct rfcomm_session, list); + sk = s->sock->sk; + + list_for_each(pp, &s->dlcs) { + struct rfcomm_dlc *d; + d = list_entry(pp, struct rfcomm_dlc, list); + + ptr += sprintf(ptr, "dlc %s %s %ld %d %d %d %d\n", + batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), + d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits); + } + } + + rfcomm_unlock(); + + return ptr - buf; +} + +extern int rfcomm_sock_dump(char *buf); + +static int rfcomm_read_proc(char *buf, char **start, off_t offset, int count, int *eof, void *priv) +{ + char *ptr = buf; + int len; + + BT_DBG("count %d, offset %ld", count, offset); + + ptr += rfcomm_dlc_dump(ptr); + ptr += rfcomm_sock_dump(ptr); + len = ptr - buf; + + if (len <= count + offset) + *eof = 1; + + *start = buf + offset; + len -= offset; + + if (len > count) + len = count; + if (len < 0) + len = 0; + + return len; +} + +/* ---- Initialization ---- */ +int __init rfcomm_init(void) +{ + kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + + rfcomm_init_sockets(); + +#ifdef CONFIG_BLUEZ_RFCOMM_TTY + rfcomm_init_ttys(); +#endif + + create_proc_read_entry("bluetooth/rfcomm", 0, 0, rfcomm_read_proc, NULL); + + BT_INFO("BlueZ RFCOMM ver %s", VERSION); + BT_INFO("Copyright (C) 2002 Maxim Krasnyansky "); + BT_INFO("Copyright (C) 2002 Marcel Holtmann "); + return 0; +} + +void rfcomm_cleanup(void) +{ + /* Terminate working thread. + * ie. Set terminate flag and wake it up */ + atomic_inc(&terminate); + rfcomm_schedule(RFCOMM_SCHED_STATE); + + /* Wait until thread is running */ + while (atomic_read(&running)) + schedule(); + + remove_proc_entry("bluetooth/rfcomm", NULL); + +#ifdef CONFIG_BLUEZ_RFCOMM_TTY + rfcomm_cleanup_ttys(); +#endif + + rfcomm_cleanup_sockets(); + return; +} + +module_init(rfcomm_init); +module_exit(rfcomm_cleanup); + +MODULE_AUTHOR("Maxim Krasnyansky , Marcel Holtmann "); +MODULE_DESCRIPTION("BlueZ RFCOMM ver " VERSION); +MODULE_LICENSE("GPL"); diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/rfcomm/crc.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/rfcomm/crc.c --- linux-2.4.20-wolk4.1s/net/bluetooth/rfcomm/crc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/rfcomm/crc.c 2003-06-03 20:02:49.000000000 +0200 @@ -0,0 +1,71 @@ +/* + RFCOMM implementation for Linux Bluetooth stack (BlueZ). + Copyright (C) 2002 Maxim Krasnyansky + Copyright (C) 2002 Marcel Holtmann + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * RFCOMM FCS calculation. + * + * $Id: crc.c,v 1.2 2002/09/21 09:54:32 holtmann Exp $ + */ + +/* reversed, 8-bit, poly=0x07 */ +unsigned char rfcomm_crc_table[256] = { + 0x00, 0x91, 0xe3, 0x72, 0x07, 0x96, 0xe4, 0x75, + 0x0e, 0x9f, 0xed, 0x7c, 0x09, 0x98, 0xea, 0x7b, + 0x1c, 0x8d, 0xff, 0x6e, 0x1b, 0x8a, 0xf8, 0x69, + 0x12, 0x83, 0xf1, 0x60, 0x15, 0x84, 0xf6, 0x67, + + 0x38, 0xa9, 0xdb, 0x4a, 0x3f, 0xae, 0xdc, 0x4d, + 0x36, 0xa7, 0xd5, 0x44, 0x31, 0xa0, 0xd2, 0x43, + 0x24, 0xb5, 0xc7, 0x56, 0x23, 0xb2, 0xc0, 0x51, + 0x2a, 0xbb, 0xc9, 0x58, 0x2d, 0xbc, 0xce, 0x5f, + + 0x70, 0xe1, 0x93, 0x02, 0x77, 0xe6, 0x94, 0x05, + 0x7e, 0xef, 0x9d, 0x0c, 0x79, 0xe8, 0x9a, 0x0b, + 0x6c, 0xfd, 0x8f, 0x1e, 0x6b, 0xfa, 0x88, 0x19, + 0x62, 0xf3, 0x81, 0x10, 0x65, 0xf4, 0x86, 0x17, + + 0x48, 0xd9, 0xab, 0x3a, 0x4f, 0xde, 0xac, 0x3d, + 0x46, 0xd7, 0xa5, 0x34, 0x41, 0xd0, 0xa2, 0x33, + 0x54, 0xc5, 0xb7, 0x26, 0x53, 0xc2, 0xb0, 0x21, + 0x5a, 0xcb, 0xb9, 0x28, 0x5d, 0xcc, 0xbe, 0x2f, + + 0xe0, 0x71, 0x03, 0x92, 0xe7, 0x76, 0x04, 0x95, + 0xee, 0x7f, 0x0d, 0x9c, 0xe9, 0x78, 0x0a, 0x9b, + 0xfc, 0x6d, 0x1f, 0x8e, 0xfb, 0x6a, 0x18, 0x89, + 0xf2, 0x63, 0x11, 0x80, 0xf5, 0x64, 0x16, 0x87, + + 0xd8, 0x49, 0x3b, 0xaa, 0xdf, 0x4e, 0x3c, 0xad, + 0xd6, 0x47, 0x35, 0xa4, 0xd1, 0x40, 0x32, 0xa3, + 0xc4, 0x55, 0x27, 0xb6, 0xc3, 0x52, 0x20, 0xb1, + 0xca, 0x5b, 0x29, 0xb8, 0xcd, 0x5c, 0x2e, 0xbf, + + 0x90, 0x01, 0x73, 0xe2, 0x97, 0x06, 0x74, 0xe5, + 0x9e, 0x0f, 0x7d, 0xec, 0x99, 0x08, 0x7a, 0xeb, + 0x8c, 0x1d, 0x6f, 0xfe, 0x8b, 0x1a, 0x68, 0xf9, + 0x82, 0x13, 0x61, 0xf0, 0x85, 0x14, 0x66, 0xf7, + + 0xa8, 0x39, 0x4b, 0xda, 0xaf, 0x3e, 0x4c, 0xdd, + 0xa6, 0x37, 0x45, 0xd4, 0xa1, 0x30, 0x42, 0xd3, + 0xb4, 0x25, 0x57, 0xc6, 0xb3, 0x22, 0x50, 0xc1, + 0xba, 0x2b, 0x59, 0xc8, 0xbd, 0x2c, 0x5e, 0xcf +}; diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/rfcomm/sock.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/rfcomm/sock.c --- linux-2.4.20-wolk4.1s/net/bluetooth/rfcomm/sock.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/rfcomm/sock.c 2003-06-03 20:02:49.000000000 +0200 @@ -0,0 +1,847 @@ +/* + RFCOMM implementation for Linux Bluetooth stack (BlueZ). + Copyright (C) 2002 Maxim Krasnyansky + Copyright (C) 2002 Marcel Holtmann + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * RFCOMM sockets. + * + * $Id: sock.c,v 1.30 2002/10/18 20:12:12 maxk Exp $ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG +#undef BT_DBG +#define BT_DBG(D...) +#endif + +static struct proto_ops rfcomm_sock_ops; + +static struct bluez_sock_list rfcomm_sk_list = { + lock: RW_LOCK_UNLOCKED +}; + +static void rfcomm_sock_close(struct sock *sk); +static void rfcomm_sock_kill(struct sock *sk); + +/* ---- DLC callbacks ---- + * + * called under rfcomm_dlc_lock() + */ +static void rfcomm_sk_data_ready(struct rfcomm_dlc *d, struct sk_buff *skb) +{ + struct sock *sk = d->owner; + if (!sk) + return; + + atomic_add(skb->len, &sk->rmem_alloc); + skb_queue_tail(&sk->receive_queue, skb); + sk->data_ready(sk, skb->len); + + if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) + rfcomm_dlc_throttle(d); +} + +static void rfcomm_sk_state_change(struct rfcomm_dlc *d, int err) +{ + struct sock *sk = d->owner, *parent; + if (!sk) + return; + + BT_DBG("dlc %p state %ld err %d", d, d->state, err); + + bh_lock_sock(sk); + + if (err) + sk->err = err; + sk->state = d->state; + + parent = bluez_pi(sk)->parent; + if (!parent) { + if (d->state == BT_CONNECTED) + rfcomm_session_getaddr(d->session, &bluez_pi(sk)->src, NULL); + sk->state_change(sk); + } else + parent->data_ready(parent, 0); + + bh_unlock_sock(sk); +} + +/* ---- Socket functions ---- */ +static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src) +{ + struct sock *sk; + + for (sk = rfcomm_sk_list.head; sk; sk = sk->next) { + if (rfcomm_pi(sk)->channel == channel && + !bacmp(&bluez_pi(sk)->src, src)) + break; + } + + return sk; +} + +/* Find socket with channel and source bdaddr. + * Returns closest match. + */ +static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) +{ + struct sock *sk, *sk1 = NULL; + + for (sk = rfcomm_sk_list.head; sk; sk = sk->next) { + if (state && sk->state != state) + continue; + + if (rfcomm_pi(sk)->channel == channel) { + /* Exact match. */ + if (!bacmp(&bluez_pi(sk)->src, src)) + break; + + /* Closest match */ + if (!bacmp(&bluez_pi(sk)->src, BDADDR_ANY)) + sk1 = sk; + } + } + return sk ? sk : sk1; +} + +/* Find socket with given address (channel, src). + * Returns locked socket */ +static inline struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src) +{ + struct sock *s; + read_lock(&rfcomm_sk_list.lock); + s = __rfcomm_get_sock_by_channel(state, channel, src); + if (s) bh_lock_sock(s); + read_unlock(&rfcomm_sk_list.lock); + return s; +} + +static void rfcomm_sock_destruct(struct sock *sk) +{ + struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; + + BT_DBG("sk %p dlc %p", sk, d); + + skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->write_queue); + + rfcomm_dlc_lock(d); + rfcomm_pi(sk)->dlc = NULL; + + /* Detach DLC if it's owned by this socket */ + if (d->owner == sk) + d->owner = NULL; + rfcomm_dlc_unlock(d); + + rfcomm_dlc_put(d); + + MOD_DEC_USE_COUNT; +} + +static void rfcomm_sock_cleanup_listen(struct sock *parent) +{ + struct sock *sk; + + BT_DBG("parent %p", parent); + + /* Close not yet accepted dlcs */ + while ((sk = bluez_accept_dequeue(parent, NULL))) { + rfcomm_sock_close(sk); + rfcomm_sock_kill(sk); + } + + parent->state = BT_CLOSED; + parent->zapped = 1; +} + +/* Kill socket (only if zapped and orphan) + * Must be called on unlocked socket. + */ +static void rfcomm_sock_kill(struct sock *sk) +{ + if (!sk->zapped || sk->socket) + return; + + BT_DBG("sk %p state %d refcnt %d", sk, sk->state, atomic_read(&sk->refcnt)); + + /* Kill poor orphan */ + bluez_sock_unlink(&rfcomm_sk_list, sk); + sk->dead = 1; + sock_put(sk); +} + +static void __rfcomm_sock_close(struct sock *sk) +{ + struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; + + BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket); + + switch (sk->state) { + case BT_LISTEN: + rfcomm_sock_cleanup_listen(sk); + break; + + case BT_CONNECT: + case BT_CONNECT2: + case BT_CONFIG: + case BT_CONNECTED: + rfcomm_dlc_close(d, 0); + + default: + sk->zapped = 1; + break; + } +} + +/* Close socket. + * Must be called on unlocked socket. + */ +static void rfcomm_sock_close(struct sock *sk) +{ + lock_sock(sk); + __rfcomm_sock_close(sk); + release_sock(sk); +} + +static void rfcomm_sock_init(struct sock *sk, struct sock *parent) +{ + BT_DBG("sk %p", sk); + + if (parent) + sk->type = parent->type; +} + +static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio) +{ + struct rfcomm_dlc *d; + struct sock *sk; + + sk = sk_alloc(PF_BLUETOOTH, prio, 1); + if (!sk) + return NULL; + + d = rfcomm_dlc_alloc(prio); + if (!d) { + sk_free(sk); + return NULL; + } + d->data_ready = rfcomm_sk_data_ready; + d->state_change = rfcomm_sk_state_change; + + rfcomm_pi(sk)->dlc = d; + d->owner = sk; + + bluez_sock_init(sock, sk); + + sk->zapped = 0; + + sk->destruct = rfcomm_sock_destruct; + sk->sndtimeo = RFCOMM_CONN_TIMEOUT; + + sk->sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; + sk->rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; + + sk->protocol = proto; + sk->state = BT_OPEN; + + bluez_sock_link(&rfcomm_sk_list, sk); + + BT_DBG("sk %p", sk); + + MOD_INC_USE_COUNT; + return sk; +} + +static int rfcomm_sock_create(struct socket *sock, int protocol) +{ + struct sock *sk; + + BT_DBG("sock %p", sock); + + sock->state = SS_UNCONNECTED; + + if (sock->type != SOCK_STREAM && sock->type != SOCK_RAW) + return -ESOCKTNOSUPPORT; + + sock->ops = &rfcomm_sock_ops; + + if (!(sk = rfcomm_sock_alloc(sock, protocol, GFP_KERNEL))) + return -ENOMEM; + + rfcomm_sock_init(sk, NULL); + return 0; +} + +static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) +{ + struct sockaddr_rc *sa = (struct sockaddr_rc *) addr; + struct sock *sk = sock->sk; + int err = 0; + + BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr)); + + if (!addr || addr->sa_family != AF_BLUETOOTH) + return -EINVAL; + + lock_sock(sk); + + if (sk->state != BT_OPEN) { + err = -EBADFD; + goto done; + } + + write_lock_bh(&rfcomm_sk_list.lock); + + if (sa->rc_channel && __rfcomm_get_sock_by_addr(sa->rc_channel, &sa->rc_bdaddr)) { + err = -EADDRINUSE; + } else { + /* Save source address */ + bacpy(&bluez_pi(sk)->src, &sa->rc_bdaddr); + rfcomm_pi(sk)->channel = sa->rc_channel; + sk->state = BT_BOUND; + } + + write_unlock_bh(&rfcomm_sk_list.lock); + +done: + release_sock(sk); + return err; +} + +static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) +{ + struct sockaddr_rc *sa = (struct sockaddr_rc *) addr; + struct sock *sk = sock->sk; + struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; + int err = 0; + + BT_DBG("sk %p", sk); + + if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc)) + return -EINVAL; + + if (sk->state != BT_OPEN && sk->state != BT_BOUND) + return -EBADFD; + + if (sk->type != SOCK_STREAM) + return -EINVAL; + + lock_sock(sk); + + sk->state = BT_CONNECT; + bacpy(&bluez_pi(sk)->dst, &sa->rc_bdaddr); + rfcomm_pi(sk)->channel = sa->rc_channel; + + err = rfcomm_dlc_open(d, &bluez_pi(sk)->src, &sa->rc_bdaddr, sa->rc_channel); + if (!err) + err = bluez_sock_wait_state(sk, BT_CONNECTED, + sock_sndtimeo(sk, flags & O_NONBLOCK)); + + release_sock(sk); + return err; +} + +int rfcomm_sock_listen(struct socket *sock, int backlog) +{ + struct sock *sk = sock->sk; + int err = 0; + + BT_DBG("sk %p backlog %d", sk, backlog); + + lock_sock(sk); + + if (sk->state != BT_BOUND) { + err = -EBADFD; + goto done; + } + + sk->max_ack_backlog = backlog; + sk->ack_backlog = 0; + sk->state = BT_LISTEN; + +done: + release_sock(sk); + return err; +} + +int rfcomm_sock_accept(struct socket *sock, struct socket *newsock, int flags) +{ + DECLARE_WAITQUEUE(wait, current); + struct sock *sk = sock->sk, *nsk; + long timeo; + int err = 0; + + lock_sock(sk); + + if (sk->state != BT_LISTEN) { + err = -EBADFD; + goto done; + } + + timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); + + BT_DBG("sk %p timeo %ld", sk, timeo); + + /* Wait for an incoming connection. (wake-one). */ + add_wait_queue_exclusive(sk->sleep, &wait); + while (!(nsk = bluez_accept_dequeue(sk, newsock))) { + set_current_state(TASK_INTERRUPTIBLE); + if (!timeo) { + err = -EAGAIN; + break; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + + if (sk->state != BT_LISTEN) { + err = -EBADFD; + break; + } + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + } + set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sleep, &wait); + + if (err) + goto done; + + newsock->state = SS_CONNECTED; + + BT_DBG("new socket %p", nsk); + +done: + release_sock(sk); + return err; +} + +static int rfcomm_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer) +{ + struct sockaddr_rc *sa = (struct sockaddr_rc *) addr; + struct sock *sk = sock->sk; + + BT_DBG("sock %p, sk %p", sock, sk); + + sa->rc_family = AF_BLUETOOTH; + sa->rc_channel = rfcomm_pi(sk)->channel; + if (peer) + bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->dst); + else + bacpy(&sa->rc_bdaddr, &bluez_pi(sk)->src); + + *len = sizeof(struct sockaddr_rc); + return 0; +} + +static int rfcomm_sock_sendmsg(struct socket *sock, struct msghdr *msg, int len, + struct scm_cookie *scm) +{ + struct sock *sk = sock->sk; + struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc; + struct sk_buff *skb; + int err, size; + int sent = 0; + + if (msg->msg_flags & MSG_OOB) + return -EOPNOTSUPP; + + if (sk->shutdown & SEND_SHUTDOWN) + return -EPIPE; + + BT_DBG("sock %p, sk %p", sock, sk); + + lock_sock(sk); + + while (len) { + size = min_t(uint, len, d->mtu); + + skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE, + msg->msg_flags & MSG_DONTWAIT, &err); + if (!skb) + break; + skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE); + + err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); + if (err) { + kfree_skb(skb); + sent = err; + break; + } + + err = rfcomm_dlc_send(d, skb); + if (err < 0) { + kfree_skb(skb); + break; + } + + sent += size; + len -= size; + } + + release_sock(sk); + + return sent ? sent : err; +} + +static long rfcomm_sock_data_wait(struct sock *sk, long timeo) +{ + DECLARE_WAITQUEUE(wait, current); + + add_wait_queue(sk->sleep, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + + if (skb_queue_len(&sk->receive_queue) || sk->err || (sk->shutdown & RCV_SHUTDOWN) || + signal_pending(current) || !timeo) + break; + + set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); + } + + __set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sleep, &wait); + return timeo; +} + +static int rfcomm_sock_recvmsg(struct socket *sock, struct msghdr *msg, int size, + int flags, struct scm_cookie *scm) +{ + struct sock *sk = sock->sk; + int target, err = 0, copied = 0; + long timeo; + + if (flags & MSG_OOB) + return -EOPNOTSUPP; + + msg->msg_namelen = 0; + + BT_DBG("sk %p size %d", sk, size); + + lock_sock(sk); + + target = sock_rcvlowat(sk, flags & MSG_WAITALL, size); + timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); + + do { + struct sk_buff *skb; + int chunk; + + skb = skb_dequeue(&sk->receive_queue); + if (!skb) { + if (copied >= target) + break; + + if ((err = sock_error(sk)) != 0) + break; + if (sk->shutdown & RCV_SHUTDOWN) + break; + + err = -EAGAIN; + if (!timeo) + break; + + timeo = rfcomm_sock_data_wait(sk, timeo); + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + goto out; + } + continue; + } + + chunk = min_t(unsigned int, skb->len, size); + if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { + skb_queue_head(&sk->receive_queue, skb); + if (!copied) + copied = -EFAULT; + break; + } + copied += chunk; + size -= chunk; + + if (!(flags & MSG_PEEK)) { + atomic_sub(chunk, &sk->rmem_alloc); + + skb_pull(skb, chunk); + if (skb->len) { + skb_queue_head(&sk->receive_queue, skb); + break; + } + kfree_skb(skb); + + } else { + /* put message back and return */ + skb_queue_head(&sk->receive_queue, skb); + break; + } + } while (size); + +out: + if (atomic_read(&sk->rmem_alloc) <= (sk->rcvbuf >> 2)) + rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc); + + release_sock(sk); + return copied ? : err; +} + +static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) +{ + struct sock *sk = sock->sk; + int err = 0; + + BT_DBG("sk %p", sk); + + lock_sock(sk); + + switch (optname) { + default: + err = -ENOPROTOOPT; + break; + }; + + release_sock(sk); + return err; +} + +static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) +{ + struct sock *sk = sock->sk; + int len, err = 0; + + BT_DBG("sk %p", sk); + + if (get_user(len, optlen)) + return -EFAULT; + + lock_sock(sk); + + switch (optname) { + default: + err = -ENOPROTOOPT; + break; + }; + + release_sock(sk); + return err; +} + +static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + struct sock *sk = sock->sk; + int err; + + lock_sock(sk); + +#ifdef CONFIG_BLUEZ_RFCOMM_TTY + err = rfcomm_dev_ioctl(sk, cmd, arg); +#else + err = -EOPNOTSUPP; +#endif + + release_sock(sk); + + return err; +} + +static int rfcomm_sock_shutdown(struct socket *sock, int how) +{ + struct sock *sk = sock->sk; + int err = 0; + + BT_DBG("sock %p, sk %p", sock, sk); + + if (!sk) return 0; + + lock_sock(sk); + if (!sk->shutdown) { + sk->shutdown = SHUTDOWN_MASK; + __rfcomm_sock_close(sk); + + if (sk->linger) + err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime); + } + release_sock(sk); + return err; +} + +static int rfcomm_sock_release(struct socket *sock) +{ + struct sock *sk = sock->sk; + int err = 0; + + BT_DBG("sock %p, sk %p", sock, sk); + + if (!sk) + return 0; + + err = rfcomm_sock_shutdown(sock, 2); + + sock_orphan(sk); + rfcomm_sock_kill(sk); + return err; +} + +/* ---- RFCOMM core layer callbacks ---- + * + * called under rfcomm_lock() + */ +int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc **d) +{ + struct sock *sk, *parent; + bdaddr_t src, dst; + int result = 0; + + BT_DBG("session %p channel %d", s, channel); + + rfcomm_session_getaddr(s, &src, &dst); + + /* Check if we have socket listening on this channel */ + parent = rfcomm_get_sock_by_channel(BT_LISTEN, channel, &src); + if (!parent) + return 0; + + /* Check for backlog size */ + if (parent->ack_backlog > parent->max_ack_backlog) { + BT_DBG("backlog full %d", parent->ack_backlog); + goto done; + } + + sk = rfcomm_sock_alloc(NULL, BTPROTO_RFCOMM, GFP_ATOMIC); + if (!sk) + goto done; + + rfcomm_sock_init(sk, parent); + bacpy(&bluez_pi(sk)->src, &src); + bacpy(&bluez_pi(sk)->dst, &dst); + rfcomm_pi(sk)->channel = channel; + + sk->state = BT_CONFIG; + bluez_accept_enqueue(parent, sk); + + /* Accept connection and return socket DLC */ + *d = rfcomm_pi(sk)->dlc; + result = 1; + +done: + bh_unlock_sock(parent); + return result; +} + +/* ---- Proc fs support ---- */ +int rfcomm_sock_dump(char *buf) +{ + struct bluez_sock_list *list = &rfcomm_sk_list; + struct rfcomm_pinfo *pi; + struct sock *sk; + char *ptr = buf; + + write_lock_bh(&list->lock); + + for (sk = list->head; sk; sk = sk->next) { + pi = rfcomm_pi(sk); + ptr += sprintf(ptr, "sk %s %s %d %d\n", + batostr(&bluez_pi(sk)->src), batostr(&bluez_pi(sk)->dst), + sk->state, rfcomm_pi(sk)->channel); + } + + write_unlock_bh(&list->lock); + + return ptr - buf; +} + +static struct proto_ops rfcomm_sock_ops = { + family: PF_BLUETOOTH, + release: rfcomm_sock_release, + bind: rfcomm_sock_bind, + connect: rfcomm_sock_connect, + listen: rfcomm_sock_listen, + accept: rfcomm_sock_accept, + getname: rfcomm_sock_getname, + sendmsg: rfcomm_sock_sendmsg, + recvmsg: rfcomm_sock_recvmsg, + shutdown: rfcomm_sock_shutdown, + setsockopt: rfcomm_sock_setsockopt, + getsockopt: rfcomm_sock_getsockopt, + ioctl: rfcomm_sock_ioctl, + poll: bluez_sock_poll, + socketpair: sock_no_socketpair, + mmap: sock_no_mmap +}; + +static struct net_proto_family rfcomm_sock_family_ops = { + family: PF_BLUETOOTH, + create: rfcomm_sock_create +}; + +int rfcomm_init_sockets(void) +{ + int err; + + if ((err = bluez_sock_register(BTPROTO_RFCOMM, &rfcomm_sock_family_ops))) { + BT_ERR("Can't register RFCOMM socket layer"); + return err; + } + + return 0; +} + +void rfcomm_cleanup_sockets(void) +{ + int err; + + /* Unregister socket, protocol and notifier */ + if ((err = bluez_sock_unregister(BTPROTO_RFCOMM))) + BT_ERR("Can't unregister RFCOMM socket layer %d", err); +} diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/rfcomm/tty.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/rfcomm/tty.c --- linux-2.4.20-wolk4.1s/net/bluetooth/rfcomm/tty.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/rfcomm/tty.c 2003-06-03 20:02:49.000000000 +0200 @@ -0,0 +1,945 @@ +/* + RFCOMM implementation for Linux Bluetooth stack (BlueZ). + Copyright (C) 2002 Maxim Krasnyansky + Copyright (C) 2002 Marcel Holtmann + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 as + published by the Free Software Foundation; + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + SOFTWARE IS DISCLAIMED. +*/ + +/* + * RFCOMM TTY. + * + * $Id: tty.c,v 1.26 2002/10/18 20:12:12 maxk Exp $ + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include + +#ifndef CONFIG_BLUEZ_RFCOMM_DEBUG +#undef BT_DBG +#define BT_DBG(D...) +#endif + +#define RFCOMM_TTY_MAGIC 0x6d02 /* magic number for rfcomm struct */ +#define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV /* whole lotta rfcomm devices */ +#define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */ +#define RFCOMM_TTY_MINOR 0 + +struct rfcomm_dev { + struct list_head list; + atomic_t refcnt; + + char name[12]; + int id; + unsigned long flags; + int opened; + int err; + + bdaddr_t src; + bdaddr_t dst; + u8 channel; + + uint modem_status; + + struct rfcomm_dlc *dlc; + struct tty_struct *tty; + wait_queue_head_t wait; + struct tasklet_struct wakeup_task; + + atomic_t wmem_alloc; +}; + +static LIST_HEAD(rfcomm_dev_list); +static rwlock_t rfcomm_dev_lock = RW_LOCK_UNLOCKED; + +static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb); +static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err); +static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig); + +static void rfcomm_tty_wakeup(unsigned long arg); + +/* ---- Device functions ---- */ +static void rfcomm_dev_destruct(struct rfcomm_dev *dev) +{ + struct rfcomm_dlc *dlc = dev->dlc; + + BT_DBG("dev %p dlc %p", dev, dlc); + + rfcomm_dlc_lock(dlc); + /* Detach DLC if it's owned by this dev */ + if (dlc->owner == dev) + dlc->owner = NULL; + rfcomm_dlc_unlock(dlc); + + rfcomm_dlc_put(dlc); + kfree(dev); + + MOD_DEC_USE_COUNT; +} + +static inline void rfcomm_dev_hold(struct rfcomm_dev *dev) +{ + atomic_inc(&dev->refcnt); +} + +static inline void rfcomm_dev_put(struct rfcomm_dev *dev) +{ + if (atomic_dec_and_test(&dev->refcnt)) + rfcomm_dev_destruct(dev); +} + +static struct rfcomm_dev *__rfcomm_dev_get(int id) +{ + struct rfcomm_dev *dev; + struct list_head *p; + + list_for_each(p, &rfcomm_dev_list) { + dev = list_entry(p, struct rfcomm_dev, list); + if (dev->id == id) + return dev; + } + + return NULL; +} + +static inline struct rfcomm_dev *rfcomm_dev_get(int id) +{ + struct rfcomm_dev *dev; + + read_lock(&rfcomm_dev_lock); + dev = __rfcomm_dev_get(id); + read_unlock(&rfcomm_dev_lock); + + if (dev) rfcomm_dev_hold(dev); + return dev; +} + +static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) +{ + struct rfcomm_dev *dev; + struct list_head *head = &rfcomm_dev_list, *p; + int err = 0; + + BT_DBG("id %d channel %d", req->dev_id, req->channel); + + dev = kmalloc(sizeof(struct rfcomm_dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + memset(dev, 0, sizeof(struct rfcomm_dev)); + + write_lock_bh(&rfcomm_dev_lock); + + if (req->dev_id < 0) { + dev->id = 0; + + list_for_each(p, &rfcomm_dev_list) { + if (list_entry(p, struct rfcomm_dev, list)->id != dev->id) + break; + + dev->id++; + head = p; + } + } else { + dev->id = req->dev_id; + + list_for_each(p, &rfcomm_dev_list) { + struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list); + + if (entry->id == dev->id) { + err = -EADDRINUSE; + goto out; + } + + if (entry->id > dev->id - 1) + break; + + head = p; + } + } + + if ((dev->id < 0) || (dev->id > RFCOMM_MAX_DEV - 1)) { + err = -ENFILE; + goto out; + } + + sprintf(dev->name, "rfcomm%d", dev->id); + + list_add(&dev->list, head); + atomic_set(&dev->refcnt, 1); + + bacpy(&dev->src, &req->src); + bacpy(&dev->dst, &req->dst); + dev->channel = req->channel; + + dev->flags = req->flags & + ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC)); + + init_waitqueue_head(&dev->wait); + tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); + + rfcomm_dlc_lock(dlc); + dlc->data_ready = rfcomm_dev_data_ready; + dlc->state_change = rfcomm_dev_state_change; + dlc->modem_status = rfcomm_dev_modem_status; + + dlc->owner = dev; + dev->dlc = dlc; + rfcomm_dlc_unlock(dlc); + + MOD_INC_USE_COUNT; + +out: + write_unlock_bh(&rfcomm_dev_lock); + + if (err) { + kfree(dev); + return err; + } else + return dev->id; +} + +static void rfcomm_dev_del(struct rfcomm_dev *dev) +{ + BT_DBG("dev %p", dev); + + write_lock_bh(&rfcomm_dev_lock); + list_del_init(&dev->list); + write_unlock_bh(&rfcomm_dev_lock); + + rfcomm_dev_put(dev); +} + +/* ---- Send buffer ---- */ + +static inline unsigned int rfcomm_room(struct rfcomm_dlc *dlc) +{ + /* We can't let it be zero, because we don't get a callback + when tx_credits becomes nonzero, hence we'd never wake up */ + return dlc->mtu * (dlc->tx_credits?:1); +} + +static void rfcomm_wfree(struct sk_buff *skb) +{ + struct rfcomm_dev *dev = (void *) skb->sk; + atomic_sub(skb->truesize, &dev->wmem_alloc); + if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags)) + tasklet_schedule(&dev->wakeup_task); + rfcomm_dev_put(dev); +} + +static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev) +{ + rfcomm_dev_hold(dev); + atomic_add(skb->truesize, &dev->wmem_alloc); + skb->sk = (void *) dev; + skb->destructor = rfcomm_wfree; +} + +static struct sk_buff *rfcomm_wmalloc(struct rfcomm_dev *dev, unsigned long size, int force, int priority) +{ + if (force || atomic_read(&dev->wmem_alloc) < rfcomm_room(dev->dlc)) { + struct sk_buff *skb = alloc_skb(size, priority); + if (skb) { + rfcomm_set_owner_w(skb, dev); + return skb; + } + } + return NULL; +} + +/* ---- Device IOCTLs ---- */ + +#define NOCAP_FLAGS ((1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP)) + +static int rfcomm_create_dev(struct sock *sk, unsigned long arg) +{ + struct rfcomm_dev_req req; + struct rfcomm_dlc *dlc; + int id; + + if (copy_from_user(&req, (void *) arg, sizeof(req))) + return -EFAULT; + + BT_DBG("sk %p dev_id %id flags 0x%x", sk, req.dev_id, req.flags); + + if (req.flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) + return -EPERM; + + if (req.flags & (1 << RFCOMM_REUSE_DLC)) { + /* Socket must be connected */ + if (sk->state != BT_CONNECTED) + return -EBADFD; + + dlc = rfcomm_pi(sk)->dlc; + rfcomm_dlc_hold(dlc); + } else { + dlc = rfcomm_dlc_alloc(GFP_KERNEL); + if (!dlc) + return -ENOMEM; + } + + id = rfcomm_dev_add(&req, dlc); + if (id < 0) { + rfcomm_dlc_put(dlc); + return id; + } + + if (req.flags & (1 << RFCOMM_REUSE_DLC)) { + /* DLC is now used by device. + * Socket must be disconnected */ + sk->state = BT_CLOSED; + } + + return id; +} + +static int rfcomm_release_dev(unsigned long arg) +{ + struct rfcomm_dev_req req; + struct rfcomm_dev *dev; + + if (copy_from_user(&req, (void *) arg, sizeof(req))) + return -EFAULT; + + BT_DBG("dev_id %id flags 0x%x", req.dev_id, req.flags); + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (!(dev = rfcomm_dev_get(req.dev_id))) + return -ENODEV; + + if (req.flags & (1 << RFCOMM_HANGUP_NOW)) + rfcomm_dlc_close(dev->dlc, 0); + + rfcomm_dev_del(dev); + rfcomm_dev_put(dev); + return 0; +} + +static int rfcomm_get_dev_list(unsigned long arg) +{ + struct rfcomm_dev_list_req *dl; + struct rfcomm_dev_info *di; + struct list_head *p; + int n = 0, size; + u16 dev_num; + + BT_DBG(""); + + if (get_user(dev_num, (u16 *) arg)) + return -EFAULT; + + if (!dev_num) + return -EINVAL; + + size = sizeof(*dl) + dev_num * sizeof(*di); + + if (verify_area(VERIFY_WRITE, (void *)arg, size)) + return -EFAULT; + + if (!(dl = kmalloc(size, GFP_KERNEL))) + return -ENOMEM; + + di = dl->dev_info; + + read_lock_bh(&rfcomm_dev_lock); + + list_for_each(p, &rfcomm_dev_list) { + struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list); + (di + n)->id = dev->id; + (di + n)->flags = dev->flags; + (di + n)->state = dev->dlc->state; + (di + n)->channel = dev->channel; + bacpy(&(di + n)->src, &dev->src); + bacpy(&(di + n)->dst, &dev->dst); + if (++n >= dev_num) + break; + } + + read_unlock_bh(&rfcomm_dev_lock); + + dl->dev_num = n; + size = sizeof(*dl) + n * sizeof(*di); + + copy_to_user((void *) arg, dl, size); + kfree(dl); + return 0; +} + +static int rfcomm_get_dev_info(unsigned long arg) +{ + struct rfcomm_dev *dev; + struct rfcomm_dev_info di; + int err = 0; + + BT_DBG(""); + + if (copy_from_user(&di, (void *)arg, sizeof(di))) + return -EFAULT; + + if (!(dev = rfcomm_dev_get(di.id))) + return -ENODEV; + + di.flags = dev->flags; + di.channel = dev->channel; + di.state = dev->dlc->state; + bacpy(&di.src, &dev->src); + bacpy(&di.dst, &dev->dst); + + if (copy_to_user((void *)arg, &di, sizeof(di))) + err = -EFAULT; + + rfcomm_dev_put(dev); + return err; +} + +int rfcomm_dev_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) +{ + BT_DBG("cmd %d arg %ld", cmd, arg); + + switch (cmd) { + case RFCOMMCREATEDEV: + return rfcomm_create_dev(sk, arg); + + case RFCOMMRELEASEDEV: + return rfcomm_release_dev(arg); + + case RFCOMMGETDEVLIST: + return rfcomm_get_dev_list(arg); + + case RFCOMMGETDEVINFO: + return rfcomm_get_dev_info(arg); + } + + return -EINVAL; +} + +/* ---- DLC callbacks ---- */ +static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb) +{ + struct rfcomm_dev *dev = dlc->owner; + struct tty_struct *tty; + + if (!dev || !(tty = dev->tty)) { + kfree_skb(skb); + return; + } + + BT_DBG("dlc %p tty %p len %d", dlc, tty, skb->len); + + if (test_bit(TTY_DONT_FLIP, &tty->flags)) { + register int i; + for (i = 0; i < skb->len; i++) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + tty_flip_buffer_push(tty); + + tty_insert_flip_char(tty, skb->data[i], 0); + } + tty_flip_buffer_push(tty); + } else + tty->ldisc.receive_buf(tty, skb->data, NULL, skb->len); + + kfree_skb(skb); +} + +static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err) +{ + struct rfcomm_dev *dev = dlc->owner; + if (!dev) + return; + + BT_DBG("dlc %p dev %p err %d", dlc, dev, err); + + dev->err = err; + wake_up_interruptible(&dev->wait); + + if (dlc->state == BT_CLOSED) { + if (!dev->tty) { + if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) { + rfcomm_dev_hold(dev); + rfcomm_dev_del(dev); + + /* We have to drop DLC lock here, otherwise + * rfcomm_dev_put() will dead lock if it's the last refference */ + rfcomm_dlc_unlock(dlc); + rfcomm_dev_put(dev); + rfcomm_dlc_lock(dlc); + } + } else + tty_hangup(dev->tty); + } +} + +static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig) +{ + struct rfcomm_dev *dev = dlc->owner; + if (!dev) + return; + + BT_DBG("dlc %p dev %p v24_sig 0x%02x", dlc, dev, v24_sig); + + dev->modem_status = + ((v24_sig & RFCOMM_V24_RTC) ? (TIOCM_DSR | TIOCM_DTR) : 0) | + ((v24_sig & RFCOMM_V24_RTR) ? (TIOCM_RTS | TIOCM_CTS) : 0) | + ((v24_sig & RFCOMM_V24_IC) ? TIOCM_RI : 0) | + ((v24_sig & RFCOMM_V24_DV) ? TIOCM_CD : 0); +} + +/* ---- TTY functions ---- */ +static void rfcomm_tty_wakeup(unsigned long arg) +{ + struct rfcomm_dev *dev = (void *) arg; + struct tty_struct *tty = dev->tty; + if (!tty) + return; + + BT_DBG("dev %p tty %p", dev, tty); + + if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + + wake_up_interruptible(&tty->write_wait); +#ifdef SERIAL_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif +} + +static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) +{ + DECLARE_WAITQUEUE(wait, current); + struct rfcomm_dev *dev; + struct rfcomm_dlc *dlc; + int err, id; + + id = MINOR(tty->device) - tty->driver.minor_start; + + BT_DBG("tty %p id %d", tty, id); + + dev = rfcomm_dev_get(id); + if (!dev) + return -ENODEV; + + BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened); + + if (dev->opened++ != 0) + return 0; + + dlc = dev->dlc; + + /* Attach TTY and open DLC */ + + rfcomm_dlc_lock(dlc); + tty->driver_data = dev; + dev->tty = tty; + rfcomm_dlc_unlock(dlc); + set_bit(RFCOMM_TTY_ATTACHED, &dev->flags); + + err = rfcomm_dlc_open(dlc, &dev->src, &dev->dst, dev->channel); + if (err < 0) + return err; + + /* Wait for DLC to connect */ + add_wait_queue(&dev->wait, &wait); + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + + if (dlc->state == BT_CLOSED) { + err = -dev->err; + break; + } + + if (dlc->state == BT_CONNECTED) + break; + + if (signal_pending(current)) { + err = -EINTR; + break; + } + + schedule(); + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&dev->wait, &wait); + + return err; +} + +static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) +{ + struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; + if (!dev) + return; + + BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened); + + if (--dev->opened == 0) { + /* Close DLC and dettach TTY */ + rfcomm_dlc_close(dev->dlc, 0); + + clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags); + tasklet_kill(&dev->wakeup_task); + + rfcomm_dlc_lock(dev->dlc); + tty->driver_data = NULL; + dev->tty = NULL; + rfcomm_dlc_unlock(dev->dlc); + } + + rfcomm_dev_put(dev); +} + +static int rfcomm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) +{ + struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; + struct rfcomm_dlc *dlc = dev->dlc; + struct sk_buff *skb; + int err = 0, sent = 0, size; + + BT_DBG("tty %p from_user %d count %d", tty, from_user, count); + + while (count) { + size = min_t(uint, count, dlc->mtu); + + if (from_user) + skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_KERNEL); + else + skb = rfcomm_wmalloc(dev, size + RFCOMM_SKB_RESERVE, 0, GFP_ATOMIC); + + if (!skb) + break; + + skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE); + + if (from_user) + copy_from_user(skb_put(skb, size), buf + sent, size); + else + memcpy(skb_put(skb, size), buf + sent, size); + + if ((err = rfcomm_dlc_send(dlc, skb)) < 0) { + kfree_skb(skb); + break; + } + + sent += size; + count -= size; + } + + return sent ? sent : err; +} + +static void rfcomm_tty_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; + struct rfcomm_dlc *dlc = dev->dlc; + struct sk_buff *skb; + + BT_DBG("tty %p char %x", tty, ch); + + skb = rfcomm_wmalloc(dev, 1 + RFCOMM_SKB_RESERVE, 1, GFP_ATOMIC); + + if (!skb) + return; + + skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE); + + *(char *)skb_put(skb, 1) = ch; + + if ((rfcomm_dlc_send(dlc, skb)) < 0) + kfree_skb(skb); +} + +static int rfcomm_tty_write_room(struct tty_struct *tty) +{ + struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; + int room; + + BT_DBG("tty %p", tty); + + room = rfcomm_room(dev->dlc) - atomic_read(&dev->wmem_alloc); + if (room < 0) + room = 0; + + return room; +} + +static int rfcomm_tty_set_modem_status(uint cmd, struct rfcomm_dlc *dlc, uint status) +{ + u8 v24_sig, mask; + + BT_DBG("dlc %p cmd 0x%02x", dlc, cmd); + + if (cmd == TIOCMSET) + v24_sig = 0; + else + rfcomm_dlc_get_modem_status(dlc, &v24_sig); + + mask = ((status & TIOCM_DSR) ? RFCOMM_V24_RTC : 0) | + ((status & TIOCM_DTR) ? RFCOMM_V24_RTC : 0) | + ((status & TIOCM_RTS) ? RFCOMM_V24_RTR : 0) | + ((status & TIOCM_CTS) ? RFCOMM_V24_RTR : 0) | + ((status & TIOCM_RI) ? RFCOMM_V24_IC : 0) | + ((status & TIOCM_CD) ? RFCOMM_V24_DV : 0); + + if (cmd == TIOCMBIC) + v24_sig &= ~mask; + else + v24_sig |= mask; + + rfcomm_dlc_set_modem_status(dlc, v24_sig); + return 0; +} + +static int rfcomm_tty_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; + struct rfcomm_dlc *dlc = dev->dlc; + uint status; + int err; + + BT_DBG("tty %p cmd 0x%02x", tty, cmd); + + switch (cmd) { + case TCGETS: + BT_DBG("TCGETS is not supported"); + return -ENOIOCTLCMD; + + case TCSETS: + BT_DBG("TCSETS is not supported"); + return -ENOIOCTLCMD; + + case TIOCMGET: + BT_DBG("TIOCMGET"); + + return put_user(dev->modem_status, (unsigned int *)arg); + + case TIOCMSET: /* Turns on and off the lines as specified by the mask */ + case TIOCMBIS: /* Turns on the lines as specified by the mask */ + case TIOCMBIC: /* Turns off the lines as specified by the mask */ + if ((err = get_user(status, (unsigned int *)arg))) + return err; + return rfcomm_tty_set_modem_status(cmd, dlc, status); + + case TIOCMIWAIT: + BT_DBG("TIOCMIWAIT"); + break; + + case TIOCGICOUNT: + BT_DBG("TIOCGICOUNT"); + break; + + case TIOCGSERIAL: + BT_ERR("TIOCGSERIAL is not supported"); + return -ENOIOCTLCMD; + + case TIOCSSERIAL: + BT_ERR("TIOCSSERIAL is not supported"); + return -ENOIOCTLCMD; + + case TIOCSERGSTRUCT: + BT_ERR("TIOCSERGSTRUCT is not supported"); + return -ENOIOCTLCMD; + + case TIOCSERGETLSR: + BT_ERR("TIOCSERGETLSR is not supported"); + return -ENOIOCTLCMD; + + case TIOCSERCONFIG: + BT_ERR("TIOCSERCONFIG is not supported"); + return -ENOIOCTLCMD; + + default: + return -ENOIOCTLCMD; /* ioctls which we must ignore */ + + } + + return -ENOIOCTLCMD; +} + +#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + +static void rfcomm_tty_set_termios(struct tty_struct *tty, struct termios *old) +{ + BT_DBG("tty %p", tty); + + if ((tty->termios->c_cflag == old->c_cflag) && + (RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old->c_iflag))) + return; + + /* handle turning off CRTSCTS */ + if ((old->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { + BT_DBG("turning off CRTSCTS"); + } +} + +static void rfcomm_tty_throttle(struct tty_struct *tty) +{ + struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; + + BT_DBG("tty %p dev %p", tty, dev); + + rfcomm_dlc_throttle(dev->dlc); +} + +static void rfcomm_tty_unthrottle(struct tty_struct *tty) +{ + struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; + + BT_DBG("tty %p dev %p", tty, dev); + + rfcomm_dlc_unthrottle(dev->dlc); +} + +static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty) +{ + struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; + struct rfcomm_dlc *dlc = dev->dlc; + + BT_DBG("tty %p dev %p", tty, dev); + + if (skb_queue_len(&dlc->tx_queue)) + return dlc->mtu; + + return 0; +} + +static void rfcomm_tty_flush_buffer(struct tty_struct *tty) +{ + struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; + if (!dev) + return; + + BT_DBG("tty %p dev %p", tty, dev); + + skb_queue_purge(&dev->dlc->tx_queue); + + if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && tty->ldisc.write_wakeup) + tty->ldisc.write_wakeup(tty); +} + +static void rfcomm_tty_send_xchar(struct tty_struct *tty, char ch) +{ + BT_DBG("tty %p ch %c", tty, ch); +} + +static void rfcomm_tty_wait_until_sent(struct tty_struct *tty, int timeout) +{ + BT_DBG("tty %p timeout %d", tty, timeout); +} + +static void rfcomm_tty_hangup(struct tty_struct *tty) +{ + struct rfcomm_dev *dev = (struct rfcomm_dev *) tty->driver_data; + if (!dev) + return; + + BT_DBG("tty %p dev %p", tty, dev); + + rfcomm_tty_flush_buffer(tty); + + if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags)) + rfcomm_dev_del(dev); +} + +static int rfcomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused) +{ + return 0; +} + +/* ---- TTY structure ---- */ +static int rfcomm_tty_refcount; /* If we manage several devices */ + +static struct tty_struct *rfcomm_tty_table[RFCOMM_TTY_PORTS]; +static struct termios *rfcomm_tty_termios[RFCOMM_TTY_PORTS]; +static struct termios *rfcomm_tty_termios_locked[RFCOMM_TTY_PORTS]; + +static struct tty_driver rfcomm_tty_driver = { + magic: TTY_DRIVER_MAGIC, + driver_name: "rfcomm", +#ifdef CONFIG_DEVFS_FS + name: "bluetooth/rfcomm/%d", +#else + name: "rfcomm", +#endif + major: RFCOMM_TTY_MAJOR, + minor_start: RFCOMM_TTY_MINOR, + num: RFCOMM_TTY_PORTS, + type: TTY_DRIVER_TYPE_SERIAL, + subtype: SERIAL_TYPE_NORMAL, + flags: TTY_DRIVER_REAL_RAW, + + refcount: &rfcomm_tty_refcount, + table: rfcomm_tty_table, + termios: rfcomm_tty_termios, + termios_locked: rfcomm_tty_termios_locked, + + open: rfcomm_tty_open, + close: rfcomm_tty_close, + put_char: rfcomm_tty_put_char, + write: rfcomm_tty_write, + write_room: rfcomm_tty_write_room, + chars_in_buffer: rfcomm_tty_chars_in_buffer, + flush_buffer: rfcomm_tty_flush_buffer, + ioctl: rfcomm_tty_ioctl, + throttle: rfcomm_tty_throttle, + unthrottle: rfcomm_tty_unthrottle, + set_termios: rfcomm_tty_set_termios, + send_xchar: rfcomm_tty_send_xchar, + stop: NULL, + start: NULL, + hangup: rfcomm_tty_hangup, + wait_until_sent: rfcomm_tty_wait_until_sent, + read_proc: rfcomm_tty_read_proc, +}; + +int rfcomm_init_ttys(void) +{ + int i; + + /* Initalize our global data */ + for (i = 0; i < RFCOMM_TTY_PORTS; i++) + rfcomm_tty_table[i] = NULL; + + /* Register the TTY driver */ + rfcomm_tty_driver.init_termios = tty_std_termios; + rfcomm_tty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + rfcomm_tty_driver.flags = TTY_DRIVER_REAL_RAW; + + if (tty_register_driver(&rfcomm_tty_driver)) { + BT_ERR("Can't register RFCOMM TTY driver"); + return -1; + } + + return 0; +} + +void rfcomm_cleanup_ttys(void) +{ + tty_unregister_driver(&rfcomm_tty_driver); + return; +} diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/sco.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/sco.c --- linux-2.4.20-wolk4.1s/net/bluetooth/sco.c 2002-12-18 01:04:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/sco.c 2003-06-03 20:02:49.000000000 +0200 @@ -332,8 +332,10 @@ static void sco_sock_cleanup_listen(stru BT_DBG("parent %p", parent); /* Close not yet accepted channels */ - while ((sk = bluez_accept_dequeue(parent, NULL))) + while ((sk = bluez_accept_dequeue(parent, NULL))) { sco_sock_close(sk); + sco_sock_kill(sk); + } parent->state = BT_CLOSED; parent->zapped = 1; @@ -388,8 +390,6 @@ static void sco_sock_close(struct sock * }; release_sock(sk); - - sco_sock_kill(sk); } static void sco_sock_init(struct sock *sk, struct sock *parent) @@ -508,7 +508,8 @@ static int sco_sock_connect(struct socke if ((err = sco_connect(sk))) goto done; - err = bluez_sock_w4_connect(sk, flags); + err = bluez_sock_wait_state(sk, BT_CONNECTED, + sock_sndtimeo(sk, flags & O_NONBLOCK)); done: release_sock(sk); @@ -678,7 +679,7 @@ int sco_sock_getsockopt(struct socket *s opts.mtu = sco_pi(sk)->conn->mtu; - BT_INFO("mtu %d", opts.mtu); + BT_DBG("mtu %d", opts.mtu); len = MIN(len, sizeof(opts)); if (copy_to_user(optval, (char *)&opts, len)) @@ -712,16 +713,23 @@ int sco_sock_getsockopt(struct socket *s static int sco_sock_release(struct socket *sock) { struct sock *sk = sock->sk; + int err = 0; BT_DBG("sock %p, sk %p", sock, sk); if (!sk) return 0; - sock_orphan(sk); sco_sock_close(sk); + if (sk->linger) { + lock_sock(sk); + err = bluez_sock_wait_state(sk, BT_CLOSED, sk->lingertime); + release_sock(sk); + } - return 0; + sock_orphan(sk); + sco_sock_kill(sk); + return err; } static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) diff -Naurp linux-2.4.20-wolk4.1s/net/bluetooth/syms.c linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/syms.c --- linux-2.4.20-wolk4.1s/net/bluetooth/syms.c 2002-09-27 23:26:12.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/bluetooth/syms.c 2003-06-03 20:02:49.000000000 +0200 @@ -44,6 +44,9 @@ /* HCI Core */ EXPORT_SYMBOL(hci_register_dev); EXPORT_SYMBOL(hci_unregister_dev); +EXPORT_SYMBOL(hci_suspend_dev); +EXPORT_SYMBOL(hci_resume_dev); + EXPORT_SYMBOL(hci_register_proto); EXPORT_SYMBOL(hci_unregister_proto); @@ -56,7 +59,7 @@ EXPORT_SYMBOL(hci_conn_encrypt); EXPORT_SYMBOL(hci_recv_frame); EXPORT_SYMBOL(hci_send_acl); EXPORT_SYMBOL(hci_send_sco); -EXPORT_SYMBOL(hci_send_raw); +EXPORT_SYMBOL(hci_send_cmd); EXPORT_SYMBOL(hci_si_event); /* BlueZ lib */ @@ -75,4 +78,4 @@ EXPORT_SYMBOL(bluez_sock_recvmsg); EXPORT_SYMBOL(bluez_sock_poll); EXPORT_SYMBOL(bluez_accept_enqueue); EXPORT_SYMBOL(bluez_accept_dequeue); -EXPORT_SYMBOL(bluez_sock_w4_connect); +EXPORT_SYMBOL(bluez_sock_wait_state); diff -Naurp linux-2.4.20-wolk4.1s/net/core/rtnetlink.c linux-2.4.20-wolk4.2-fullkernel/net/core/rtnetlink.c --- linux-2.4.20-wolk4.1s/net/core/rtnetlink.c 2003-05-15 21:52:49.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/core/rtnetlink.c 2003-06-02 17:23:41.000000000 +0200 @@ -396,7 +396,7 @@ err_inval: * Malformed skbs with wrong lengths of messages are discarded silently. */ -extern __inline__ int rtnetlink_rcv_skb(struct sk_buff *skb) +static __inline__ int rtnetlink_rcv_skb(struct sk_buff *skb) { int err; struct nlmsghdr * nlh; diff -Naurp linux-2.4.20-wolk4.1s/net/ipsec/Makefile.ver linux-2.4.20-wolk4.2-fullkernel/net/ipsec/Makefile.ver --- linux-2.4.20-wolk4.1s/net/ipsec/Makefile.ver 2003-05-20 09:56:55.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipsec/Makefile.ver 2003-06-03 11:00:39.000000000 +0200 @@ -1 +1 @@ -IPSECVERSION=super-freeswan-1.99.7 +IPSECVERSION=super-freeswan-1.99.7.2 diff -Naurp linux-2.4.20-wolk4.1s/net/ipsec/ipsec_init.c linux-2.4.20-wolk4.2-fullkernel/net/ipsec/ipsec_init.c --- linux-2.4.20-wolk4.1s/net/ipsec/ipsec_init.c 2003-05-15 21:52:49.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipsec/ipsec_init.c 2003-06-03 11:01:13.000000000 +0200 @@ -135,7 +135,7 @@ ipsec_init(void) #endif /* CONFIG_IPSEC_ENC_3DES */ KLIPS_PRINT(1, "klips_info:ipsec_init: " - "KLIPS startup, FreeS/WAN IPSec version: %s + X.509 Certificate Support v0.9.28\n", + "KLIPS startup, FreeS/WAN IPSec version: %s including X.509 Certificate Support v0.9.30\n", ipsec_version_code()); error |= ipsec_proc_init(); diff -Naurp linux-2.4.20-wolk4.1s/net/ipsec/ipsec_tunnel.c linux-2.4.20-wolk4.2-fullkernel/net/ipsec/ipsec_tunnel.c --- linux-2.4.20-wolk4.1s/net/ipsec/ipsec_tunnel.c 2003-05-15 21:52:49.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipsec/ipsec_tunnel.c 2003-06-01 18:14:59.000000000 +0200 @@ -1032,7 +1032,7 @@ ipsec_tunnel_start_xmit(struct sk_buff * } stats->tx_dropped++; } - default: + default:; /* XXX what do we do with an unknown shunt spi? */ } /* switch (ntohl(outgoing_said.spi)) */ goto cleanup; @@ -1853,7 +1853,7 @@ ipsec_tunnel_start_xmit(struct sk_buff * case 1: iph->tos = 0; break; - default: + default:; } #ifdef NET_21 #ifdef NETDEV_23 diff -Naurp linux-2.4.20-wolk4.1s/net/ipsec/libcrypto/libblowfish/bf_enc.c linux-2.4.20-wolk4.2-fullkernel/net/ipsec/libcrypto/libblowfish/bf_enc.c --- linux-2.4.20-wolk4.1s/net/ipsec/libcrypto/libblowfish/bf_enc.c 2003-05-15 21:52:50.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipsec/libcrypto/libblowfish/bf_enc.c 2003-06-03 11:00:39.000000000 +0200 @@ -72,8 +72,8 @@ to modify the code. void BF_encrypt(BF_LONG *data, const BF_KEY *key) { #ifndef BF_PTR2 - const register BF_LONG *p,*s; - register BF_LONG l,r; + const BF_LONG *p,*s; + BF_LONG l,r; p=key->P; s= &(key->S[0]); @@ -108,7 +108,7 @@ void BF_encrypt(BF_LONG *data, const BF_ data[1]=l&0xffffffffL; data[0]=r&0xffffffffL; #else - register BF_LONG l,r,t,*k; + BF_LONG l,r,t,*k; l=data[0]; r=data[1]; @@ -149,8 +149,8 @@ void BF_encrypt(BF_LONG *data, const BF_ void BF_decrypt(BF_LONG *data, const BF_KEY *key) { #ifndef BF_PTR2 - const register BF_LONG *p,*s; - register BF_LONG l,r; + const BF_LONG *p,*s; + BF_LONG l,r; p=key->P; s= &(key->S[0]); @@ -185,7 +185,7 @@ void BF_decrypt(BF_LONG *data, const BF_ data[1]=l&0xffffffffL; data[0]=r&0xffffffffL; #else - register BF_LONG l,r,t,*k; + BF_LONG l,r,t,*k; l=data[0]; r=data[1]; @@ -224,9 +224,9 @@ void BF_decrypt(BF_LONG *data, const BF_ void BF_cbc_encrypt(const unsigned char *in, unsigned char *out, long length, const BF_KEY *schedule, unsigned char *ivec, int encrypt) { - register BF_LONG tin0,tin1; - register BF_LONG tout0,tout1,xor0,xor1; - register long l=length; + BF_LONG tin0,tin1; + BF_LONG tout0,tout1,xor0,xor1; + long l=length; BF_LONG tin[2]; if (encrypt) diff -Naurp linux-2.4.20-wolk4.1s/net/ipsec/libfreeswan/pfkey_v2_parse.c linux-2.4.20-wolk4.2-fullkernel/net/ipsec/libfreeswan/pfkey_v2_parse.c --- linux-2.4.20-wolk4.1s/net/ipsec/libfreeswan/pfkey_v2_parse.c 2003-05-15 21:52:50.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipsec/libfreeswan/pfkey_v2_parse.c 2003-06-01 18:14:59.000000000 +0200 @@ -1254,7 +1254,7 @@ pfkey_msg_parse(struct sadb_msg *pfkey_m pfkey_v2_sadb_type_string(pfkey_msg->sadb_msg_type)); SENDERR(EINVAL); } - default: + default:; } /* errno must not be set in downward messages */ @@ -1501,7 +1501,7 @@ pfkey_msg_parse(struct sadb_msg *pfkey_m SENDERR(EINVAL); } break; - default: + default:; } if(ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi) <= 255) { DEBUGGING(PF_KEY_DEBUG_PARSE_PROBLEM, @@ -1510,7 +1510,7 @@ pfkey_msg_parse(struct sadb_msg *pfkey_m ntohl(((struct sadb_sa*)(extensions[SADB_EXT_SA]))->sadb_sa_spi)); SENDERR(EINVAL); } - default: + default:; } errlab: diff -Naurp linux-2.4.20-wolk4.1s/net/ipsec/pfkey_v2_parser.c linux-2.4.20-wolk4.2-fullkernel/net/ipsec/pfkey_v2_parser.c --- linux-2.4.20-wolk4.1s/net/ipsec/pfkey_v2_parser.c 2003-05-15 21:52:50.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipsec/pfkey_v2_parser.c 2003-06-01 18:14:59.000000000 +0200 @@ -500,7 +500,7 @@ pfkey_address_process(struct sadb_ext *p "uh, tdb_said.dst doesn't do address family=%d yet, said will be invalid.\n", s->sa_family); } - default: + default:; } /* XXX check if port!=0 */ @@ -4027,7 +4027,7 @@ pfkey_msg_interp(struct sock *sk, struct extr.tdb->tdb_said.proto); } break; - default: + default:; } /* The NULL below causes the default extension parsers to be used */ diff -Naurp linux-2.4.20-wolk4.1s/net/ipv4/ipvs/Config.in linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/Config.in --- linux-2.4.20-wolk4.1s/net/ipv4/ipvs/Config.in 2003-05-15 21:52:51.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/Config.in 2003-06-01 18:15:01.000000000 +0200 @@ -1,13 +1,13 @@ # -# IPVS configuration +# IP VS configuration # mainmenu_option next_comment comment ' IP: Virtual Server Configuration' -tristate 'IP virtual server support (EXPERIMENTAL)' CONFIG_IP_VS +tristate 'virtual server support (EXPERIMENTAL)' CONFIG_IP_VS if [ "$CONFIG_IP_VS" != "n" ]; then bool ' IP virtual server debugging' CONFIG_IP_VS_DEBUG - int ' IPVS connection hash table size (the Nth power of 2)' CONFIG_IP_VS_TAB_BITS 12 + int ' IPVS connection table size (the Nth power of 2)' CONFIG_IP_VS_TAB_BITS 12 comment 'IPVS scheduler' dep_tristate ' round-robin scheduling' CONFIG_IP_VS_RR $CONFIG_IP_VS dep_tristate ' weighted round-robin scheduling' CONFIG_IP_VS_WRR $CONFIG_IP_VS @@ -17,6 +17,8 @@ if [ "$CONFIG_IP_VS" != "n" ]; then dep_tristate ' locality-based least-connection with replication scheduling' CONFIG_IP_VS_LBLCR $CONFIG_IP_VS dep_tristate ' destination hashing scheduling' CONFIG_IP_VS_DH $CONFIG_IP_VS dep_tristate ' source hashing scheduling' CONFIG_IP_VS_SH $CONFIG_IP_VS + dep_tristate ' shortest expected delay scheduling' CONFIG_IP_VS_SED $CONFIG_IP_VS + dep_tristate ' never queue scheduling' CONFIG_IP_VS_NQ $CONFIG_IP_VS comment 'IPVS application helper' dep_tristate ' FTP protocol helper' CONFIG_IP_VS_FTP $CONFIG_IP_VS fi diff -Naurp linux-2.4.20-wolk4.1s/net/ipv4/ipvs/Makefile linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/Makefile --- linux-2.4.20-wolk4.1s/net/ipv4/ipvs/Makefile 2003-05-15 21:52:51.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/Makefile 2003-06-01 18:15:01.000000000 +0200 @@ -31,6 +31,8 @@ obj-$(CONFIG_IP_VS_LBLC) += ip_vs_lblc.o obj-$(CONFIG_IP_VS_LBLCR) += ip_vs_lblcr.o obj-$(CONFIG_IP_VS_DH) += ip_vs_dh.o obj-$(CONFIG_IP_VS_SH) += ip_vs_sh.o +obj-$(CONFIG_IP_VS_SED) += ip_vs_sed.o +obj-$(CONFIG_IP_VS_NQ) += ip_vs_nq.o # IPVS application helpers obj-$(CONFIG_IP_VS_FTP) += ip_vs_ftp.o diff -Naurp linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_conn.c linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_conn.c --- linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_conn.c 2003-05-15 21:52:51.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_conn.c 2003-06-01 18:15:01.000000000 +0200 @@ -5,7 +5,7 @@ * high-performance and highly available server based on a * cluster of servers. * - * Version: $Id: ip_vs_conn.c,v 1.28.2.1 2002/11/14 10:05:23 wensong Exp $ + * Version: $Id: ip_vs_conn.c,v 1.28.2.2 2003/04/11 14:02:35 wensong Exp $ * * Authors: Wensong Zhang * Peter Kese diff -Naurp linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_core.c linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_core.c --- linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_core.c 2003-05-15 21:52:51.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_core.c 2003-06-01 18:15:01.000000000 +0200 @@ -5,7 +5,7 @@ * high-performance and highly available server based on a * cluster of servers. * - * Version: $Id: ip_vs_core.c,v 1.31.2.1 2002/11/14 10:05:23 wensong Exp $ + * Version: $Id: ip_vs_core.c,v 1.31.2.2 2003/04/11 14:02:35 wensong Exp $ * * Authors: Wensong Zhang * Peter Kese diff -Naurp linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_lc.c linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_lc.c --- linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_lc.c 2003-05-15 21:52:51.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_lc.c 2003-06-01 18:15:01.000000000 +0200 @@ -1,7 +1,7 @@ /* * IPVS: Least-Connection Scheduling module * - * Version: $Id: ip_vs_lc.c,v 1.8 2001/10/19 15:05:17 wensong Exp $ + * Version: $Id: ip_vs_lc.c,v 1.8.2.1 2003/04/11 14:02:35 wensong Exp $ * * Authors: Wensong Zhang * diff -Naurp linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_nq.c linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_nq.c --- linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_nq.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_nq.c 2003-06-01 18:15:01.000000000 +0200 @@ -0,0 +1,177 @@ +/* + * IPVS: Never Queue scheduling module + * + * Version: $Id: ip_vs_nq.c,v 1.1.2.1 2003/05/20 17:05:02 wensong Exp $ + * + * Authors: Wensong Zhang + * + * 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. + * + * Changes: + * + */ + +/* + * The NQ algorithm adopts a two-speed model. When there is an idle server + * available, the job will be sent to the idle server, instead of waiting + * for a fast one. When there is no idle server available, the job will be + * sent to the server that minimize its expected delay (The Shortest + * Expected Delay scheduling algorithm). + * + * See the following paper for more information: + * A. Weinrib and S. Shenker, Greed is not enough: Adaptive load sharing + * in large heterogeneous systems. In Proceedings IEEE INFOCOM'88, + * pages 986-994, 1988. + * + * Thanks must go to Marko Buuri for talking NQ to me. + * + * The difference between NQ and SED is that NQ can improve overall + * system utilization. + * + */ + +#include +#include +#include +#include +#include +#include + +#include + + +static int +ip_vs_nq_init_svc(struct ip_vs_service *svc) +{ + return 0; +} + + +static int +ip_vs_nq_done_svc(struct ip_vs_service *svc) +{ + return 0; +} + + +static int +ip_vs_nq_update_svc(struct ip_vs_service *svc) +{ + return 0; +} + + +static inline unsigned int +ip_vs_nq_dest_overhead(struct ip_vs_dest *dest) +{ + /* + * We only use the active connection number in the cost + * calculation here. + */ + return atomic_read(&dest->activeconns) + 1; +} + + +/* + * Weighted Least Connection scheduling + */ +static struct ip_vs_dest * +ip_vs_nq_schedule(struct ip_vs_service *svc, struct iphdr *iph) +{ + register struct list_head *l, *e; + struct ip_vs_dest *dest, *least; + unsigned int loh, doh; + + IP_VS_DBG(6, "ip_vs_nq_schedule(): Scheduling...\n"); + + /* + * We calculate the load of each dest server as follows: + * (server expected overhead) / dest->weight + * + * Remember -- no floats in kernel mode!!! + * The comparison of h1*w2 > h2*w1 is equivalent to that of + * h1/w1 > h2/w2 + * if every weight is larger than zero. + * + * The server with weight=0 is quiesced and will not receive any + * new connections. + */ + + l = &svc->destinations; + for (e=l->next; e!=l; e=e->next) { + least = list_entry(e, struct ip_vs_dest, n_list); + if (atomic_read(&least->weight) > 0) { + loh = ip_vs_nq_dest_overhead(least); + + /* return the server directly if it is idle */ + if (atomic_read(&least->activeconns) == 0) + goto out; + + goto nextstage; + } + } + return NULL; + + /* + * Find the destination with the least load. + */ + nextstage: + for (e=e->next; e!=l; e=e->next) { + dest = list_entry(e, struct ip_vs_dest, n_list); + doh = ip_vs_nq_dest_overhead(dest); + + /* return the server directly if it is idle */ + if (atomic_read(&dest->activeconns) == 0) { + least = dest; + loh = doh; + goto out; + } + + if (loh * atomic_read(&dest->weight) > + doh * atomic_read(&least->weight)) { + least = dest; + loh = doh; + } + } + + out: + IP_VS_DBG(6, "NQ: server %u.%u.%u.%u:%u " + "activeconns %d refcnt %d weight %d overhead %d\n", + NIPQUAD(least->addr), ntohs(least->port), + atomic_read(&least->activeconns), + atomic_read(&least->refcnt), + atomic_read(&least->weight), loh); + + return least; +} + + +static struct ip_vs_scheduler ip_vs_nq_scheduler = +{ + .name = "nq", + .refcnt = ATOMIC_INIT(0), + .module = THIS_MODULE, + .init_service = ip_vs_nq_init_svc, + .done_service = ip_vs_nq_done_svc, + .update_service = ip_vs_nq_update_svc, + .schedule = ip_vs_nq_schedule, +}; + + +static int __init ip_vs_nq_init(void) +{ + INIT_LIST_HEAD(&ip_vs_nq_scheduler.n_list); + return register_ip_vs_scheduler(&ip_vs_nq_scheduler); +} + +static void __exit ip_vs_nq_cleanup(void) +{ + unregister_ip_vs_scheduler(&ip_vs_nq_scheduler); +} + +module_init(ip_vs_nq_init); +module_exit(ip_vs_nq_cleanup); +MODULE_LICENSE("GPL"); diff -Naurp linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_sed.c linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_sed.c --- linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_sed.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_sed.c 2003-06-01 18:15:01.000000000 +0200 @@ -0,0 +1,167 @@ +/* + * IPVS: Shortest Expected Delay scheduling module + * + * Version: $Id: ip_vs_sed.c,v 1.1.2.1 2003/05/20 17:05:02 wensong Exp $ + * + * Authors: Wensong Zhang + * + * 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. + * + * Changes: + * + */ + +/* + * The SED algorithm attempts to minimize each job's expected delay until + * completion. The expected delay that the job will experience is + * (Ci + 1) / Ui if sent to the ith server, in which Ci is the number of + * jobs on the the ith server and Ui is the fixed service rate (weight) of + * the ith server. The SED algorithm adopts a greedy policy that each does + * what is in its own best interest, i.e. to join the queue which would + * minimize its expected delay of completion. + * + * See the following paper for more information: + * A. Weinrib and S. Shenker, Greed is not enough: Adaptive load sharing + * in large heterogeneous systems. In Proceedings IEEE INFOCOM'88, + * pages 986-994, 1988. + * + * Thanks must go to Marko Buuri for talking SED to me. + * + * The difference between SED and WLC is that SED includes the incoming + * job in the cost function (the increment of 1). SED may outperform + * WLC, while scheduling big jobs under larger heterogeneous systems + * (the server weight varies a lot). + * + */ + +#include +#include +#include +#include +#include +#include + +#include + + +static int +ip_vs_sed_init_svc(struct ip_vs_service *svc) +{ + return 0; +} + + +static int +ip_vs_sed_done_svc(struct ip_vs_service *svc) +{ + return 0; +} + + +static int +ip_vs_sed_update_svc(struct ip_vs_service *svc) +{ + return 0; +} + + +static inline unsigned int +ip_vs_sed_dest_overhead(struct ip_vs_dest *dest) +{ + /* + * We only use the active connection number in the cost + * calculation here. + */ + return atomic_read(&dest->activeconns) + 1; +} + + +/* + * Weighted Least Connection scheduling + */ +static struct ip_vs_dest * +ip_vs_sed_schedule(struct ip_vs_service *svc, struct iphdr *iph) +{ + register struct list_head *l, *e; + struct ip_vs_dest *dest, *least; + unsigned int loh, doh; + + IP_VS_DBG(6, "ip_vs_sed_schedule(): Scheduling...\n"); + + /* + * We calculate the load of each dest server as follows: + * (server expected overhead) / dest->weight + * + * Remember -- no floats in kernel mode!!! + * The comparison of h1*w2 > h2*w1 is equivalent to that of + * h1/w1 > h2/w2 + * if every weight is larger than zero. + * + * The server with weight=0 is quiesced and will not receive any + * new connections. + */ + + l = &svc->destinations; + for (e=l->next; e!=l; e=e->next) { + least = list_entry(e, struct ip_vs_dest, n_list); + if (atomic_read(&least->weight) > 0) { + loh = ip_vs_sed_dest_overhead(least); + goto nextstage; + } + } + return NULL; + + /* + * Find the destination with the least load. + */ + nextstage: + for (e=e->next; e!=l; e=e->next) { + dest = list_entry(e, struct ip_vs_dest, n_list); + doh = ip_vs_sed_dest_overhead(dest); + if (loh * atomic_read(&dest->weight) > + doh * atomic_read(&least->weight)) { + least = dest; + loh = doh; + } + } + + IP_VS_DBG(6, "SED: server %u.%u.%u.%u:%u " + "activeconns %d refcnt %d weight %d overhead %d\n", + NIPQUAD(least->addr), ntohs(least->port), + atomic_read(&least->activeconns), + atomic_read(&least->refcnt), + atomic_read(&least->weight), loh); + + return least; +} + + +static struct ip_vs_scheduler ip_vs_sed_scheduler = +{ + .name = "sed", + .refcnt = ATOMIC_INIT(0), + .module = THIS_MODULE, + .init_service = ip_vs_sed_init_svc, + .done_service = ip_vs_sed_done_svc, + .update_service = ip_vs_sed_update_svc, + .schedule = ip_vs_sed_schedule, +}; + + +static int __init ip_vs_sed_init(void) +{ + INIT_LIST_HEAD(&ip_vs_sed_scheduler.n_list); + return register_ip_vs_scheduler(&ip_vs_sed_scheduler); +} + +static void __exit ip_vs_sed_cleanup(void) +{ + unregister_ip_vs_scheduler(&ip_vs_sed_scheduler); +} + +module_init(ip_vs_sed_init); +module_exit(ip_vs_sed_cleanup); +MODULE_LICENSE("GPL"); diff -Naurp linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_timer.c linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_timer.c --- linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_timer.c 2003-05-15 21:52:51.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_timer.c 2003-06-01 18:15:01.000000000 +0200 @@ -5,7 +5,7 @@ * high-performance and highly available server based on a * cluster of servers. * - * Version: $Id: ip_vs_timer.c,v 1.8 2002/01/31 14:33:12 wensong Exp $ + * Version: $Id: ip_vs_timer.c,v 1.8.2.2 2003/05/20 17:05:02 wensong Exp $ * * Authors: Wensong Zhang * Julian Anastasov @@ -245,8 +245,6 @@ void ip_vs_sltimer_init(void) */ init_sltimervecs(); - sltimer_jiffies = jiffies; - init_timer(&slow_timer); slow_timer.function = sltimer_handler; slow_timer.expires = jiffies+SLTIMER_PERIOD; diff -Naurp linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_wlc.c linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_wlc.c --- linux-2.4.20-wolk4.1s/net/ipv4/ipvs/ip_vs_wlc.c 2003-05-15 21:52:51.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipv4/ipvs/ip_vs_wlc.c 2003-06-01 18:15:01.000000000 +0200 @@ -1,7 +1,7 @@ /* * IPVS: Weighted Least-Connection Scheduling module * - * Version: $Id: ip_vs_wlc.c,v 1.10 2002/03/25 12:44:35 wensong Exp $ + * Version: $Id: ip_vs_wlc.c,v 1.10.2.1 2003/04/11 14:02:35 wensong Exp $ * * Authors: Wensong Zhang * Peter Kese diff -Naurp linux-2.4.20-wolk4.1s/net/ipv4/netfilter/ipt_unclean.c linux-2.4.20-wolk4.2-fullkernel/net/ipv4/netfilter/ipt_unclean.c --- linux-2.4.20-wolk4.1s/net/ipv4/netfilter/ipt_unclean.c 2003-05-15 21:52:52.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/net/ipv4/netfilter/ipt_unclean.c 2003-06-02 17:23:42.000000000 +0200 @@ -271,7 +271,6 @@ check_tcp(const struct iphdr *iph, u_int8_t *opt = (u_int8_t *)tcph; u_int8_t *endhdr = (u_int8_t *)tcph + tcph->doff * 4; u_int8_t tcpflags; - int end_of_options = 0; size_t i; /* CHECK: Can't have offset=1: used to override TCP syn-checks. */ @@ -350,21 +349,12 @@ check_tcp(const struct iphdr *iph, for (i = sizeof(struct tcphdr); i < tcph->doff * 4; ) { switch (opt[i]) { case 0: - end_of_options = 1; - i++; - break; case 1: i++; break; default: - /* CHECK: options after EOO. */ - if (end_of_options) { - limpk("TCP option %u after end\n", - opt[i]); - return 0; - } /* CHECK: options at tail. */ - else if (i+1 >= tcph->doff * 4) { + if (i+1 >= tcph->doff * 4) { limpk("TCP option %u at tail\n", opt[i]); return 0; diff -Naurp linux-2.4.20-wolk4.1s/scripts/mkdep.c linux-2.4.20-wolk4.2-fullkernel/scripts/mkdep.c --- linux-2.4.20-wolk4.1s/scripts/mkdep.c 2002-09-27 23:26:13.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/scripts/mkdep.c 2003-06-03 11:58:33.000000000 +0200 @@ -45,8 +45,7 @@ -char __depname[512] = "\n\t@touch "; -#define depname (__depname+9) +char depname[512]; int hasdep; struct path_struct { @@ -75,9 +74,14 @@ do_depname(void) { if (!hasdep) { hasdep = 1; - printf("%s:", depname); - if (g_filename) + if (g_filename) { + /* Source file (*.[cS]) */ + printf("%s:", depname); printf(" %s", g_filename); + } else { + /* header file (*.h) */ + printf("dep_%s +=", depname); + } } } @@ -203,7 +207,8 @@ void handle_include(int start, const cha path->buffer[path->len+len] = '\0'; if (access(path->buffer, F_OK) == 0) { do_depname(); - printf(" \\\n %s", path->buffer); + printf(" \\\n %s $(dep_%s)", path->buffer, + path->buffer); return; } } @@ -520,7 +525,7 @@ cee_CONFIG_word: /* * Generate dependencies for one file. */ -void do_depend(const char * filename, const char * command) +void do_depend(const char * filename) { int mapsize; int pagesizem1 = getpagesize()-1; @@ -559,9 +564,7 @@ void do_depend(const char * filename, co clear_config(); state_machine(map, map+st.st_size); if (hasdep) { - puts(command); - if (*command) - define_precious(filename); + puts(""); } munmap(map, mapsize); @@ -607,7 +610,6 @@ int main(int argc, char **argv) while (--argc > 0) { const char * filename = *++argv; - const char * command = __depname; g_filename = 0; len = strlen(filename); memcpy(depname, filename, len+1); @@ -615,10 +617,9 @@ int main(int argc, char **argv) if (filename[len-1] == 'c' || filename[len-1] == 'S') { depname[len-1] = 'o'; g_filename = filename; - command = ""; } } - do_depend(filename, command); + do_depend(filename); } if (len_precious) { *(str_precious+len_precious) = '\0'; diff -Naurp linux-2.4.20-wolk4.1s/scripts/vlogger/README.vlogger linux-2.4.20-wolk4.2-fullkernel/scripts/vlogger/README.vlogger --- linux-2.4.20-wolk4.1s/scripts/vlogger/README.vlogger 2003-05-15 21:52:53.000000000 +0200 +++ linux-2.4.20-wolk4.2-fullkernel/scripts/vlogger/README.vlogger 2003-06-02 17:24:33.000000000 +0200 @@ -466,7 +466,7 @@ You can switch between logging modes by Change the following options // directory to store log files -#define LOG_DIR "/tmp/log" +#define LOG_DIR "/var/log/vlogger" // your local timezone #define TIMEZONE 7*60*60 // GMT+7