From 95857c645ce6136f948ccc9792897cb9906e8e4e Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:27:05 -0500 Subject: [PATCH] Linux 2.3.15 There's a rather huge patch-set out there now, taking the 2.3.x series to 2.3.15. This has a lot of the merge code I've been sent over the last two weeks, but I will invariably have missed some, if for no other reason than simply that I got absolutely _flooded_ by people sending me patches. One of the more interesting things was the SMP pipe cleanup sent by Richard, but try as I might it was never really stable under load on x86 - not with the plain semaphores in 2.3.14, and not with the patches Andrea had either. I assume Richard tested it on an alpha with the much more well-thought-out atomic operation that the alpha provides. I ended up rewriting the x86 semaphore code (and some of Richards pipe code too, for that matter, to get rid of some races in waking things up), and it doesn't show the problems I saw before, but hey, maybe I just exchanged one set of problems for another set that I can't trigger any more. Give me feedback, please. Other features that don't impact everybody, but are rather major: - ATM support merged in - firewalling is gone (again), replaced by an even more generic netfilter facility. - general networking merges and updates - Various driver updates (ISDN, ISA PnP, sound, fbcon, usb, intelliport, you name it) - make system call return type "long" even if the system call only returns valid data in the lower order bits - we use the high bits for error handling, and some 64-bit architectures care (read: the Merced calling conventions want this because they don't automatically extend the return type - I bet it will be a new portability issue for other programs than just the kernel) Have fun, Linus --- Documentation/00-INDEX | 4 +- Documentation/isdn/INTERFACE | 134 +++- Documentation/isdn/README.HiSax | 7 +- arch/alpha/kernel/Makefile | 2 +- arch/alpha/kernel/semaphore.c | 129 ++++ arch/i386/kernel/Makefile | 2 +- arch/i386/kernel/irq.c | 1 - arch/i386/kernel/semaphore.c | 223 +++++++ arch/i386/kernel/setup.c | 4 +- arch/i386/lib/Makefile | 2 +- arch/i386/lib/semaphore.S | 51 -- arch/i386/mm/init.c | 5 +- drivers/atm/ambassador.h | 2 + drivers/atm/horizon.c | 1 - drivers/atm/horizon.h | 2 + drivers/atm/suni.c | 1 - drivers/atm/uPD98402.c | 1 - drivers/atm/zatm.c | 1 + drivers/atm/zatm.h | 1 + drivers/char/ip2.c | 2 - drivers/char/ip2main.c | 2 - drivers/isdn/Config.in | 2 +- drivers/isdn/avmb1/b1.c | 10 +- drivers/isdn/avmb1/b1isa.c | 10 +- drivers/isdn/avmb1/b1pcmcia.c | 10 +- drivers/isdn/avmb1/t1isa.c | 10 +- drivers/isdn/divert/divert_init.c | 8 +- drivers/isdn/divert/isdn_divert.c | 16 +- drivers/isdn/divert/isdn_divert.h | 8 +- drivers/isdn/eicon/eicon.h | 101 ++- drivers/isdn/eicon/eicon_idi.c | 50 +- drivers/isdn/eicon/eicon_idi.h | 8 +- drivers/isdn/eicon/eicon_io.c | 239 +++++-- drivers/isdn/eicon/eicon_isa.c | 10 +- drivers/isdn/eicon/eicon_mod.c | 83 ++- drivers/isdn/eicon/eicon_pci.c | 10 +- drivers/isdn/hisax/arcofi.c | 9 +- drivers/isdn/hisax/bkm_a4t.c | 10 +- drivers/isdn/hisax/bkm_a8.c | 10 +- drivers/isdn/hisax/callc.c | 106 +-- drivers/isdn/hisax/config.c | 38 +- drivers/isdn/hisax/elsa.c | 32 +- drivers/isdn/hisax/gazel.c | 10 +- drivers/isdn/hisax/hfc_pci.c | 83 ++- drivers/isdn/hisax/hisax.h | 26 +- drivers/isdn/hisax/isac.c | 9 +- drivers/isdn/hisax/isar.c | 111 +++- drivers/isdn/hisax/isar.h | 108 ++-- drivers/isdn/hisax/isdnl1.c | 15 +- drivers/isdn/hisax/isdnl2.c | 9 +- drivers/isdn/hisax/isurf.c | 35 +- drivers/isdn/hisax/l3dss1.c | 41 +- drivers/isdn/hisax/md5sums.asc | 22 +- drivers/isdn/hisax/sedlbauer.c | 19 +- drivers/isdn/icn/icn.c | 27 +- drivers/isdn/isdn_audio.c | 9 +- drivers/isdn/isdn_concap.c | 8 +- drivers/isdn/isdn_net.c | 10 +- drivers/isdn/isdn_net.h | 8 +- drivers/isdn/isdn_ppp.c | 32 +- drivers/isdn/isdn_ppp.h | 8 +- drivers/isdn/isdn_tty.h | 8 +- drivers/isdn/isdn_ttyfax.c | 10 +- drivers/isdn/isdn_x25iface.c | 8 +- drivers/isdn/pcbit/module.c | 19 +- drivers/net/ppp_async.c | 2 +- drivers/net/sb1000.c | 1 - drivers/net/sk_mca.c | 1 - drivers/pci/names.c | 6 +- drivers/pci/pci.c | 4 - drivers/pci/quirks.c | 1 - drivers/scsi/megaraid.c | 1 - drivers/sound/esssolo1.c | 1 - drivers/sound/vwsnd.c | 1 - drivers/usb/Config.in | 2 + drivers/usb/Makefile | 25 +- drivers/usb/acm.c | 36 +- drivers/usb/audio.c | 88 +-- drivers/usb/cpia.c | 117 +++- drivers/usb/cpia.h | 6 + drivers/usb/ezusb.c | 13 +- drivers/usb/ezusb.h | 11 +- drivers/usb/hub.c | 215 +++---- drivers/usb/hub.h | 20 +- drivers/usb/mouse.c | 14 +- drivers/usb/printer.c | 2 +- drivers/usb/proc_usb.c | 254 +++++++- drivers/usb/uhci-debug.c | 157 +++-- drivers/usb/uhci.c | 958 +++++++++++++++++----------- drivers/usb/uhci.h | 38 +- drivers/usb/usb-debug.c | 101 +-- drivers/usb/usb.c | 683 +++++++++++--------- drivers/usb/usb.h | 262 ++++++-- drivers/usb/usb_scsi.c | 8 +- drivers/usb/uss720.c | 5 +- drivers/video/Config.in | 2 +- drivers/video/Makefile | 5 + drivers/video/atyfb.c | 13 +- drivers/video/clgenfb.c | 96 ++- drivers/video/fbmem.c | 13 +- drivers/video/matroxfb.c | 7 +- drivers/video/pm2fb.c | 61 +- drivers/video/vesafb.c | 25 +- drivers/video/vga.h | 1 + drivers/video/vga16fb.c | 30 +- fs/fifo.c | 178 +++--- fs/pipe.c | 429 ++++++++----- include/asm-i386/atomic.h | 8 +- include/asm-i386/io.h | 6 + include/asm-i386/semaphore-helper.h | 102 --- include/asm-i386/semaphore.h | 4 +- include/linux/concap.h | 15 +- include/linux/i2c.h | 2 - include/linux/if_ether.h | 1 + include/linux/isdn.h | 13 +- include/linux/isdn_compat.h | 8 + include/linux/isdnif.h | 5 +- include/linux/msg.h | 22 +- include/linux/netfilter.h | 3 - include/linux/netfilter_ipv4.h | 1 + include/linux/pipe_fs_i.h | 29 +- include/linux/prctl.h | 5 +- include/video/fbcon.h | 21 + ipc/msg.c | 30 +- kernel/module.c | 2 +- kernel/sched.c | 123 ---- kernel/sys.c | 3 + mm/memory.c | 1 - net/802/fc.c | 2 - net/802/llc_macinit.c | 2 +- net/802/p8022.c | 2 +- net/802/psnap.c | 2 +- net/802/tr.c | 2 +- net/appletalk/aarp.c | 2 +- net/appletalk/ddp.c | 2 +- net/atm/atm_misc.c | 1 - net/atm/ipcommon.c | 1 - net/atm/lec.c | 2 +- net/ax25/af_ax25.c | 2 +- net/core/dev.c | 2 +- net/core/dev_mcast.c | 2 +- net/core/dst.c | 2 +- net/core/netfilter.c | 3 +- net/core/profile.c | 4 +- net/core/rtnetlink.c | 2 +- net/ipv4/af_inet.c | 2 +- net/ipv4/arp.c | 2 +- net/ipv4/ip_fragment.c | 1 + net/ipv4/route.c | 2 +- net/ipv4/tcp.c | 1 + net/khttpd/datasending.c | 1 + net/khttpd/main.c | 1 + net/khttpd/sysctl.c | 1 - net/khttpd/userspace.c | 2 + net/khttpd/waitheaders.c | 1 + net/netsyms.c | 2 - net/unix/af_unix.c | 2 +- 157 files changed, 4159 insertions(+), 2183 deletions(-) create mode 100644 arch/alpha/kernel/semaphore.c create mode 100644 arch/i386/kernel/semaphore.c delete mode 100644 arch/i386/lib/semaphore.S delete mode 100644 include/asm-i386/semaphore-helper.h diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX index ea256f2f1747..dc29ec22badd 100644 --- a/Documentation/00-INDEX +++ b/Documentation/00-INDEX @@ -34,7 +34,7 @@ cdrom/ cpqarray.txt - info on using Compaq's SMART2 Intelligent Disk Array Controllers. devices.tex - - TeX source listing of all the nodes in /dev/ with major minor #'s + - LaTeX source listing of all the nodes in /dev/ with major minor #'s devices.txt - plain ASCII listing of all the nodes in /dev/ with major minor #'s digiboard.txt @@ -138,7 +138,7 @@ sgi-visws.txt smart-config.txt - description of the Smart Config makefile feature. smp.tex - - TeX document describing implementation of Multiprocessor Linux + - LaTeX document describing implementation of Multiprocessor Linux smp.txt - a few more notes on symmetric multi-processing sound/ diff --git a/Documentation/isdn/INTERFACE b/Documentation/isdn/INTERFACE index d8bf08ccc63c..c2a5494b1f88 100644 --- a/Documentation/isdn/INTERFACE +++ b/Documentation/isdn/INTERFACE @@ -1,4 +1,4 @@ -$Id: INTERFACE,v 1.13 1999/08/11 20:30:26 armin Exp $ +$Id: INTERFACE,v 1.15 1999/08/25 20:02:13 werner Exp $ Description of the Interface between Linklevel and Hardwarelevel of isdn4linux: @@ -436,6 +436,57 @@ Description of the Interface between Linklevel and Hardwarelevel arg = unused. parm = unused. + ISDN_CMD_PROCEED: + + With this command, the HL-driver is told to proceed with a incoming call. + + Parameter: + driver = driver-Id. + command = ISDN_CMD_PROCEED + arg = channel-number locally to the driver. (starting with 0) + setup.eazmsn= empty string or string send as uus1 in DSS1 with + PROCEED message + + ISDN_CMD_ALERT: + + With this command, the HL-driver is told to alert a proceeding call. + + Parameter: + driver = driver-Id. + command = ISDN_CMD_ALERT + arg = channel-number locally to the driver. (starting with 0) + setup.eazmsn= empty string or string send as uus1 in DSS1 with + ALERT message + + ISDN_CMD_REDIR: + + With this command, the HL-driver is told to redirect a call in proceeding + or alerting state. + + Parameter: + driver = driver-Id. + command = ISDN_CMD_REDIR + arg = channel-number locally to the driver. (starting with 0) + setup.eazmsn= empty string or string send as uus1 in DSS1 protocol + setup.screen= screening indicator + setup.phone = redirected to party number + + ISDN_CMD_PROT_IO: + + With this call, the LL-driver invokes protocol specific features through + the LL. + The call is not implicitely bound to a connection. + + Parameter: + driver = driver-Id + command = ISDN_CMD_PROT_IO + arg = The lower 8 Bits define the adressed protocol as defined + in ISDN_PTYPE..., the upper bits are used to differenciate + the protocol specific CMD. + + para = protocol and function specific. See isdnif.h for detail. + + ISDN_CMD_FAXCMD: With this command the HL-driver receives a fax sub-command. @@ -471,34 +522,44 @@ Description of the Interface between Linklevel and Hardwarelevel parm = unused. ISDN_STAT_ICALL: + ISDN_STAT_ICALLW: With this call, the HL-driver signals an incoming call to the LL. + If ICALLW is signalled the incoming call is a waiting call without + a available B-chan. Parameter: driver = driver-Id command = ISDN_STAT_ICALL arg = channel-number, locally to the driver. (starting with 0) - parm.setup.phone = Callernumber. - parm.setup.eazmsn = CalledNumber. - parm.setup.si1 = Service Indicator. - parm.setup.si2 = Additional Service Indicator. - parm.setup.plan = octet 3 from Calling party number Information Element. - parm.setup.screen = octet 3a from Calling party number Information Element. + para.setup.phone = Callernumber. + para.setup.eazmsn = CalledNumber. + para.setup.si1 = Service Indicator. + para.setup.si2 = Additional Service Indicator. + para.setup.plan = octet 3 from Calling party number Information Element. + para.setup.screen = octet 3a from Calling party number Information Element. Return: 0 = No device matching this call. 1 = At least one device matching this call (RING on ttyI). HL-driver may send ALERTING on the D-channel in this case. 2 = Call will be rejected. - 3 = Incomplete number. - The CalledNumber would match, if more digits are appended. - This feature is needed for Number-Blocks assigned to - a line. In this case, the LL driver should assemble the - CalledNumber by handling keypad protocol and try again - later with a longer CalledNumber. - HL drivers serving ordinary lines should interpret this - return code like 0 (nothing matches). + 3 = Incoming called party number is currently incomplete. + Additional digits are required. + Used for signalling with PtP connections. + 4 = Call will be held in a proceeding state + (HL driver sends PROCEEDING) + Used when a user space prog needs time to interpret a call + para.setup.eazmsn may be filled with an uus1 message of + 30 octets maximum. Empty string if no uus. + 5 = Call will be actively deflected to another party + Only available in DSS1/EURO protocol + para.setup.phone must be set to destination party number + para.setup.eazmsn may be filled with an uus1 message of + 30 octets maximum. Empty string if no uus. -1 = An error happened. (Invalid parameters for example.) + The keypad support now is included in the dial command. + ISDN_STAT_RUN: @@ -654,19 +715,31 @@ Description of the Interface between Linklevel and Hardwarelevel arg = channel-number, locally to the driver. (starting with 0) parm.num = ASCII string containing CAUSE-message. - ISDN_STAT_L1ERR: + ISDN_STAT_DISPLAY: - ***CHANGEI1.21 new status message. - A signal can be sent to the linklevel if an Layer1-error results in - packet-loss on receive or send. The field errcode of the cmd.parm - union describes the error more precisely. + With this call, the HL-driver delivers DISPLAY-messages to the LL. + Currently the LL does not use this messages. Parameter: driver = driver-Id - command = ISDN_STAT_L1ERR + command = ISDN_STAT_DISPLAY arg = channel-number, locally to the driver. (starting with 0) - parm.errcode= ISDN_STAT_L1ERR_SEND: Packet lost while sending. - ISDN_STAT_L1ERR_RECV: Packet lost while receiving. + para.display= string containing DISPLAY-message. + + ISDN_STAT_PROT: + + With this call, the HL-driver delivers protocol specific infos to the LL. + The call is not implicitely bound to a connection. + + Parameter: + driver = driver-Id + command = ISDN_STAT_PROT + arg = The lower 8 Bits define the adressed protocol as defined + in ISDN_PTYPE..., the upper bits are used to differenciate + the protocol specific STAT. + + para = protocol and function specific. See isdnif.h for detail. + ISDN_STAT_DISCH: With this call, the HL-driver signals the LL to disable or enable the @@ -683,7 +756,20 @@ Description of the Interface between Linklevel and Hardwarelevel command = ISDN_STAT_DISCH arg = channel-number, locally to the driver. (starting with 0) parm.num[0] = 0 if channel shall be disabled, else enabled. - + + ISDN_STAT_L1ERR: + + ***CHANGEI1.21 new status message. + A signal can be sent to the linklevel if an Layer1-error results in + packet-loss on receive or send. The field errcode of the cmd.parm + union describes the error more precisely. + + Parameter: + driver = driver-Id + command = ISDN_STAT_L1ERR + arg = channel-number, locally to the driver. (starting with 0) + parm.errcode= ISDN_STAT_L1ERR_SEND: Packet lost while sending. + ISDN_STAT_L1ERR_RECV: Packet lost while receiving. ISDN_STAT_FAXIND: With this call the HL-driver signals a fax sub-command to the LL. diff --git a/Documentation/isdn/README.HiSax b/Documentation/isdn/README.HiSax index a9f9851beb08..7faff4a34922 100644 --- a/Documentation/isdn/README.HiSax +++ b/Documentation/isdn/README.HiSax @@ -55,7 +55,8 @@ USR Sportster internal TA (compatible Stollmann tina-pp V3) ith Kommunikationstechnik GmbH MIC 16 ISA card Traverse Technologie NETjet PCI S0 card Dr. Neuhaus Niccy PnP/PCI -Siemens I-Surf +Siemens I-Surf 1.0 +Siemens I-Surf 2.0 (with IPAC, try type 12 asuscom) ACER P10 HST Saphir Berkom Telekom A4T @@ -173,7 +174,7 @@ Card types: 27 AVM PnP (Fritz!PnP) irq, io (from isapnp setup) 27 AVM PCI (Fritz!PCI) no parameter 28 Sedlbauer Speed Fax+ irq, io (from isapnp setup) - 29 Siemens I-Surf irq, io, memory (from isapnp setup) + 29 Siemens I-Surf 1.0 irq, io, memory (from isapnp setup) 30 ACER P10 irq, io (from isapnp setup) 31 HST Saphir irq, io 32 Telekom A4T none @@ -276,7 +277,7 @@ type 27 AVM PnP (Fritz!PnP) ONLY WORKS AS A MODULE ! 27 AVM PCI (Fritz!PCI) no parameter 28 Sedlbauer Speed Fax+ ONLY WORKS AS A MODULE ! - 29 Siemens I-Surf ONLY WORKS AS A MODULE ! + 29 Siemens I-Surf 1.0 ONLY WORKS AS A MODULE ! 30 ACER P10 ONLY WORKS AS A MODULE ! 31 HST Saphir pa=irq, pb=io 32 Telekom A4T no parameter diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile index 9b1553cfe580..01498a66b0db 100644 --- a/arch/alpha/kernel/Makefile +++ b/arch/alpha/kernel/Makefile @@ -16,7 +16,7 @@ all: kernel.o head.o O_TARGET := kernel.o O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \ - bios32.o ptrace.o time.o fpreg.o + bios32.o ptrace.o time.o fpreg.o semaphore.o OX_OBJS := alpha_ksyms.o diff --git a/arch/alpha/kernel/semaphore.c b/arch/alpha/kernel/semaphore.c new file mode 100644 index 000000000000..d62b355e1706 --- /dev/null +++ b/arch/alpha/kernel/semaphore.c @@ -0,0 +1,129 @@ +/* + * Generic semaphore code. Buyer beware. Do your own + * specific changes in + */ + +#include +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to sleep, while the "waking" variable is + * incremented when the "up()" code goes to wake up waiting + * processes. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * waking_non_zero() (from asm/semaphore.h) must execute + * atomically. + * + * When __up() is called, the count was negative before + * incrementing it, and we need to wake up somebody. + * + * This routine adds one to the count of processes that need to + * wake up and exit. ALL waiting processes actually wake up but + * only the one that gets to the "waking" field first will gate + * through and acquire the semaphore. The others will go back + * to sleep. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ +void __up(struct semaphore *sem) +{ + wake_one_more(sem); + wake_up(&sem->wait); +} + +/* + * Perform the "down" function. Return zero for semaphore acquired, + * return negative for signalled out of the function. + * + * If called from __down, the return is ignored and the wait loop is + * not interruptible. This means that a task waiting on a semaphore + * using "down()" cannot be killed until someone does an "up()" on + * the semaphore. + * + * If called from __down_interruptible, the return value gets checked + * upon return. If the return value is negative then the task continues + * with the negative value in the return register (it can be tested by + * the caller). + * + * Either form may be used in conjunction with "up()". + * + */ + +#define DOWN_VAR \ + struct task_struct *tsk = current; \ + wait_queue_t wait; \ + init_waitqueue_entry(&wait, tsk); + +#define DOWN_HEAD(task_state) \ + \ + \ + tsk->state = (task_state); \ + add_wait_queue(&sem->wait, &wait); \ + \ + /* \ + * Ok, we're set up. sem->count is known to be less than zero \ + * so we must wait. \ + * \ + * We can let go the lock for purposes of waiting. \ + * We re-acquire it after awaking so as to protect \ + * all semaphore operations. \ + * \ + * If "up()" is called before we call waking_non_zero() then \ + * we will catch it right away. If it is called later then \ + * we will have to go through a wakeup cycle to catch it. \ + * \ + * Multiple waiters contend for the semaphore lock to see \ + * who gets to gate through and who has to wait some more. \ + */ \ + for (;;) { + +#define DOWN_TAIL(task_state) \ + tsk->state = (task_state); \ + } \ + tsk->state = TASK_RUNNING; \ + remove_wait_queue(&sem->wait, &wait); + +void __down(struct semaphore * sem) +{ + DOWN_VAR + DOWN_HEAD(TASK_UNINTERRUPTIBLE) + if (waking_non_zero(sem)) + break; + schedule(); + DOWN_TAIL(TASK_UNINTERRUPTIBLE) +} + +int __down_interruptible(struct semaphore * sem) +{ + int ret = 0; + DOWN_VAR + DOWN_HEAD(TASK_INTERRUPTIBLE) + + ret = waking_non_zero_interruptible(sem, tsk); + if (ret) + { + if (ret == 1) + /* ret != 0 only if we get interrupted -arca */ + ret = 0; + break; + } + schedule(); + DOWN_TAIL(TASK_INTERRUPTIBLE) + return ret; +} + +int __down_trylock(struct semaphore * sem) +{ + return waking_non_zero_trylock(sem); +} diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile index 8ec25a3178a7..875f52d5a801 100644 --- a/arch/i386/kernel/Makefile +++ b/arch/i386/kernel/Makefile @@ -13,7 +13,7 @@ all: kernel.o head.o init_task.o O_TARGET := kernel.o -O_OBJS := process.o signal.o entry.o traps.o irq.o vm86.o \ +O_OBJS := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o OX_OBJS := i386_ksyms.o MX_OBJS := diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 8d71ed8bcb9d..bda71716477f 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -20,7 +20,6 @@ * Naturally it's not a 1:1 relation, but there are similarities. */ -#include #include #include #include diff --git a/arch/i386/kernel/semaphore.c b/arch/i386/kernel/semaphore.c new file mode 100644 index 000000000000..dc5e8f6fbe2e --- /dev/null +++ b/arch/i386/kernel/semaphore.c @@ -0,0 +1,223 @@ +/* + * i386 semaphore implementation. + * + * (C) Copyright 1999 Linus Torvalds + */ +#include + +#include + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to aquire the semaphore, while the "sleeping" + * variable is a count of such aquires. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * "sleeping" and the contention routine ordering is + * protected by the semaphore spinlock. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in + * where we want to avoid any extra jumps and calls. + */ + +/* + * Logic: + * - only on a boundary condition do we need to care. When we go + * from a negative count to a non-negative, we wake people up. + * - when we go from a non-negative count to a negative do we + * (a) synchronize with the "sleeper" count and (b) make sure + * that we're on the wakeup list before we synchronize so that + * we cannot lose wakeup events. + */ + +void __up(struct semaphore *sem) +{ + wake_up(&sem->wait); +} + +static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED; + +void __down(struct semaphore * sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + wake_up(&sem->wait); + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_UNINTERRUPTIBLE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; +} + +int __down_interruptible(struct semaphore * sem) +{ + int retval; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_INTERRUPTIBLE; + add_wait_queue(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers ++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * With signals pending, this turns into + * the trylock failure case - we won't be + * sleeping, and we* can't get the lock as + * it has contention. Just correct the count + * and exit. + */ + retval = -EINTR; + if (signal_pending(current)) { + sem->sleepers = 0; + if (atomic_add_negative(sleepers, &sem->count)) + break; + wake_up(&sem->wait); + break; + } + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. The + * "-1" is because we're still hoping to get + * the lock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + wake_up(&sem->wait); + retval = 0; + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_INTERRUPTIBLE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + tsk->state = TASK_RUNNING; + remove_wait_queue(&sem->wait, &wait); + return retval; +} + +/* + * Trylock failed - make sure we correct for + * having decremented the count. + * + * We could have done the trylock with a + * single "cmpxchg" without failure cases, + * but then it wouldn't work on a 386. + */ +int __down_trylock(struct semaphore * sem) +{ + int retval, sleepers; + + spin_lock_irq(&semaphore_lock); + sleepers = sem->sleepers + 1; + sem->sleepers = 0; + + /* + * Add "everybody else" and us into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers, &sem->count)) + wake_up(&sem->wait); + + spin_unlock_irq(&semaphore_lock); + return 1; +} + + +/* + * The semaphore operations have a special calling sequence that + * allow us to do a simpler in-line version of them. These routines + * need to convert that sequence back into the C sequence when + * there is contention on the semaphore. + * + * %ecx contains the semaphore pointer on entry. Save the C-clobbered + * registers (%eax, %edx and %ecx) except %eax when used as a return + * value.. + */ +asm( +".align 4\n" +".globl __down_failed\n" +"__down_failed:\n\t" + "pushl %eax\n\t" + "pushl %edx\n\t" + "pushl %ecx\n\t" + "call __down\n\t" + "popl %ecx\n\t" + "popl %edx\n\t" + "popl %eax\n\t" + "ret" +); + +asm( +".align 4\n" +".globl __down_failed_interruptible\n" +"__down_failed_interruptible:\n\t" + "pushl %edx\n\t" + "pushl %ecx\n\t" + "call __down_interruptible\n\t" + "popl %ecx\n\t" + "popl %edx\n\t" + "ret" +); + +asm( +".align 4\n" +".globl __down_failed_trylock\n" +"__down_failed_trylock:\n\t" + "pushl %edx\n\t" + "pushl %ecx\n\t" + "call __down_trylock\n\t" + "popl %ecx\n\t" + "popl %edx\n\t" + "ret" +); + +asm( +".align 4\n" +".globl __up_wakeup\n" +"__up_wakeup:\n\t" + "pushl %eax\n\t" + "pushl %edx\n\t" + "pushl %ecx\n\t" + "call __up\n\t" + "popl %ecx\n\t" + "popl %edx\n\t" + "popl %eax\n\t" + "ret" +); diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c index 293877a15639..54645d254105 100644 --- a/arch/i386/kernel/setup.c +++ b/arch/i386/kernel/setup.c @@ -1134,11 +1134,11 @@ void cpu_init (void) struct tss_struct * t = &init_tss[nr]; if (test_and_set_bit(nr,&cpu_initialized)) { - printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr); + printk("CPU#%d already initialized!\n", nr); for (;;) __sti(); } cpus_initialized++; - printk("INITIALIZING CPU#%d\n", nr); + printk("Initializing CPU#%d\n", nr); if (boot_cpu_data.x86_capability & X86_FEATURE_PSE) clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE); diff --git a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile index c2cb3e5a6b9d..a6f8dff0993b 100644 --- a/arch/i386/lib/Makefile +++ b/arch/i386/lib/Makefile @@ -6,7 +6,7 @@ $(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o L_TARGET = lib.a -L_OBJS = checksum.o old-checksum.o semaphore.o delay.o \ +L_OBJS = checksum.o old-checksum.o delay.o \ usercopy.o getuser.o putuser.o include $(TOPDIR)/Rules.make diff --git a/arch/i386/lib/semaphore.S b/arch/i386/lib/semaphore.S deleted file mode 100644 index 3f6e27fccf30..000000000000 --- a/arch/i386/lib/semaphore.S +++ /dev/null @@ -1,51 +0,0 @@ -/* - * linux/arch/i386/lib/semaphore.S - * - * Copyright (C) 1996 Linus Torvalds - */ - -#include - -/* - * The semaphore operations have a special calling sequence that - * allow us to do a simpler in-line version of them. These routines - * need to convert that sequence back into the C sequence when - * there is contention on the semaphore. - */ -ENTRY(__down_failed) - pushl %eax /* save %eax */ - pushl %edx /* save %edx */ - pushl %ecx /* save %ecx (and argument) */ - call SYMBOL_NAME(__down) - popl %ecx /* restore %ecx (count on __down not changing it) */ - popl %edx /* restore %edx */ - popl %eax /* restore %eax */ - ret - -/* Don't save/restore %eax, because that will be our return value */ -ENTRY(__down_failed_interruptible) - pushl %edx /* save %edx */ - pushl %ecx /* save %ecx (and argument) */ - call SYMBOL_NAME(__down_interruptible) - popl %ecx /* restore %ecx (count on __down_interruptible not changing it) */ - popl %edx /* restore %edx */ - ret - -/* Don't save/restore %eax, because that will be our return value */ -ENTRY(__down_failed_trylock) - pushl %edx /* save %edx */ - pushl %ecx /* save %ecx (and argument) */ - call SYMBOL_NAME(__down_trylock) - popl %ecx /* restore %ecx (count on __down_trylock not changing it) */ - popl %edx /* restore %edx */ - ret - -ENTRY(__up_wakeup) - pushl %eax /* save %eax */ - pushl %edx /* save %edx */ - pushl %ecx /* save %ecx (and argument) */ - call SYMBOL_NAME(__up) - popl %ecx /* restore %ecx (count on __up not changing it) */ - popl %edx /* restore %edx */ - popl %eax /* restore %eax */ - ret diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c index f57920c55389..752d70dce9c3 100644 --- a/arch/i386/mm/init.c +++ b/arch/i386/mm/init.c @@ -389,9 +389,10 @@ __initfunc(void mem_init(unsigned long start_mem, unsigned long end_mem)) * IBM messed up *AGAIN* in their thinkpad: 0xA0000 -> 0x9F000. * They seem to have done something stupid with the floppy * controller as well.. - * The amount of available base memory is in WORD 40:13. + * The amount of available base memory is in WORD 40:13. Except + * when it isn't. */ - endbase = PAGE_OFFSET + ((*(unsigned short *)__va(0x413) * 1024) & PAGE_MASK); + endbase = PAGE_OFFSET + 0x9f000; while (start_low_mem < endbase) { clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags); start_low_mem += PAGE_SIZE; diff --git a/drivers/atm/ambassador.h b/drivers/atm/ambassador.h index 931f5f411b10..c9742a7e9459 100644 --- a/drivers/atm/ambassador.h +++ b/drivers/atm/ambassador.h @@ -28,6 +28,8 @@ #ifndef AMBASSADOR_H #define AMBASSADOR_H +#include + #ifdef CONFIG_ATM_AMBASSADOR_DEBUG #define DEBUG_AMBASSADOR #endif diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index b2d14b243135..256cc08d687b 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -26,7 +26,6 @@ */ #include -#include #include #include #include diff --git a/drivers/atm/horizon.h b/drivers/atm/horizon.h index 41c6b635af1e..f05f4411576f 100644 --- a/drivers/atm/horizon.h +++ b/drivers/atm/horizon.h @@ -30,6 +30,8 @@ #ifndef DRIVER_ATM_HORIZON_H #define DRIVER_ATM_HORIZON_H +#include + #ifdef CONFIG_ATM_HORIZON_DEBUG #define DEBUG_HORIZON #endif diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c index 7402a6ef2c91..fa27ecbe5828 100644 --- a/drivers/atm/suni.c +++ b/drivers/atm/suni.c @@ -3,7 +3,6 @@ /* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ -#include #include #include #include diff --git a/drivers/atm/uPD98402.c b/drivers/atm/uPD98402.c index c06f120471c9..a02dabf28ec8 100644 --- a/drivers/atm/uPD98402.c +++ b/drivers/atm/uPD98402.c @@ -3,7 +3,6 @@ /* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */ -#include #include #include /* for jiffies */ #include diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index 5980a75f74b0..3b4f3ab3ce59 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -3,6 +3,7 @@ /* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */ +#include #include #include #include diff --git a/drivers/atm/zatm.h b/drivers/atm/zatm.h index e6a265bfd428..d9f05f5481bc 100644 --- a/drivers/atm/zatm.h +++ b/drivers/atm/zatm.h @@ -6,6 +6,7 @@ #ifndef DRIVER_ATM_ZATM_H #define DRIVER_ATM_ZATM_H +#include #include #include #include diff --git a/drivers/char/ip2.c b/drivers/char/ip2.c index 1dbd56ace861..96d7ef906775 100644 --- a/drivers/char/ip2.c +++ b/drivers/char/ip2.c @@ -8,8 +8,6 @@ #include #include -#include -#include #include #include "./ip2/ip2types.h" diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c index 79ab3ab63106..f1c4501a9a1f 100644 --- a/drivers/char/ip2main.c +++ b/drivers/char/ip2main.c @@ -41,10 +41,8 @@ #include #include -#include #include #include -#include #include #include diff --git a/drivers/isdn/Config.in b/drivers/isdn/Config.in index 5ad3772819c9..ec27982bbf80 100644 --- a/drivers/isdn/Config.in +++ b/drivers/isdn/Config.in @@ -51,8 +51,8 @@ if [ "$CONFIG_ISDN_DRV_HISAX" != "n" ]; then bool 'HiSax Support for Telekom A4T card' CONFIG_HISAX_BKM_A4T bool 'HiSax Support for Scitel Quadro card' CONFIG_HISAX_SCT_QUADRO bool 'HiSax Support for Gazel cards' CONFIG_HISAX_GAZEL + bool 'HiSax Support for HFC PCI-Bus cards' CONFIG_HISAX_HFC_PCI if [ "$CONFIG_EXPERIMENTAL" != "n" ]; then - bool 'HiSax Support for HFC PCI-Bus cards (EXPERIMENTAL)' CONFIG_HISAX_HFC_PCI # bool 'HiSax Support for TESTEMULATOR (EXPERIMENTAL)' CONFIG_HISAX_TESTEMU if [ "$ARCH" = "sparc" -o "$ARCH" = "sparc64" ]; then bool 'HiSax Support for Am7930' CONFIG_HISAX_AMD7930 diff --git a/drivers/isdn/avmb1/b1.c b/drivers/isdn/avmb1/b1.c index 1b7f07bc46f1..c4dffdacbc74 100644 --- a/drivers/isdn/avmb1/b1.c +++ b/drivers/isdn/avmb1/b1.c @@ -1,11 +1,17 @@ /* - * $Id: b1.c,v 1.7 1999/08/04 10:10:09 calle Exp $ + * $Id: b1.c,v 1.8 1999/08/22 20:26:22 calle Exp $ * * Common module for AVM B1 cards. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1.c,v $ + * Revision 1.8 1999/08/22 20:26:22 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.7 1999/08/04 10:10:09 calle * Bugfix: corrected /proc functions, added structure for new AVM cards. * @@ -62,7 +68,7 @@ #include "capicmd.h" #include "capiutil.h" -static char *revision = "$Revision: 1.7 $"; +static char *revision = "$Revision: 1.8 $"; /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/avmb1/b1isa.c b/drivers/isdn/avmb1/b1isa.c index d5562fb3801e..9ab1984323ee 100644 --- a/drivers/isdn/avmb1/b1isa.c +++ b/drivers/isdn/avmb1/b1isa.c @@ -1,11 +1,17 @@ /* - * $Id: b1isa.c,v 1.3 1999/07/09 15:05:40 keil Exp $ + * $Id: b1isa.c,v 1.4 1999/08/22 20:26:24 calle Exp $ * * Module for AVM B1 ISA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1isa.c,v $ + * Revision 1.4 1999/08/22 20:26:24 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.3 1999/07/09 15:05:40 keil * compat.h is now isdn_compat.h * @@ -49,7 +55,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.3 $"; +static char *revision = "$Revision: 1.4 $"; /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/avmb1/b1pcmcia.c b/drivers/isdn/avmb1/b1pcmcia.c index 9af06268abff..d6acda9d9e08 100644 --- a/drivers/isdn/avmb1/b1pcmcia.c +++ b/drivers/isdn/avmb1/b1pcmcia.c @@ -1,11 +1,17 @@ /* - * $Id: b1pcmcia.c,v 1.3 1999/07/09 15:05:41 keil Exp $ + * $Id: b1pcmcia.c,v 1.4 1999/08/22 20:26:26 calle Exp $ * * Module for AVM B1/M1/M2 PCMCIA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: b1pcmcia.c,v $ + * Revision 1.4 1999/08/22 20:26:26 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.3 1999/07/09 15:05:41 keil * compat.h is now isdn_compat.h * @@ -50,7 +56,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.3 $"; +static char *revision = "$Revision: 1.4 $"; /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/avmb1/t1isa.c b/drivers/isdn/avmb1/t1isa.c index 73fd8d24728c..3546e10610f3 100644 --- a/drivers/isdn/avmb1/t1isa.c +++ b/drivers/isdn/avmb1/t1isa.c @@ -1,11 +1,17 @@ /* - * $Id: t1isa.c,v 1.4 1999/07/09 15:05:50 keil Exp $ + * $Id: t1isa.c,v 1.5 1999/08/22 20:26:28 calle Exp $ * * Module for AVM T1 HEMA-card. * * (c) Copyright 1999 by Carsten Paeth (calle@calle.in-berlin.de) * * $Log: t1isa.c,v $ + * Revision 1.5 1999/08/22 20:26:28 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.4 1999/07/09 15:05:50 keil * compat.h is now isdn_compat.h * @@ -53,7 +59,7 @@ #include "capilli.h" #include "avmcard.h" -static char *revision = "$Revision: 1.4 $"; +static char *revision = "$Revision: 1.5 $"; /* ------------------------------------------------------------- */ diff --git a/drivers/isdn/divert/divert_init.c b/drivers/isdn/divert/divert_init.c index ec58f43c0008..ce44cfa19cd3 100644 --- a/drivers/isdn/divert/divert_init.c +++ b/drivers/isdn/divert/divert_init.c @@ -1,5 +1,5 @@ /* - * $Id: divert_init.c,v 1.3 1999/07/05 20:21:39 werner Exp $ + * $Id: divert_init.c,v 1.4 1999/08/22 20:26:32 calle Exp $ * * Module init for DSS1 diversion services for i4l. * @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: divert_init.c,v $ + * Revision 1.4 1999/08/22 20:26:32 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.3 1999/07/05 20:21:39 werner * changes to use diversion sources for all kernel versions. * removed static device, only proc filesystem used diff --git a/drivers/isdn/divert/isdn_divert.c b/drivers/isdn/divert/isdn_divert.c index 6650d47f4a12..f10ea18b26f8 100644 --- a/drivers/isdn/divert/isdn_divert.c +++ b/drivers/isdn/divert/isdn_divert.c @@ -1,5 +1,5 @@ /* - * $Id: isdn_divert.c,v 1.2 1999/07/04 21:37:32 werner Exp $ + * $Id: isdn_divert.c,v 1.4 1999/08/25 20:02:21 werner Exp $ * * DSS1 main diversion supplementary handling for i4l. * @@ -20,6 +20,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_divert.c,v $ + * Revision 1.4 1999/08/25 20:02:21 werner + * Changed return values for stat_icall(w) from 3->4 and 4->5 because of conflicts + * with existing software definitions. (PtP incomplete called party number) + * + * Revision 1.3 1999/08/22 20:26:35 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.2 1999/07/04 21:37:32 werner * Ported from kernel version 2.0 * @@ -508,14 +518,14 @@ int isdn_divert_icall(isdn_ctrl *ic) strcpy(ic->parm.setup.phone,dv->rule.to_nr); cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */ cs->timer.expires = jiffies + (HZ * AUTODEL_TIME); - retval = 4; + retval = 5; } else retval = 1; /* alerting */ } else { cs->deflect_dest[0] = '\0'; - retval = 3; /* only proceed */ + retval = 4; /* only proceed */ } sprintf(cs->info,"%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n", cs->akt_state, diff --git a/drivers/isdn/divert/isdn_divert.h b/drivers/isdn/divert/isdn_divert.h index 336187837b55..1d329c0fb749 100644 --- a/drivers/isdn/divert/isdn_divert.h +++ b/drivers/isdn/divert/isdn_divert.h @@ -1,5 +1,5 @@ /* - * $Id: isdn_divert.h,v 1.2 1999/07/04 21:37:33 werner Exp $ + * $Id: isdn_divert.h,v 1.3 1999/08/22 20:26:37 calle Exp $ * * Header for the diversion supplementary ioctl interface. * @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_divert.h,v $ + * Revision 1.3 1999/08/22 20:26:37 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.2 1999/07/04 21:37:33 werner * Ported from kernel version 2.0 * diff --git a/drivers/isdn/eicon/eicon.h b/drivers/isdn/eicon/eicon.h index 444732e7b6fa..4e107e00d5ef 100644 --- a/drivers/isdn/eicon/eicon.h +++ b/drivers/isdn/eicon/eicon.h @@ -1,4 +1,4 @@ -/* $Id: eicon.h,v 1.8 1999/07/25 15:12:01 armin Exp $ +/* $Id: eicon.h,v 1.10 1999/08/22 20:26:41 calle Exp $ * * ISDN low-level module for Eicon.Diehl active ISDN-Cards. * @@ -21,6 +21,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon.h,v $ + * Revision 1.10 1999/08/22 20:26:41 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * + * Revision 1.9 1999/08/18 20:16:57 armin + * Added XLOG function for all cards. + * Bugfix of alloc_skb NULL pointer. + * * Revision 1.8 1999/07/25 15:12:01 armin * fix of some debug logs. * enabled ISA-cards option. @@ -73,6 +83,7 @@ #define EICON_IOCTL_LOADPCI 7 #define EICON_IOCTL_LOADISA 8 #define EICON_IOCTL_GETVER 9 +#define EICON_IOCTL_GETXLOG 10 #define EICON_IOCTL_MANIF 90 @@ -102,6 +113,7 @@ #define MAX_HEADER_LEN 10 + /* Struct for adding new cards */ typedef struct eicon_cdef { int membase; @@ -225,6 +237,92 @@ typedef struct { #endif /* KERNEL */ +#define DIVAS_SHARED_OFFSET (0x1000) + +#define MIPS_BUFFER_SZ 128 +#define MIPS_MAINT_OFFS 0xff00 + +#define XLOG_ERR_CARD_NUM (13) +#define XLOG_ERR_DONE (14) +#define XLOG_ERR_CMD (15) +#define XLOG_ERR_TIMEOUT (16) +#define XLOG_ERR_CARD_STATE (17) +#define XLOG_ERR_UNKNOWN (18) +#define XLOG_OK (0) + +typedef struct { + __u8 Id __attribute__ ((packed)); + __u8 uX __attribute__ ((packed)); + __u8 listen __attribute__ ((packed)); + __u8 active __attribute__ ((packed)); + __u8 sin[3] __attribute__ ((packed)); + __u8 bc[6] __attribute__ ((packed)); + __u8 llc[6] __attribute__ ((packed)); + __u8 hlc[6] __attribute__ ((packed)); + __u8 oad[20] __attribute__ ((packed)); +}DSigStruc; + +typedef struct { + __u32 cx_b1 __attribute__ ((packed)); + __u32 cx_b2 __attribute__ ((packed)); + __u32 cr_b1 __attribute__ ((packed)); + __u32 cr_b2 __attribute__ ((packed)); + __u32 px_b1 __attribute__ ((packed)); + __u32 px_b2 __attribute__ ((packed)); + __u32 pr_b1 __attribute__ ((packed)); + __u32 pr_b2 __attribute__ ((packed)); + __u16 er_b1 __attribute__ ((packed)); + __u16 er_b2 __attribute__ ((packed)); +}BL1Struc; + +typedef struct { + __u32 XTotal __attribute__ ((packed)); + __u32 RTotal __attribute__ ((packed)); + __u16 XError __attribute__ ((packed)); + __u16 RError __attribute__ ((packed)); +}L2Struc; + +typedef struct { + __u16 free_n; +}OSStruc; + +typedef union +{ + DSigStruc DSigStats; + BL1Struc BL1Stats; + L2Struc L2Stats; + OSStruc OSStats; + __u8 b[MIPS_BUFFER_SZ]; + __u16 w[MIPS_BUFFER_SZ>>1]; + __u16 l[MIPS_BUFFER_SZ>>2]; /* word is wrong, do not use! Use 'd' instead. */ + __u32 d[MIPS_BUFFER_SZ>>2]; +} MIPS_BUFFER; + +typedef struct +{ + __u8 req __attribute__ ((packed)); + __u8 rc __attribute__ ((packed)); + __u8 reserved[2] __attribute__ ((packed)); /* R3000 alignment ... */ + __u8 *mem __attribute__ ((packed)); + __u16 length __attribute__ ((packed)); /* used to be short */ + __u16 port __attribute__ ((packed)); + __u8 fill[4] __attribute__ ((packed)); /* data at offset 16 */ + MIPS_BUFFER data __attribute__ ((packed)); +} mi_pc_maint_t; + +typedef struct +{ + __u16 command; + mi_pc_maint_t pcm; +}xlogreq_t; + +typedef struct{ + __u16 code __attribute__ ((packed)); /* used to be short */ + __u16 timeh __attribute__ ((packed)); + __u16 timel __attribute__ ((packed)); + char buffer[MIPS_BUFFER_SZ - 6]; +}xlog_entry_t; + #define DSP_COMBIFILE_FORMAT_IDENTIFICATION_SIZE 48 #define DSP_COMBIFILE_FORMAT_VERSION_BCD 0x0100 @@ -556,6 +654,7 @@ extern void eicon_io_transmit(eicon_card *card); extern void eicon_irq(int irq, void *dev_id, struct pt_regs *regs); extern void eicon_io_rcv_dispatch(eicon_card *ccard); extern void eicon_io_ack_dispatch(eicon_card *ccard); +extern int eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq); #ifdef CONFIG_MCA extern int eicon_mca_find_card(int, int, int, char *); extern int eicon_mca_probe(int, int, int, int, char *); diff --git a/drivers/isdn/eicon/eicon_idi.c b/drivers/isdn/eicon/eicon_idi.c index c10b014cdf26..bad6a4a35d38 100644 --- a/drivers/isdn/eicon/eicon_idi.c +++ b/drivers/isdn/eicon/eicon_idi.c @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.c,v 1.11 1999/07/25 15:12:03 armin Exp $ +/* $Id: eicon_idi.c,v 1.13 1999/08/22 20:26:44 calle Exp $ * * ISDN lowlevel-module for Eicon.Diehl active cards. * IDI interface @@ -21,6 +21,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_idi.c,v $ + * Revision 1.13 1999/08/22 20:26:44 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * + * Revision 1.12 1999/08/18 20:16:59 armin + * Added XLOG function for all cards. + * Bugfix of alloc_skb NULL pointer. + * * Revision 1.11 1999/07/25 15:12:03 armin * fix of some debug logs. * enabled ISA-cards option. @@ -78,7 +88,7 @@ #undef EICON_FULL_SERVICE_OKTETT -char *eicon_idi_revision = "$Revision: 1.11 $"; +char *eicon_idi_revision = "$Revision: 1.13 $"; eicon_manifbuf *manbuf; @@ -265,8 +275,8 @@ idi_call_res_req(eicon_REQ *reqbuf, eicon_chan *chan) int idi_do_req(eicon_card *card, eicon_chan *chan, int cmd, int layer) { - struct sk_buff *skb = 0; - struct sk_buff *skb2 = 0; + struct sk_buff *skb; + struct sk_buff *skb2; eicon_REQ *reqbuf; eicon_chan_ptr *chan2; @@ -1081,7 +1091,8 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) ccard->interface.statcallb(&cmd); eicon_idi_listen_req(ccard, chan); #ifdef CONFIG_ISDN_TTY_FAX - chan->fax = 0; + if (!chan->e.B2Id) + chan->fax = 0; #endif break; case INDICATE_IND: @@ -1274,12 +1285,16 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) chan->queued = 0; chan->waitq = 0; chan->waitpq = 0; + idi_do_req(ccard, chan, HANGUP, 0); if (chan->fsm_state == EICON_STATE_ACTIVE) { cmd.driver = ccard->myid; cmd.command = ISDN_STAT_BHUP; cmd.arg = chan->No; ccard->interface.statcallb(&cmd); } +#ifdef CONFIG_ISDN_TTY_FAX + chan->fax = 0; +#endif break; case IDI_N_DISC_ACK: if (DebugVar & 16) @@ -1328,7 +1343,7 @@ idi_handle_ind(eicon_card *ccard, struct sk_buff *skb) if (free_buff) dev_kfree_skb(skb); } -void +int idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) { isdn_ctrl cmd; @@ -1338,7 +1353,7 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) if (DebugVar & 16) printk(KERN_DEBUG "idi_ack: Ch%d: RcId %d not equal to last %d\n", chan->No, ack->RcId, (chan->e.ReqCh) ? chan->e.B2Id : chan->e.D3Id); - return; + return 1; } /* Management Interface */ @@ -1351,25 +1366,26 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) /* Remove an Id */ if (chan->e.Req == REMOVE) { if (ack->Reference != chan->e.ref) { - if (DebugVar & 1) + if (DebugVar & 16) printk(KERN_DEBUG "idi_ack: Ch%d: Rc-Ref %d not equal to stored %d\n", chan->No, ack->Reference, chan->e.ref); + return 0; } ccard->IdTable[ack->RcId] = NULL; if (DebugVar & 16) - printk(KERN_DEBUG "idi_ack: Ch%d: Removed : Id=%d Ch=%d (%s)\n", chan->No, + printk(KERN_DEBUG "idi_ack: Ch%d: Removed : Id=%x Ch=%d (%s)\n", chan->No, ack->RcId, ack->RcCh, (chan->e.ReqCh)? "Net":"Sig"); if (!chan->e.ReqCh) chan->e.D3Id = 0; else chan->e.B2Id = 0; - return; + return 1; } /* Signal layer */ if (!chan->e.ReqCh) { if (DebugVar & 16) - printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%d Ch=%d (ref:%d)\n", chan->No, + printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, ack->RcId, ack->RcCh, ack->Reference); } else { /* Network layer */ @@ -1410,10 +1426,11 @@ idi_handle_ack_ok(eicon_card *ccard, eicon_chan *chan, eicon_RC *ack) break; default: if (DebugVar & 16) - printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%d Ch=%d (ref:%d)\n", chan->No, + printk(KERN_DEBUG "idi_ack: Ch%d: RC OK Id=%x Ch=%d (ref:%d)\n", chan->No, ack->RcId, ack->RcCh, ack->Reference); } } + return 1; } void @@ -1448,7 +1465,8 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) printk(KERN_ERR "idi_ack: Ch%d: OK on chan without Id\n", dCh); break; } - idi_handle_ack_ok(ccard, chan, ack); + if (!idi_handle_ack_ok(ccard, chan, ack)) + chan = NULL; break; case ASSIGN_OK: @@ -1487,9 +1505,8 @@ idi_handle_ack(eicon_card *ccard, struct sk_buff *skb) case UNKNOWN_IE: case WRONG_IE: default: - chan->e.busy = 0; - if (DebugVar & 24) - printk(KERN_ERR "eicon_ack: Ch%d: Not OK: Rc=%d Id=%d Ch=%d\n", dCh, + if (DebugVar & 1) + printk(KERN_ERR "eicon_ack: Ch%d: Not OK !!: Rc=%d Id=%x Ch=%d\n", dCh, ack->Rc, ack->RcId, ack->RcCh); if (dCh == ccard->nchannels) { /* Management */ chan->fsm_state = 2; @@ -1586,7 +1603,6 @@ idi_send_data(eicon_card *card, eicon_chan *chan, int ack, struct sk_buff *skb, } - int eicon_idi_manage_assign(eicon_card *card) { diff --git a/drivers/isdn/eicon/eicon_idi.h b/drivers/isdn/eicon/eicon_idi.h index ca989cf9d83e..e09c1954d479 100644 --- a/drivers/isdn/eicon/eicon_idi.h +++ b/drivers/isdn/eicon/eicon_idi.h @@ -1,4 +1,4 @@ -/* $Id: eicon_idi.h,v 1.6 1999/07/25 15:12:04 armin Exp $ +/* $Id: eicon_idi.h,v 1.7 1999/08/22 20:26:46 calle Exp $ * * ISDN lowlevel-module for the Eicon.Diehl active cards. * IDI-Interface @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_idi.h,v $ + * Revision 1.7 1999/08/22 20:26:46 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.6 1999/07/25 15:12:04 armin * fix of some debug logs. * enabled ISA-cards option. diff --git a/drivers/isdn/eicon/eicon_io.c b/drivers/isdn/eicon/eicon_io.c index 058afa229c0a..60b5b4818495 100644 --- a/drivers/isdn/eicon/eicon_io.c +++ b/drivers/isdn/eicon/eicon_io.c @@ -1,4 +1,4 @@ -/* $Id: eicon_io.c,v 1.2 1999/07/25 15:12:05 armin Exp $ +/* $Id: eicon_io.c,v 1.4 1999/08/22 20:26:47 calle Exp $ * * ISDN low-level module for Eicon.Diehl active ISDN-Cards. * Code for communicating with hardware. @@ -24,6 +24,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_io.c,v $ + * Revision 1.4 1999/08/22 20:26:47 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * + * Revision 1.3 1999/08/18 20:17:01 armin + * Added XLOG function for all cards. + * Bugfix of alloc_skb NULL pointer. + * * Revision 1.2 1999/07/25 15:12:05 armin * fix of some debug logs. * enabled ISA-cards option. @@ -61,7 +71,7 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { /* doesn't matter if this happens */ break; default: - printk(KERN_ERR "idi: Indication for unknown channel Ind=%d Id=%d\n", ind->Ind, ind->IndId); + printk(KERN_ERR "idi: Indication for unknown channel Ind=%d Id=%x\n", ind->Ind, ind->IndId); printk(KERN_DEBUG "idi_hdl: Ch??: Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", ind->Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,ind->RBuffer.length); } @@ -89,12 +99,18 @@ eicon_io_rcv_dispatch(eicon_card *ccard) { if (DebugVar & 1) printk(KERN_ERR "eicon: buffer incomplete, but 0 in queue\n"); dev_kfree_skb(skb); - dev_kfree_skb(skb2); continue; } ind2 = (eicon_IND *)skb2->data; skb_new = alloc_skb(((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length), GFP_ATOMIC); + if (!skb_new) { + if (DebugVar & 1) + printk(KERN_ERR "eicon_io: skb_alloc failed in rcv_dispatch()\n"); + dev_kfree_skb(skb); + dev_kfree_skb(skb2); + continue; + } ind_new = (eicon_IND *)skb_put(skb_new, ((sizeof(eicon_IND)-1)+ind->RBuffer.length+ind2->RBuffer.length)); ind_new->Ind = ind2->Ind; @@ -276,6 +292,92 @@ void ram_copytocard(eicon_card *card, void *adrto, void *adr, int len) { } } +/* + * XLOG + */ +int +eicon_get_xlog(eicon_card *card, xlogreq_t *xlogreq) +{ + int timeout, i; + int divas_shared_offset = 0; + int len = 0; + int stype = 0; + __u32 time = 0; + mi_pc_maint_t *pcm = &xlogreq->pcm; + eicon_pci_card *pci_card = &card->hwif.pci; + eicon_isa_card *isa_card = &card->hwif.isa; + eicon_pr_ram *prram = 0; + char *ram; + + switch(card->type) { + case EICON_CTYPE_MAESTRAP: + ram = (char *)pci_card->PCIram; + prram = (eicon_pr_ram *)ram; + divas_shared_offset = DIVAS_SHARED_OFFSET; + len = sizeof(mi_pc_maint_t); + break; + case EICON_CTYPE_MAESTRA: + prram = 0; + divas_shared_offset = 0; + len = sizeof(mi_pc_maint_t); + break; + case EICON_CTYPE_S: + case EICON_CTYPE_SX: + case EICON_CTYPE_SCOM: + case EICON_CTYPE_QUADRO: + case EICON_CTYPE_S2M: + prram = (eicon_pr_ram *)isa_card->shmem; + divas_shared_offset = 0xfb80; + len = sizeof(mi_pc_maint_t) - 78; + stype = 1; + break; + default: + return -ENODEV; + } + + memset(&(xlogreq->pcm), 0, sizeof(mi_pc_maint_t)); + + xlogreq->pcm.rc = 0; + xlogreq->pcm.req = 1; /* DO_LOG */ + + ram = ((char *)prram) + MIPS_MAINT_OFFS - divas_shared_offset; + + ram_outb(card, ram+1, pcm->rc); + ram_outb(card, ram+0, pcm->req); + + timeout = jiffies + 50; + while (timeout > jiffies) { + pcm->rc = ram_inb(card, ram+1); + pcm->req = ram_inb(card, ram+0); + if (!pcm->req) break; + SLEEP(10); + } + + if (pcm->req) { + return XLOG_ERR_TIMEOUT; + } + + if (pcm->rc != OK) { + return XLOG_ERR_DONE; + } + + ram_copyfromcard(card, pcm, ram, len); + + if (stype) { + for (i=0; i<8; i++) + ((__u8 *)pcm)[11-i] = ((__u8 *)pcm)[9-i]; + time = (__u32)pcm->data.w[2] * 3600 * 1000 + + (__u32)pcm->data.w[1] * 1000 + + (__u32)pcm->data.b[1] * 20 + + (__u32)pcm->data.b[0] ; + pcm->data.w[1] = (__u16) (time >> 16); + pcm->data.w[2] = (__u16) (time & 0x0000ffff); + pcm->data.w[0] = 2; + } + + return XLOG_OK; +} + /* * Transmit-Function */ @@ -373,9 +475,13 @@ eicon_io_transmit(eicon_card *ccard) { chan = chan2->ptr; if (!chan->e.busy) { if((skb = skb_dequeue(&chan->e.X))) { - save_flags(flags); - cli(); - reqbuf = (eicon_REQ *)skb->data; + save_flags(flags); + cli(); + reqbuf = (eicon_REQ *)skb->data; + if ((reqbuf->Reference) && (chan->e.B2Id == 0) && (reqbuf->ReqId & 0x1f)) { + if (DebugVar & 16) + printk(KERN_WARNING "eicon: transmit: error Id=0 on %d (Net)\n", chan->No); + } else { if (scom) { ram_outw(ccard, &com->XBuffer.length, reqbuf->XBuffer.length); ram_copytocard(ccard, &com->XBuffer.P, &reqbuf->XBuffer.P, reqbuf->XBuffer.length); @@ -390,7 +496,7 @@ eicon_io_transmit(eicon_card *ccard) { ram_outb(ccard, &ReqOut->Req, reqbuf->Req); } - if (reqbuf->ReqId &0x1f) { /* if this is no ASSIGN */ + if (reqbuf->ReqId & 0x1f) { /* if this is no ASSIGN */ if (!reqbuf->Reference) { /* Signal Layer */ if (scom) @@ -439,14 +545,15 @@ eicon_io_transmit(eicon_card *ccard) { ram_outw(ccard, &prram->NextReq, ram_inw(ccard, &ReqOut->next)); chan->e.busy = 1; - restore_flags(flags); if (DebugVar & 32) printk(KERN_DEBUG "eicon: Req=%d Id=%x Ch=%d Len=%d Ref=%d\n", reqbuf->Req, ram_inb(ccard, &ReqOut->ReqId), reqbuf->ReqCh, reqbuf->XBuffer.length, chan->e.ref); - dev_kfree_skb(skb); + } + restore_flags(flags); + dev_kfree_skb(skb); } dev_kfree_skb(skb2); } @@ -636,16 +743,21 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { } } else { skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); - ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); - ack->Rc = tmp; - ack->RcId = ram_inb(ccard, &com->RcId); - ack->RcCh = ram_inb(ccard, &com->RcCh); - ack->Reference = ccard->ref_in++; - if (DebugVar & 64) - printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n", - tmp,ack->RcId,ack->RcCh,ack->Reference); - skb_queue_tail(&ccard->rackq, skb); - eicon_schedule_ack(ccard); + if (!skb) { + if (DebugVar & 1) + printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n"); + } else { + ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); + ack->Rc = tmp; + ack->RcId = ram_inb(ccard, &com->RcId); + ack->RcCh = ram_inb(ccard, &com->RcCh); + ack->Reference = ccard->ref_in++; + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n", + tmp,ack->RcId,ack->RcCh,ack->Reference); + skb_queue_tail(&ccard->rackq, skb); + eicon_schedule_ack(ccard); + } ram_outb(ccard, &com->Req, 0); ram_outb(ccard, &com->Rc, 0); } @@ -657,19 +769,24 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { eicon_IND *ind; int len = ram_inw(ccard, &com->RBuffer.length); skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); - ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); - ind->Ind = tmp; - ind->IndId = ram_inb(ccard, &com->IndId); - ind->IndCh = ram_inb(ccard, &com->IndCh); - ind->MInd = ram_inb(ccard, &com->MInd); - ind->MLength = ram_inw(ccard, &com->MLength); - ind->RBuffer.length = len; - if (DebugVar & 64) - printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", - tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len); - ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len); - skb_queue_tail(&ccard->rcvq, skb); - eicon_schedule_rx(ccard); + if (!skb) { + if (DebugVar & 1) + printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n"); + } else { + ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); + ind->Ind = tmp; + ind->IndId = ram_inb(ccard, &com->IndId); + ind->IndCh = ram_inb(ccard, &com->IndCh); + ind->MInd = ram_inb(ccard, &com->MInd); + ind->MLength = ram_inw(ccard, &com->MLength); + ind->RBuffer.length = len; + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", + tmp,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len); + ram_copyfromcard(ccard, &ind->RBuffer.P, &com->RBuffer.P, len); + skb_queue_tail(&ccard->rcvq, skb); + eicon_schedule_rx(ccard); + } ram_outb(ccard, &com->Ind, 0); } } @@ -686,17 +803,22 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { if((Rc=ram_inb(ccard, &RcIn->Rc))) { skb = alloc_skb(sizeof(eicon_RC), GFP_ATOMIC); - ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); - ack->Rc = Rc; - ack->RcId = ram_inb(ccard, &RcIn->RcId); - ack->RcCh = ram_inb(ccard, &RcIn->RcCh); - ack->Reference = ram_inw(ccard, &RcIn->Reference); - if (DebugVar & 64) - printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n", - Rc,ack->RcId,ack->RcCh,ack->Reference); - ram_outb(ccard, &RcIn->Rc, 0); - skb_queue_tail(&ccard->rackq, skb); - eicon_schedule_ack(ccard); + if (!skb) { + if (DebugVar & 1) + printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n"); + } else { + ack = (eicon_RC *)skb_put(skb, sizeof(eicon_RC)); + ack->Rc = Rc; + ack->RcId = ram_inb(ccard, &RcIn->RcId); + ack->RcCh = ram_inb(ccard, &RcIn->RcCh); + ack->Reference = ram_inw(ccard, &RcIn->Reference); + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Rc=%d Id=%x Ch=%d Ref=%d\n", + Rc,ack->RcId,ack->RcCh,ack->Reference); + skb_queue_tail(&ccard->rackq, skb); + eicon_schedule_ack(ccard); + } + ram_outb(ccard, &RcIn->Rc, 0); } /* get buffer address of next return code */ RcIn = (eicon_RC *)&prram->B[ram_inw(ccard, &RcIn->next)]; @@ -716,19 +838,24 @@ eicon_irq(int irq, void *dev_id, struct pt_regs *regs) { if(Ind) { int len = ram_inw(ccard, &IndIn->RBuffer.length); skb = alloc_skb((sizeof(eicon_IND) + len - 1), GFP_ATOMIC); - ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); - ind->Ind = Ind; - ind->IndId = ram_inb(ccard, &IndIn->IndId); - ind->IndCh = ram_inb(ccard, &IndIn->IndCh); - ind->MInd = ram_inb(ccard, &IndIn->MInd); - ind->MLength = ram_inw(ccard, &IndIn->MLength); - ind->RBuffer.length = len; - if (DebugVar & 64) - printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", - Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len); - ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len); - skb_queue_tail(&ccard->rcvq, skb); - eicon_schedule_rx(ccard); + if (!skb) { + if (DebugVar & 1) + printk(KERN_ERR "eicon_io: skb_alloc failed in _irq()\n"); + } else { + ind = (eicon_IND *)skb_put(skb, (sizeof(eicon_IND) + len - 1)); + ind->Ind = Ind; + ind->IndId = ram_inb(ccard, &IndIn->IndId); + ind->IndCh = ram_inb(ccard, &IndIn->IndCh); + ind->MInd = ram_inb(ccard, &IndIn->MInd); + ind->MLength = ram_inw(ccard, &IndIn->MLength); + ind->RBuffer.length = len; + if (DebugVar & 64) + printk(KERN_INFO "eicon: IRQ Ind=%d Id=%x Ch=%d MInd=%d MLen=%d Len=%d\n", + Ind,ind->IndId,ind->IndCh,ind->MInd,ind->MLength,len); + ram_copyfromcard(ccard, &ind->RBuffer.P, &IndIn->RBuffer.P, len); + skb_queue_tail(&ccard->rcvq, skb); + eicon_schedule_rx(ccard); + } ram_outb(ccard, &IndIn->Ind, 0); } /* get buffer address of next indication */ diff --git a/drivers/isdn/eicon/eicon_isa.c b/drivers/isdn/eicon/eicon_isa.c index ba2dd0f852c1..75122559ce9e 100644 --- a/drivers/isdn/eicon/eicon_isa.c +++ b/drivers/isdn/eicon/eicon_isa.c @@ -1,4 +1,4 @@ -/* $Id: eicon_isa.c,v 1.6 1999/07/25 15:12:06 armin Exp $ +/* $Id: eicon_isa.c,v 1.7 1999/08/22 20:26:48 calle Exp $ * * ISDN low-level module for Eicon.Diehl active ISDN-Cards. * Hardware-specific code for old ISA cards. @@ -22,6 +22,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_isa.c,v $ + * Revision 1.7 1999/08/22 20:26:48 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.6 1999/07/25 15:12:06 armin * fix of some debug logs. * enabled ISA-cards option. @@ -58,7 +64,7 @@ #define release_shmem release_region #define request_shmem request_region -char *eicon_isa_revision = "$Revision: 1.6 $"; +char *eicon_isa_revision = "$Revision: 1.7 $"; #ifdef CONFIG_ISDN_DRV_EICON_ISA diff --git a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c index 9efb770ed1f3..8b5484c1d480 100644 --- a/drivers/isdn/eicon/eicon_mod.c +++ b/drivers/isdn/eicon/eicon_mod.c @@ -1,4 +1,4 @@ -/* $Id: eicon_mod.c,v 1.8 1999/07/25 15:12:08 armin Exp $ +/* $Id: eicon_mod.c,v 1.9 1999/08/18 20:17:02 armin Exp $ * * ISDN lowlevel-module for Eicon.Diehl active cards. * @@ -26,6 +26,10 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_mod.c,v $ + * Revision 1.9 1999/08/18 20:17:02 armin + * Added XLOG function for all cards. + * Bugfix of alloc_skb NULL pointer. + * * Revision 1.8 1999/07/25 15:12:08 armin * fix of some debug logs. * enabled ISA-cards option. @@ -63,6 +67,8 @@ * */ +#define DRIVERPATCH "" + #include #include #include @@ -77,7 +83,7 @@ static eicon_card *cards = (eicon_card *) NULL; /* glob. var , contains start of card-list */ -static char *eicon_revision = "$Revision: 1.8 $"; +static char *eicon_revision = "$Revision: 1.9 $"; extern char *eicon_pci_revision; extern char *eicon_isa_revision; @@ -87,7 +93,7 @@ extern char *eicon_idi_revision; #define MOD_USE_COUNT (GET_USE_COUNT (&__this_module)) #endif -#define EICON_CTRL_VERSION 1 +#define EICON_CTRL_VERSION 2 ulong DebugVar; @@ -355,6 +361,32 @@ eicon_transmit(struct eicon_card *card) } } +static int eicon_xlog(eicon_card *card, xlogreq_t *xlogreq) +{ + xlogreq_t *xlr; + int ret_val; + + if (!(xlr = kmalloc(sizeof(xlogreq_t), GFP_KERNEL))) { + if (DebugVar & 1) + printk(KERN_WARNING "idi_err: alloc_xlogreq_t failed\n"); + return -ENOMEM; + } + if (copy_from_user(xlr, xlogreq, sizeof(xlogreq_t))) { + kfree(xlr); + return -EFAULT; + } + + ret_val = eicon_get_xlog(card, xlr); + + if (copy_to_user(xlogreq, xlr, sizeof(xlogreq_t))) { + kfree(xlr); + return -EFAULT; + } + kfree(xlr); + + return ret_val; +} + static int eicon_command(eicon_card * card, isdn_ctrl * c) { @@ -366,6 +398,10 @@ eicon_command(eicon_card * card, isdn_ctrl * c) int ret = 0; unsigned long flags; + if (DebugVar & 16) + printk(KERN_WARNING "eicon_cmd 0x%x with arg 0x%lx (0x%lx)\n", + c->command, c->arg, (ulong) *c->parm.num); + switch (c->command) { case ISDN_CMD_IOCTL: memcpy(&a, c->parm.num, sizeof(ulong)); @@ -507,6 +543,12 @@ eicon_command(eicon_card * card, isdn_ctrl * c) card, (eicon_manifbuf *)a); return ret; + + case EICON_IOCTL_GETXLOG: + if (!card->flags & EICON_FLAGS_RUNNING) + return XLOG_ERR_CARD_STATE; + ret = eicon_xlog(card, (xlogreq_t *)a); + return ret; #if CONFIG_PCI case EICON_IOCTL_LOADPCI: if (card->flags & EICON_FLAGS_RUNNING) @@ -674,6 +716,10 @@ eicon_command(eicon_card * card, isdn_ctrl * c) if (!(chan = find_channel(card, c->arg & 0x1f))) break; chan->l3prot = (c->arg >> 8); +#ifdef CONFIG_ISDN_TTY_FAX + if (chan->l3prot == ISDN_PROTO_L3_FAX) + chan->fax = c->parm.fax; +#endif return 0; case ISDN_CMD_GETL3: if (!card->flags & EICON_FLAGS_RUNNING) @@ -705,6 +751,17 @@ eicon_command(eicon_card * card, isdn_ctrl * c) case ISDN_CMD_UNLOCK: MOD_DEC_USE_COUNT; return 0; +#ifdef CONFIG_ISDN_TTY_FAX + case ISDN_CMD_FAXCMD: + if (!card->flags & EICON_FLAGS_RUNNING) + return -ENODEV; + if (!(chan = find_channel(card, c->arg & 0x1f))) + break; + if (!chan->fax) + break; + idi_fax_cmd(card, chan); + return 0; +#endif case ISDN_CMD_AUDIO: if (!card->flags & EICON_FLAGS_RUNNING) return -ENODEV; @@ -752,16 +809,19 @@ if_command(isdn_ctrl * c) static int if_writecmd(const u_char * buf, int len, int user, int id, int channel) { +#if 0 + /* Not yet used */ eicon_card *card = eicon_findcard(id); if (card) { if (!card->flags & EICON_FLAGS_RUNNING) - return -ENODEV; + return (len); return (len); } printk(KERN_ERR "eicon: if_writecmd called with invalid driverId!\n"); - return -ENODEV; +#endif + return (len); } static int @@ -779,7 +839,7 @@ if_readstatus(u_char * buf, int len, int user, int id, int channel) printk(KERN_ERR "eicon: if_readstatus called with invalid driverId!\n"); #endif - return -ENODEV; + return 0; } static int @@ -802,6 +862,13 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb) return -ENODEV; } if (chan->fsm_state == EICON_STATE_ACTIVE) { +#ifdef CONFIG_ISDN_TTY_FAX + if (chan->l2prot == ISDN_PROTO_L2_FAX) { + if ((ret = idi_faxdata_send(card, chan, skb)) > 0) + ret = len; + } + else +#endif ret = idi_send_data(card, chan, ack, skb, 1); return (ret); } else { @@ -1231,8 +1298,8 @@ eicon_init(void)) printk("%s\n", eicon_getrev(tmprev)); release += getrel(tmprev); sprintf(tmprev,"%d", release); - printk(KERN_INFO "%s Release: %s.%s\n", DRIVERNAME, - DRIVERRELEASE, tmprev); + printk(KERN_INFO "%s Release: %s.%s%s\n", DRIVERNAME, + DRIVERRELEASE, tmprev, DRIVERPATCH); #ifdef CONFIG_ISDN_DRV_EICON_ISA #ifdef CONFIG_MCA diff --git a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c index 6bb4c9a30904..c1919e9f810c 100644 --- a/drivers/isdn/eicon/eicon_pci.c +++ b/drivers/isdn/eicon/eicon_pci.c @@ -1,4 +1,4 @@ -/* $Id: eicon_pci.c,v 1.9 1999/08/11 21:01:11 keil Exp $ +/* $Id: eicon_pci.c,v 1.10 1999/08/22 20:26:49 calle Exp $ * * ISDN low-level module for Eicon.Diehl active ISDN-Cards. * Hardware-specific code for PCI cards. @@ -26,6 +26,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: eicon_pci.c,v $ + * Revision 1.10 1999/08/22 20:26:49 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.9 1999/08/11 21:01:11 keil * new PCI codefix * @@ -71,7 +77,7 @@ #include "eicon_pci.h" -char *eicon_pci_revision = "$Revision: 1.9 $"; +char *eicon_pci_revision = "$Revision: 1.10 $"; #if CONFIG_PCI /* intire stuff is only for PCI */ diff --git a/drivers/isdn/hisax/arcofi.c b/drivers/isdn/hisax/arcofi.c index 641106a19197..9e582641d30e 100644 --- a/drivers/isdn/hisax/arcofi.c +++ b/drivers/isdn/hisax/arcofi.c @@ -1,4 +1,4 @@ -/* $Id: arcofi.c,v 1.7 1999/07/01 08:11:17 keil Exp $ +/* $Id: arcofi.c,v 1.8 1999/08/25 16:50:51 keil Exp $ * arcofi.c Ansteuerung ARCOFI 2165 * @@ -7,6 +7,9 @@ * * * $Log: arcofi.c,v $ + * Revision 1.8 1999/08/25 16:50:51 keil + * Fix bugs which cause 2.3.14 hangs (waitqueue init) + * * Revision 1.7 1999/07/01 08:11:17 keil * Common HiSax version for 2.0, 2.1, 2.2 and 2.3 kernel * @@ -151,4 +154,8 @@ init_arcofi(struct IsdnCardState *cs) { cs->dc.isac.arcofitimer.function = (void *) arcofi_timer; cs->dc.isac.arcofitimer.data = (long) cs; init_timer(&cs->dc.isac.arcofitimer); +#ifdef COMPAT_HAS_NEW_WAITQ + init_waitqueue_head(&cs->dc.isac.arcofi_wait); +#endif + test_and_set_bit(HW_ARCOFI, &cs->HW_Flags); } diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c index adf6b73b2012..4781a822a84e 100644 --- a/drivers/isdn/hisax/bkm_a4t.c +++ b/drivers/isdn/hisax/bkm_a4t.c @@ -1,4 +1,4 @@ -/* $Id: bkm_a4t.c,v 1.6 1999/08/11 21:01:22 keil Exp $ +/* $Id: bkm_a4t.c,v 1.7 1999/08/22 20:26:55 calle Exp $ * bkm_a4t.c low level stuff for T-Berkom A4T * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -7,6 +7,12 @@ * Author Roland Klabunde (R.Klabunde@Berkom.de) * * $Log: bkm_a4t.c,v $ + * Revision 1.7 1999/08/22 20:26:55 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.6 1999/08/11 21:01:22 keil * new PCI codefix * @@ -42,7 +48,7 @@ extern const char *CardType[]; -const char *bkm_a4t_revision = "$Revision: 1.6 $"; +const char *bkm_a4t_revision = "$Revision: 1.7 $"; static inline u_char diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c index 0defb74b59dd..61709bfebf50 100644 --- a/drivers/isdn/hisax/bkm_a8.c +++ b/drivers/isdn/hisax/bkm_a8.c @@ -1,4 +1,4 @@ -/* $Id: bkm_a8.c,v 1.6 1999/08/11 21:01:24 keil Exp $ +/* $Id: bkm_a8.c,v 1.7 1999/08/22 20:26:58 calle Exp $ * bkm_a8.c low level stuff for Scitel Quadro (4*S0, passive) * derived from the original file sedlbauer.c * derived from the original file niccy.c @@ -7,6 +7,12 @@ * Author Roland Klabunde (R.Klabunde@Berkom.de) * * $Log: bkm_a8.c,v $ + * Revision 1.7 1999/08/22 20:26:58 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.6 1999/08/11 21:01:24 keil * new PCI codefix * @@ -43,7 +49,7 @@ extern const char *CardType[]; -const char sct_quadro_revision[] = "$Revision: 1.6 $"; +const char sct_quadro_revision[] = "$Revision: 1.7 $"; /* To survive the startup phase */ typedef struct { diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c index 6caf0341fe71..9d5ec964b62c 100644 --- a/drivers/isdn/hisax/callc.c +++ b/drivers/isdn/hisax/callc.c @@ -1,4 +1,4 @@ -/* $Id: callc.c,v 2.31 1999/08/05 20:43:10 keil Exp $ +/* $Id: callc.c,v 2.34 1999/08/25 20:02:34 werner Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -11,6 +11,20 @@ * Fritz Elfert * * $Log: callc.c,v $ + * Revision 2.34 1999/08/25 20:02:34 werner + * Changed return values for stat_icall(w) from 3->4 and 4->5 because of conflicts + * with existing software definitions. (PtP incomplete called party number) + * + * Revision 2.33 1999/08/25 17:00:09 keil + * Make ISAR V32bis modem running + * Make LL->HL interface open for additional commands + * + * Revision 2.32 1999/08/22 20:27:01 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 2.31 1999/08/05 20:43:10 keil * ISAR analog modem support * @@ -140,7 +154,7 @@ extern long mod_use_count_; #endif /* COMPAT_HAS_NEW_SYMTAB */ #endif /* MODULE */ -const char *lli_revision = "$Revision: 2.31 $"; +const char *lli_revision = "$Revision: 2.34 $"; extern struct IsdnCard cards[]; extern int nrcards; @@ -498,12 +512,12 @@ lli_deliver_call(struct FsmInst *fi, int event, void *arg) FsmChangeState(fi, ST_IN_ALERT_SENT); chanp->d_st->lli.l4l3(chanp->d_st, CC_ALERTING | REQUEST, chanp->proc); break; - case 4: /* direct redirect */ - case 3: /* Proceeding desired */ + case 5: /* direct redirect */ + case 4: /* Proceeding desired */ FsmDelTimer(&chanp->drel_timer, 61); FsmChangeState(fi, ST_IN_PROCEED_SEND); chanp->d_st->lli.l4l3(chanp->d_st, CC_PROCEED_SEND | REQUEST, chanp->proc); - if (ret == 4) + if (ret == 5) { chanp->setup = ic.parm.setup; chanp->d_st->lli.l4l3(chanp->d_st, CC_REDIR | REQUEST, chanp->proc); } @@ -971,6 +985,7 @@ release_b_st(struct Channel *chanp) case (ISDN_PROTO_L2_HDLC): case (ISDN_PROTO_L2_TRANS): case (ISDN_PROTO_L2_MODEM): + case (ISDN_PROTO_L2_FAX): releasestack_transl2(st); break; } @@ -1359,6 +1374,9 @@ init_b_st(struct Channel *chanp, int incoming) case (ISDN_PROTO_L2_MODEM): st->l1.mode = L1_MODE_V32; break; + case (ISDN_PROTO_L2_FAX): + st->l1.mode = L1_MODE_FAX; + break; } chanp->bcs->conmsg = NULL; if (chanp->bcs->BC_SetStack(st, chanp->bcs)) @@ -1388,6 +1406,7 @@ init_b_st(struct Channel *chanp, int incoming) case (ISDN_PROTO_L2_HDLC): case (ISDN_PROTO_L2_TRANS): case (ISDN_PROTO_L2_MODEM): + case (ISDN_PROTO_L2_FAX): st->l1.l1l2 = lltrans_handler; st->lli.userdata = chanp; st->lli.l1writewakeup = ll_writewakeup; @@ -1395,8 +1414,7 @@ init_b_st(struct Channel *chanp, int incoming) setstack_l3bc(st, chanp); break; } - test_and_set_bit(FLG_START_B, &chanp->Flags); - + test_and_set_bit(FLG_START_B, &chanp->Flags); return (0); } @@ -1547,29 +1565,29 @@ lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg * /***************************************************************/ static int set_channel_limit(struct IsdnCardState *cs, int chanmax) -{ isdn_ctrl ic; - int i, ii; - - if ((chanmax < 0) || (chanmax > 2)) - return(-EINVAL); - cs->chanlimit = 0; - for (ii = 0; ii < 2; ii++) { - ic.driver = cs->myid; - ic.command = ISDN_STAT_DISCH; - ic.arg = ii; - if (ii >= chanmax) - ic.parm.num[0] = 0; /* disabled */ - else - ic.parm.num[0] = 1; /* enabled */ - i = cs->iif.statcallb(&ic); - if (i) return(-EINVAL); - if (ii < chanmax) - cs->chanlimit++; - } - return(0); +{ + isdn_ctrl ic; + int i, ii; + + if ((chanmax < 0) || (chanmax > 2)) + return(-EINVAL); + cs->chanlimit = 0; + for (ii = 0; ii < 2; ii++) { + ic.driver = cs->myid; + ic.command = ISDN_STAT_DISCH; + ic.arg = ii; + if (ii >= chanmax) + ic.parm.num[0] = 0; /* disabled */ + else + ic.parm.num[0] = 1; /* enabled */ + i = cs->iif.statcallb(&ic); + if (i) return(-EINVAL); + if (ii < chanmax) + cs->chanlimit++; + } + return(0); } /* set_channel_limit */ - int HiSax_command(isdn_ctrl * ic) { @@ -1578,7 +1596,6 @@ HiSax_command(isdn_ctrl * ic) struct Channel *chanp; int i; u_int num; - u_long adr; if (!csta) { printk(KERN_ERR @@ -1586,12 +1603,10 @@ HiSax_command(isdn_ctrl * ic) ic->command, ic->driver); return -ENODEV; } - switch (ic->command) { case (ISDN_CMD_SETEAZ): chanp = csta->channel + ic->arg; break; - case (ISDN_CMD_SETL2): chanp = csta->channel + (ic->arg & 0xff); if (chanp->debug & 1) @@ -1767,11 +1782,6 @@ HiSax_command(isdn_ctrl * ic) chanp->d_st->lli.l4l3(chanp->d_st, DL_ESTABLISH | REQUEST, NULL); break; - case (9): /* load firmware */ - memcpy(&adr, ic->parm.num, sizeof(ulong)); - csta->cardmsg(csta, CARD_LOAD_FIRM, - (void *) adr); - break; #ifdef MODULE case (55): MOD_USE_COUNT = 0; @@ -1797,23 +1807,12 @@ HiSax_command(isdn_ctrl * ic) printk(KERN_DEBUG "HiSax: l3 debugging flags card %d set to %x\n", csta->cardnr + 1, *(unsigned int *) ic->parm.num); break; - case (10): - i = *(unsigned int *) ic->parm.num; - if ((i < 0) || (i > 2)) - return(-EINVAL); /* invalid number */ + case (10): + i = *(unsigned int *) ic->parm.num; return(set_channel_limit(csta, i)); - break; - case (12): - i = *(unsigned int *) ic->parm.num; -#ifdef CONFIG_HISAX_HFC_PCI - if (csta->typ != ISDN_CTYPE_HFC_PCI) - return(-EINVAL); - return(hfcpci_set_echo(csta,i)); -#else - return(-EINVAL); -#endif - break; default: + if (csta->auxcmd) + return(csta->auxcmd(csta, ic)); printk(KERN_DEBUG "HiSax: invalid ioclt %d\n", (int) ic->arg); return (-EINVAL); @@ -1850,9 +1849,10 @@ HiSax_command(isdn_ctrl * ic) return(-EINVAL); break; default: - break; + if (csta->auxcmd) + return(csta->auxcmd(csta, ic)); + return(-EINVAL); } - return (0); } diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index 6e54fd1dcfeb..aef71936bc14 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -1,10 +1,13 @@ -/* $Id: config.c,v 2.30 1999/08/05 20:43:14 keil Exp $ +/* $Id: config.c,v 2.31 1999/08/25 16:47:43 keil Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden * * * $Log: config.c,v $ + * Revision 2.31 1999/08/25 16:47:43 keil + * Support new __setup; allow to add FEATURES after register_isdn + * * Revision 2.30 1999/08/05 20:43:14 keil * ISAR analog modem support * @@ -117,6 +120,10 @@ #include #include #include +#include +#ifdef COMPAT_HAS_NEW_SETUP +#include +#endif #include "hisax.h" #include #include @@ -546,12 +553,24 @@ HiSax_mod_inc_use_count(void) #ifdef MODULE #define HiSax_init init_module #else +#ifdef COMPAT_HAS_NEW_SETUP +#define MAX_ARG (HISAX_MAX_CARDS*5) +__initfunc(int +HiSax_setup(char *line)) +{ + int i, j, argc; + int ints[MAX_ARG + 1]; + char *str; + + str = get_options(line, MAX_ARG, ints); +#else __initfunc(void HiSax_setup(char *str, int *ints)) { int i, j, argc; - +#endif argc = ints[0]; + printk(KERN_DEBUG"HiSax_setup: argc(%d) str(%s)\n", argc, str); i = 0; j = 1; while (argc && (i < HISAX_MAX_CARDS)) { @@ -589,8 +608,15 @@ HiSax_setup(char *str, int *ints)) strcpy(HiSaxID, "HiSax"); HiSax_id = HiSaxID; } +#ifdef COMPAT_HAS_NEW_SETUP + return(1); } -#endif + +__setup("hisax=", HiSax_setup); +#else +} +#endif /* COMPAT_HAS_NEW_SETUP */ +#endif /* MODULES */ #if CARD_TELES0 extern int setup_teles0(struct IsdnCard *card); @@ -875,7 +901,7 @@ HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...) } int -ll_run(struct IsdnCardState *cs) +ll_run(struct IsdnCardState *cs, int addfeatures) { long flags; isdn_ctrl ic; @@ -884,6 +910,7 @@ ll_run(struct IsdnCardState *cs) cli(); ic.driver = cs->myid; ic.command = ISDN_STAT_RUN; + cs->iif.features |= addfeatures; cs->iif.statcallb(&ic); restore_flags(flags); return 0; @@ -1053,7 +1080,6 @@ checkcard(int cardnr, char *id, int *busy_flag)) cs->iif.features = ISDN_FEATURE_L2_X75I | ISDN_FEATURE_L2_HDLC | - ISDN_FEATURE_L2_MODEM | ISDN_FEATURE_L2_TRANS | ISDN_FEATURE_L3_TRANS | #ifdef CONFIG_HISAX_1TR6 @@ -1269,7 +1295,7 @@ checkcard(int cardnr, char *id, int *busy_flag)) CallcNewChan(cs); /* ISAR needs firmware download first */ if (!test_bit(HW_ISAR, &cs->HW_Flags)) - ll_run(cs); + ll_run(cs, 0); restore_flags(flags); return (1); } diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c index 8f47869ba8f7..c2d6cf2d3852 100644 --- a/drivers/isdn/hisax/elsa.c +++ b/drivers/isdn/hisax/elsa.c @@ -1,4 +1,4 @@ -/* $Id: elsa.c,v 2.17 1999/08/11 20:57:40 keil Exp $ +/* $Id: elsa.c,v 2.18 1999/08/25 16:50:54 keil Exp $ * elsa.c low level stuff for Elsa isdn cards * @@ -14,6 +14,9 @@ * for ELSA PCMCIA support * * $Log: elsa.c,v $ + * Revision 2.18 1999/08/25 16:50:54 keil + * Fix bugs which cause 2.3.14 hangs (waitqueue init) + * * Revision 2.17 1999/08/11 20:57:40 keil * bugfix IPAC version 1.1 * new PCI codefix @@ -96,7 +99,7 @@ extern const char *CardType[]; -const char *Elsa_revision = "$Revision: 2.17 $"; +const char *Elsa_revision = "$Revision: 2.18 $"; const char *Elsa_Types[] = {"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro", "PCMCIA", "QS 1000", "QS 3000", "QS 1000 PCI", "QS 3000 PCI", @@ -180,6 +183,7 @@ const char *ITACVer[] = #define ELSA_IPAC_LINE_LED 0x40 /* Bit 6 Gelbe LED */ #define ELSA_IPAC_STAT_LED 0x80 /* Bit 7 Gruene LED */ +#if ARCOFI_USE static struct arcofi_msg ARCOFI_XOP_F = {NULL,0,2,{0xa1,0x3f,0,0,0,0,0,0,0,0}}; /* Normal OP */ static struct arcofi_msg ARCOFI_XOP_1 = @@ -203,9 +207,8 @@ static struct arcofi_msg ARCOFI_XOP_0 = static void set_arcofi(struct IsdnCardState *cs, int bc); -#if ARCOFI_USE #include "elsa_ser.c" -#endif +#endif /* ARCOFI_USE */ static inline u_char readreg(unsigned int ale, unsigned int adr, u_char off) @@ -432,6 +435,7 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs) cs->hw.elsa.counter++; } } +#if ARCOFI_USE if (cs->hw.elsa.MFlag) { val = serial_inp(cs, UART_MCR); val ^= 0x8; @@ -440,6 +444,7 @@ elsa_interrupt(int intno, void *dev_id, struct pt_regs *regs) val ^= 0x8; serial_outp(cs, UART_MCR, val); } +#endif if (cs->hw.elsa.trig) byteout(cs->hw.elsa.trig, 0x00); writereg(cs->hw.elsa.ale, cs->hw.elsa.hscx, HSCX_MASK, 0x0); @@ -514,7 +519,9 @@ release_io_elsa(struct IsdnCardState *cs) int bytecnt = 8; del_timer(&cs->hw.elsa.tl); +#if ARCOFI_USE clear_arcofi(cs); +#endif if (cs->hw.elsa.ctrl) byteout(cs->hw.elsa.ctrl, 0); /* LEDs Out */ if (cs->subtyp == ELSA_QS1000PCI) { @@ -536,7 +543,9 @@ release_io_elsa(struct IsdnCardState *cs) (cs->subtyp == ELSA_PCF) || (cs->subtyp == ELSA_QS3000PCI)) { bytecnt = 16; +#if ARCOFI_USE release_modem(cs); +#endif } if (cs->hw.elsa.base) release_region(cs->hw.elsa.base, bytecnt); @@ -592,6 +601,8 @@ reset_elsa(struct IsdnCardState *cs) } } +#if ARCOFI_USE + static void set_arcofi(struct IsdnCardState *cs, int bc) { cs->dc.isac.arcofi_bc = bc; @@ -602,7 +613,6 @@ set_arcofi(struct IsdnCardState *cs, int bc) { static int check_arcofi(struct IsdnCardState *cs) { -#if ARCOFI_USE int arcofi_present = 0; char tmp[40]; char *t; @@ -690,9 +700,9 @@ check_arcofi(struct IsdnCardState *cs) interruptible_sleep_on(&cs->dc.isac.arcofi_wait); return(1); } -#endif return(0); } +#endif /* ARCOFI_USE */ static void elsa_led_handler(struct IsdnCardState *cs) @@ -738,8 +748,7 @@ elsa_led_handler(struct IsdnCardState *cs) static int Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) { - int len, ret = 0; - u_char *msg; + int ret = 0; long flags; switch (mt) { @@ -828,8 +837,12 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) cs->hw.elsa.status &= ~0x0100; } break; +#if ARCOFI_USE case CARD_AUX_IND: if (cs->hw.elsa.MFlag) { + int len; + u_char *msg; + if (!arg) return(0); msg = arg; @@ -838,6 +851,7 @@ Elsa_card_msg(struct IsdnCardState *cs, int mt, void *arg) modem_write_cmd(cs, msg, len); } break; +#endif } if (cs->typ == ISDN_CTYPE_ELSA) { int pwr = bytein(cs->hw.elsa.ale); @@ -1199,7 +1213,9 @@ setup_elsa(struct IsdnCard *card) request_region(cs->hw.elsa.cfg, 0x80, "elsa isdn pci"); } } +#if ARCOFI_USE init_arcofi(cs); +#endif cs->hw.elsa.tl.function = (void *) elsa_led_handler; cs->hw.elsa.tl.data = (long) cs; init_timer(&cs->hw.elsa.tl); diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c index 199bf2b609c8..ce83fc859086 100644 --- a/drivers/isdn/hisax/gazel.c +++ b/drivers/isdn/hisax/gazel.c @@ -1,4 +1,4 @@ -/* $Id: gazel.c,v 2.5 1999/08/11 21:01:26 keil Exp $ +/* $Id: gazel.c,v 2.6 1999/08/22 20:27:03 calle Exp $ * gazel.c low level stuff for Gazel isdn cards * @@ -6,6 +6,12 @@ * based on source code from Karsten Keil * * $Log: gazel.c,v $ + * Revision 2.6 1999/08/22 20:27:03 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 2.5 1999/08/11 21:01:26 keil * new PCI codefix * @@ -36,7 +42,7 @@ #endif extern const char *CardType[]; -const char *gazel_revision = "$Revision: 2.5 $"; +const char *gazel_revision = "$Revision: 2.6 $"; #define R647 1 #define R685 2 diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c index 837c957bed80..6d3f4efb7c58 100644 --- a/drivers/isdn/hisax/hfc_pci.c +++ b/drivers/isdn/hisax/hfc_pci.c @@ -1,4 +1,4 @@ -/* $Id: hfc_pci.c,v 1.13 1999/08/11 21:01:28 keil Exp $ +/* $Id: hfc_pci.c,v 1.16 1999/08/25 17:01:27 keil Exp $ * hfc_pci.c low level driver for CCD´s hfc-pci based cards * @@ -23,6 +23,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: hfc_pci.c,v $ + * Revision 1.16 1999/08/25 17:01:27 keil + * Use new LL->HL auxcmd call + * + * Revision 1.15 1999/08/22 20:27:05 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * + * Revision 1.14 1999/08/12 18:59:45 werner + * Added further manufacturer and device ids to PCI list + * * Revision 1.13 1999/08/11 21:01:28 keil * new PCI codefix * @@ -80,20 +92,33 @@ extern const char *CardType[]; -static const char *hfcpci_revision = "$Revision: 1.13 $"; - -static const int CCD_VENDOR_IDS[] = { - 0x1043, /* Asuscom */ - 0x1051, /* Motorola MC145575 */ - 0x1397, /* CCD and Billion */ - 0, -}; - -static const int CCD_DEVICE_IDS[] = { - 0x675, /* Asuscom */ - 0x100, /* Motorola MC145575 */ - 0x2BD0, /* CCD and Billion */ - 0, +static const char *hfcpci_revision = "$Revision: 1.16 $"; + +/* table entry in the PCI devices list */ +typedef struct { + int vendor_id; + int device_id; + char *vendor_name; + char *card_name; + } PCI_ENTRY; + +static const PCI_ENTRY id_list[] = { + {0x1397,0x2BD0,"CCD/Billion/Asuscom","2BD0"}, + {0x1397,0xB000,"Billion","B000"}, + {0x1397,0xB006,"Billion","B006"}, + {0x1397,0xB007,"Billion","B007"}, + {0x1397,0xB008,"Billion","B008"}, + {0x1397,0xB009,"Billion","B009"}, + {0x1397,0xB00A,"Billion","B00A"}, + {0x1397,0xB00B,"Billion","B00B"}, + {0x1397,0xB00C,"Billion","B00C"}, + {0x1043,0x0675,"Asuscom/Askey","675"}, + {0x0871,0xFFA2,"German telekom","T-Concept"}, + {0x0871,0xFFA1,"German telekom","A1T"}, + {0x1051,0x0100,"Motorola MC145575","MC145575"}, + {0x1397,0xB100,"Seyeon","B100"}, + {0x15B0,0x2BD0,"Zoltrix","2BD0"}, + {0,0,NULL,NULL}, }; @@ -618,9 +643,12 @@ hfcpci_fill_fifo(struct BCState *bcs) /***********************/ /* set/reset echo mode */ /***********************/ -int hfcpci_set_echo(struct IsdnCardState *cs, int i) -{ int flags; - +static int +hfcpci_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) +{ + int flags; + int i = *(unsigned int *) ic->parm.num; + if (cs->chanlimit > 1) return(-EINVAL); @@ -651,7 +679,7 @@ int hfcpci_set_echo(struct IsdnCardState *cs, int i) Write_hfc(cs, HFCPCI_INT_M1, cs->hw.hfcpci.int_m1); restore_flags(flags); return(0); -} /* hfcpci_set_echo */ +} /* hfcpci_auxcmd */ /*****************************/ /* E-channel receive routine */ @@ -1476,9 +1504,9 @@ __initfunc(int return (0); } i = 0; - while (CCD_VENDOR_IDS[i]) { - tmp_hfcpci = pci_find_device(CCD_VENDOR_IDS[i], - CCD_DEVICE_IDS[i], + while (id_list[i].vendor_id) { + tmp_hfcpci = pci_find_device(id_list[i].vendor_id, + id_list[i].device_id, dev_hfcpci); if (tmp_hfcpci) break; i++; @@ -1494,6 +1522,7 @@ __initfunc(int return (0); } cs->hw.hfcpci.pci_io = (char *) get_pcibase(dev_hfcpci, 1); + printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n",id_list[i].vendor_name,id_list[i].card_name); } else { printk(KERN_WARNING "HFC-PCI: No PCI card found\n"); return (0); @@ -1503,14 +1532,14 @@ __initfunc(int unsigned char irq; i = 0; - while (CCD_VENDOR_IDS[i]) { - if (pcibios_find_device(CCD_VENDOR_IDS[i], - CCD_DEVICE_IDS[i], pci_index, + while (id_list[i].vendor_id) { + if (pcibios_find_device(id_list[i].vendor_id, + id_list[i].device_id, pci_index, &cs->hw.hfcpci.pci_bus, &cs->hw.hfcpci.pci_device_fn) == 0) break; i++; } - if (!CCD_VENDOR_IDS[i]) + if (!id_list[i].vendor_id) continue; pcibios_read_config_byte(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, @@ -1520,6 +1549,7 @@ __initfunc(int pcibios_read_config_dword(cs->hw.hfcpci.pci_bus, cs->hw.hfcpci.pci_device_fn, PCI_BASE_ADDRESS_1, (void *) &cs->hw.hfcpci.pci_io); + printk(KERN_INFO "HiSax: HFC-PCI card manufacturer: %s card name: %s\n",id_list[i].vendor_name,id_list[i].card_name); break; } if (pci_index == 255) { @@ -1577,6 +1607,7 @@ __initfunc(int reset_hfcpci(cs); cs->cardmsg = &hfcpci_card_msg; + cs->auxcmd = &hfcpci_auxcmd; return (1); #else printk(KERN_WARNING "HFC-PCI: NO_PCI_BIOS\n"); diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 14c201386a02..b2859bce73f0 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -1,8 +1,12 @@ -/* $Id: hisax.h,v 2.33 1999/08/05 20:43:16 keil Exp $ +/* $Id: hisax.h,v 2.34 1999/08/25 17:00:04 keil Exp $ * Basic declarations, defines and prototypes * * $Log: hisax.h,v $ + * Revision 2.34 1999/08/25 17:00:04 keil + * Make ISAR V32bis modem running + * Make LL->HL interface open for additional commands + * * Revision 2.33 1999/08/05 20:43:16 keil * ISAR analog modem support * @@ -154,7 +158,6 @@ #define CARD_RELEASE 0x00F3 #define CARD_TEST 0x00F4 #define CARD_AUX_IND 0x00F5 -#define CARD_LOAD_FIRM 0x00F6 #define PH_ACTIVATE 0x0100 #define PH_DEACTIVATE 0x0110 @@ -458,6 +461,12 @@ struct isar_hw { int rcvidx; int txcnt; int mml; + u_char state; + u_char cmd; + u_char mod; + u_char newcmd; + u_char newmod; + struct timer_list ftimer; u_char *rcvbuf; /* B-Channel receive Buffer */ u_char conmsg[16]; struct isar_reg *reg; @@ -528,6 +537,14 @@ struct amd7930_hw { #define BC_FLG_HALF 5 #define BC_FLG_EMPTY 6 #define BC_FLG_ORIG 7 +#define BC_FLG_DLEETX 8 +#define BC_FLG_LASTDLE 9 +#define BC_FLG_FIRST 10 +#define BC_FLG_LASTDATA 11 +#define BC_FLG_NMD_DATA 12 +#define BC_FLG_FTI_RUN 13 +#define BC_FLG_LL_OK 14 +#define BC_FLG_LL_CONN 15 #define L1_MODE_NULL 0 #define L1_MODE_TRANS 1 @@ -852,6 +869,7 @@ struct hfcpci_chip { #define HW_IOM1 0 #define HW_IPAC 1 #define HW_ISAR 2 +#define HW_ARCOFI 3 #define FLG_TWO_DCHAN 4 #define FLG_L1_DBUSY 5 #define FLG_DBUSY_TIMER 6 @@ -910,6 +928,7 @@ struct IsdnCardState { void (*setstack_d) (struct PStack *, struct IsdnCardState *); void (*DC_Close) (struct IsdnCardState *); void (*irq_func) (int, void *, struct pt_regs *); + int (*auxcmd) (struct IsdnCardState *, isdn_ctrl *); struct Channel channel[2+MAX_WAITING_CALLS]; struct BCState bcs[2+MAX_WAITING_CALLS]; struct PStack *stlist; @@ -1138,7 +1157,6 @@ struct IsdnCardState { #ifdef CONFIG_HISAX_HFC_PCI #define CARD_HFC_PCI 1 -extern int hfcpci_set_echo(struct IsdnCardState *, int); #else #define CARD_HFC_PCI 0 #endif @@ -1327,7 +1345,7 @@ void setstack_isac(struct PStack *st, struct IsdnCardState *cs); #define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);} -int ll_run(struct IsdnCardState *cs); +int ll_run(struct IsdnCardState *cs, int addfeatures); void ll_stop(struct IsdnCardState *cs); void CallcNew(void); void CallcFree(void); diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c index 6a130ed01001..46d5daef0071 100644 --- a/drivers/isdn/hisax/isac.c +++ b/drivers/isdn/hisax/isac.c @@ -1,4 +1,4 @@ -/* $Id: isac.c,v 1.22 1999/08/09 19:04:40 keil Exp $ +/* $Id: isac.c,v 1.23 1999/08/25 16:50:52 keil Exp $ * isac.c ISAC specific routines * @@ -9,6 +9,9 @@ * ../../../Documentation/isdn/HiSax.cert * * $Log: isac.c,v $ + * Revision 1.23 1999/08/25 16:50:52 keil + * Fix bugs which cause 2.3.14 hangs (waitqueue init) + * * Revision 1.22 1999/08/09 19:04:40 keil * Fix race condition - Thanks to Christer Weinigel * @@ -168,10 +171,14 @@ isac_bh(struct IsdnCardState *cs) DChannel_proc_rcv(cs); if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) DChannel_proc_xmt(cs); +#if ARCOFI_USE + if (!test_bit(HW_ARCOFI, &cs->HW_Flags)) + return; if (test_and_clear_bit(D_RX_MON1, &cs->event)) arcofi_fsm(cs, ARCOFI_RX_END, NULL); if (test_and_clear_bit(D_TX_MON1, &cs->event)) arcofi_fsm(cs, ARCOFI_TX_END, NULL); +#endif } void diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c index 05fb7fe9cb95..96442ff7d4dd 100644 --- a/drivers/isdn/hisax/isar.c +++ b/drivers/isdn/hisax/isar.c @@ -1,4 +1,4 @@ -/* $Id: isar.c,v 1.4 1999/08/05 20:43:18 keil Exp $ +/* $Id: isar.c,v 1.5 1999/08/25 16:59:55 keil Exp $ * isar.c ISAR (Siemens PSB 7110) specific routines * @@ -6,6 +6,10 @@ * * * $Log: isar.c,v $ + * Revision 1.5 1999/08/25 16:59:55 keil + * Make ISAR V32bis modem running + * Make LL->HL interface open for additional commands + * * Revision 1.4 1999/08/05 20:43:18 keil * ISAR analog modem support * @@ -309,6 +313,10 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf) printk(KERN_DEBUG"isar firmware block %5d words loaded\n", blk_head.len); } + /* 10ms delay */ + cnt = 10; + while (cnt--) + udelay(1000); msg[0] = 0xff; msg[1] = 0xfe; ireg->bstat = 0; @@ -343,20 +351,26 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf) printk(KERN_DEBUG"isar general status event %x\n", ireg->bstat); } + /* 10ms delay */ + cnt = 10; + while (cnt--) + udelay(1000); ireg->iis = 0; if (!sendmsg(cs, ISAR_HIS_DIAG, ISAR_CTRL_STST, 0, NULL)) { printk(KERN_ERR"isar sendmsg self tst failed\n"); ret = 1;goto reterrflg; } - cnt = 1000; /* max 10 ms */ + cnt = 10000; /* max 100 ms */ while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { udelay(10); cnt--; } + udelay(1000); if (!cnt) { printk(KERN_ERR"isar no self tst response\n"); ret = 1;goto reterrflg; - } else if ((ireg->cmsb == ISAR_CTRL_STST) && (ireg->clsb == 1) + } + if ((ireg->cmsb == ISAR_CTRL_STST) && (ireg->clsb == 1) && (ireg->par[0] == 0)) { printk(KERN_DEBUG"isar selftest OK\n"); } else { @@ -369,11 +383,12 @@ isar_load_firmware(struct IsdnCardState *cs, u_char *buf) printk(KERN_ERR"isar RQST SVN failed\n"); ret = 1;goto reterror; } - cnt = 10000; /* max 100 ms */ + cnt = 30000; /* max 300 ms */ while ((ireg->iis != ISAR_IIS_DIAG) && cnt) { udelay(10); cnt--; } + udelay(1000); if (!cnt) { printk(KERN_ERR"isar no SVN response\n"); ret = 1;goto reterrflg; @@ -402,7 +417,18 @@ reterror: return(ret); } -void +extern void BChannel_bh(struct BCState *); +#define B_LL_NOCARRIER 8 +#define B_LL_CONNECT 9 +#define B_LL_OK 10 + +static void +isar_bh(struct BCState *bcs) +{ + BChannel_bh(bcs); +} + +static void isar_sched_event(struct BCState *bcs, int event) { bcs->event |= 1 << event; @@ -464,9 +490,9 @@ isar_rcv_frame(struct IsdnCardState *cs, struct BCState *bcs) if (bcs->hw.isar.rcvidx < 3) { /* last 2 bytes are the FCS */ printk(KERN_WARNING "ISAR: HDLC frame too short(%d)\n", bcs->hw.isar.rcvidx); - } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) + } else if (!(skb = dev_alloc_skb(bcs->hw.isar.rcvidx-2))) { printk(KERN_WARNING "ISAR: receive out of memory\n"); - else { + } else { SET_SKB_FREE(skb); memcpy(skb_put(skb, bcs->hw.isar.rcvidx-2), bcs->hw.isar.rcvbuf, bcs->hw.isar.rcvidx-2); @@ -709,7 +735,6 @@ isar_pump_status_ev(struct BCState *bcs, u_char devt) { case PSEV_DSR_ON: if (cs->debug & L1_DEB_HSCX) debugl1(cs, "pump stev DSR ON"); -// sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, 0xCF, 0, NULL); break; case PSEV_DSR_OFF: if (cs->debug & L1_DEB_HSCX) @@ -734,7 +759,7 @@ isar_pump_status_ev(struct BCState *bcs, u_char devt) { } } -static char debbuf[64]; +static char debbuf[128]; void isar_int_main(struct IsdnCardState *cs) @@ -806,6 +831,12 @@ isar_int_main(struct IsdnCardState *cs) debugl1(cs, debbuf); } break; + case ISAR_IIS_INVMSG: + rcv_mbox(cs, ireg, debbuf); + if (cs->debug & L1_DEB_WARN) + debugl1(cs, "invalid msg his:%x", + ireg->cmsb); + break; default: rcv_mbox(cs, ireg, debbuf); if (cs->debug & L1_DEB_WARN) @@ -816,7 +847,7 @@ isar_int_main(struct IsdnCardState *cs) restore_flags(flags); } -void +static void setup_pump(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; u_char dps = SET_DPS(bcs->hw.isar.dpath); @@ -840,15 +871,12 @@ setup_pump(struct BCState *bcs) { } else { param[5] = PV32P6_ATN; } - param[0] = 11; /* 11 db */ -// param[1] = PV32P2_V22A | PV32P2_V22B | PV32P2_V21; - param[1] = PV32P2_V22A; -// param[2] = PV32P3_AMOD | PV32P3_V32B; - param[2] = PV32P3_AMOD; - param[3] = PV32P4_48; - param[4] = PV32P5_48; -// param[3] = PV32P4_UT144; -// param[4] = PV32P5_UT144; + param[0] = 6; /* 6 db */ + param[1] = PV32P2_V23R | PV32P2_V22A | PV32P2_V22B | + PV32P2_V22C | PV32P2_V21 | PV32P2_BEL; + param[2] = PV32P3_AMOD | PV32P3_V32B | PV32P3_V23B; + param[3] = PV32P4_UT144; + param[4] = PV32P5_UT144; if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 6, param)) { if (cs->debug) debugl1(cs, "isar pump datamodem cfg dp%d failed", @@ -863,7 +891,7 @@ setup_pump(struct BCState *bcs) { } else { param[1] = PFAXP2_ATN; } - param[0] = 8; /* 8 db */ + param[0] = 6; /* 6 db */ if (!sendmsg(cs, dps | ISAR_HIS_PUMPCFG, ctrl, 2, param)) { if (cs->debug) debugl1(cs, "isar pump faxmodem cfg dp%d failed", @@ -878,7 +906,7 @@ setup_pump(struct BCState *bcs) { } } -void +static void setup_sart(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; u_char dps = SET_DPS(bcs->hw.isar.dpath); @@ -900,7 +928,9 @@ setup_sart(struct BCState *bcs) { } break; case L1_MODE_HDLC: - if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, "\0")) { + case L1_MODE_FAX: + param[0] = 0; + if (!sendmsg(cs, dps | ISAR_HIS_SARTCFG, SMODE_HDLC, 1, param)) { if (cs->debug) debugl1(cs, "isar sart hdlc dp%d failed", bcs->hw.isar.dpath); @@ -924,7 +954,7 @@ setup_sart(struct BCState *bcs) { } } -void +static void setup_iom2(struct BCState *bcs) { struct IsdnCardState *cs = bcs->cs; u_char dps = SET_DPS(bcs->hw.isar.dpath); @@ -967,6 +997,9 @@ modeisar(struct BCState *bcs, int mode, int bc) bcs->channel = bc; switch (mode) { case L1_MODE_NULL: /* init */ + if (!bcs->hw.isar.dpath) + /* no init for dpath 0 */ + return(0); break; case L1_MODE_TRANS: case L1_MODE_HDLC: @@ -983,6 +1016,7 @@ modeisar(struct BCState *bcs, int mode, int bc) } break; case L1_MODE_V32: + case L1_MODE_FAX: /* only datapath 1 */ if (!test_and_set_bit(ISAR_DP1_USE, &bcs->hw.isar.reg->Flags)) @@ -1032,6 +1066,7 @@ isar_setup(struct IsdnCardState *cs) cs->bcs[i].mode = 0; cs->bcs[i].hw.isar.dpath = i + 1; modeisar(&cs->bcs[i], 0, 0); + cs->bcs[i].tqueue.routine = (void *) (void *) isar_bh; } } @@ -1169,6 +1204,36 @@ setstack_isar(struct PStack *st, struct BCState *bcs) return (0); } +int +isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) { + u_long adr; + int features; + + if (cs->debug & L1_DEB_HSCX) + debugl1(cs, "isar_auxcmd cmd/ch %x/%d", ic->command, ic->arg); + switch (ic->command) { + case (ISDN_CMD_IOCTL): + switch (ic->arg) { + case (9): /* load firmware */ + features = ISDN_FEATURE_L2_MODEM; + memcpy(&adr, ic->parm.num, sizeof(ulong)); + if (isar_load_firmware(cs, (u_char *)adr)) + return(1); + else + ll_run(cs, features); + break; + default: + printk(KERN_DEBUG "HiSax: invalid ioclt %d\n", + (int) ic->arg); + return(-EINVAL); + } + break; + default: + return(-EINVAL); + } + return(0); +} + HISAX_INITFUNC(void initisar(struct IsdnCardState *cs)) { diff --git a/drivers/isdn/hisax/isar.h b/drivers/isdn/hisax/isar.h index c17875263901..c6ac6532b231 100644 --- a/drivers/isdn/hisax/isar.h +++ b/drivers/isdn/hisax/isar.h @@ -1,10 +1,14 @@ -/* $Id: isar.h,v 1.4 1999/08/05 20:43:20 keil Exp $ +/* $Id: isar.h,v 1.5 1999/08/25 16:59:59 keil Exp $ * isar.h ISAR (Siemens PSB 7110) specific defines * * Author Karsten Keil (keil@isdn4linux.de) * * * $Log: isar.h,v $ + * Revision 1.5 1999/08/25 16:59:59 keil + * Make ISAR V32bis modem running + * Make LL->HL interface open for additional commands + * * Revision 1.4 1999/08/05 20:43:20 keil * ISAR analog modem support * @@ -33,40 +37,41 @@ #define ISAR_WADR 0x4a #define ISAR_RADR 0x48 -#define ISAR_HIS_VNR 0x14 -#define ISAR_HIS_DKEY 0x02 -#define ISAR_HIS_FIRM 0x1e -#define ISAR_HIS_STDSP 0x08 -#define ISAR_HIS_DIAG 0x05 -#define ISAR_HIS_P0CFG 0x3c -#define ISAR_HIS_P12CFG 0x24 +#define ISAR_HIS_VNR 0x14 +#define ISAR_HIS_DKEY 0x02 +#define ISAR_HIS_FIRM 0x1e +#define ISAR_HIS_STDSP 0x08 +#define ISAR_HIS_DIAG 0x05 +#define ISAR_HIS_P0CFG 0x3c +#define ISAR_HIS_P12CFG 0x24 #define ISAR_HIS_SARTCFG 0x25 #define ISAR_HIS_PUMPCFG 0x26 #define ISAR_HIS_PUMPCTRL 0x2a #define ISAR_HIS_IOM2CFG 0x27 #define ISAR_HIS_IOM2REQ 0x07 #define ISAR_HIS_IOM2CTRL 0x2b -#define ISAR_HIS_BSTREQ 0x0c -#define ISAR_HIS_PSTREQ 0x0e -#define ISAR_HIS_SDATA 0x20 -#define ISAR_HIS_DPS1 0x40 -#define ISAR_HIS_DPS2 0x80 -#define SET_DPS(x) ((x<<6) & 0xc0) - -#define ISAR_IIS_MSCMSD 0x3f -#define ISAR_IIS_VNR 0x15 -#define ISAR_IIS_DKEY 0x03 -#define ISAR_IIS_FIRM 0x1f -#define ISAR_IIS_STDSP 0x09 -#define ISAR_IIS_DIAG 0x25 -#define ISAR_IIS_GSTEV 0x0 -#define ISAR_IIS_BSTEV 0x28 -#define ISAR_IIS_BSTRSP 0x2c -#define ISAR_IIS_PSTRSP 0x2e -#define ISAR_IIS_PSTEV 0x2a +#define ISAR_HIS_BSTREQ 0x0c +#define ISAR_HIS_PSTREQ 0x0e +#define ISAR_HIS_SDATA 0x20 +#define ISAR_HIS_DPS1 0x40 +#define ISAR_HIS_DPS2 0x80 +#define SET_DPS(x) ((x<<6) & 0xc0) + +#define ISAR_IIS_MSCMSD 0x3f +#define ISAR_IIS_VNR 0x15 +#define ISAR_IIS_DKEY 0x03 +#define ISAR_IIS_FIRM 0x1f +#define ISAR_IIS_STDSP 0x09 +#define ISAR_IIS_DIAG 0x25 +#define ISAR_IIS_GSTEV 0x00 +#define ISAR_IIS_BSTEV 0x28 +#define ISAR_IIS_BSTRSP 0x2c +#define ISAR_IIS_PSTRSP 0x2e +#define ISAR_IIS_PSTEV 0x2a #define ISAR_IIS_IOM2RSP 0x27 +#define ISAR_IIS_RDATA 0x20 +#define ISAR_IIS_INVMSG 0x3f -#define ISAR_IIS_RDATA 0x20 #define ISAR_CTRL_SWVER 0x10 #define ISAR_CTRL_STST 0x40 @@ -93,30 +98,33 @@ #define PV32P2_V21 0x02 #define PV32P2_BEL 0x01 +// LSB MSB in ISAR doc wrong !!! Arghhh #define PV32P3_AMOD 0x80 #define PV32P3_V32B 0x02 -#define PV32P4_48 0x05 -#define PV32P5_48 0x11 -#define PV32P4_UT48 0x0d -#define PV32P5_UT48 0x11 -#define PV32P4_96 0x03 -#define PV32P5_96 0x11 -#define PV32P4_UT96 0x0f -#define PV32P5_UT96 0x11 -#define PV32P4_B96 0x0b -#define PV32P5_B96 0x91 -#define PV32P4_UTB96 0x0f -#define PV32P5_UTB96 0xd1 -#define PV32P4_120 0x09 -#define PV32P5_120 0xb1 -#define PV32P4_UT120 0x0f -#define PV32P5_UT120 0xf1 -#define PV32P4_144 0x09 -#define PV32P5_144 0x99 -#define PV32P4_UT144 0x0f -#define PV32P5_UT144 0xf9 +#define PV32P3_V23B 0x01 +#define PV32P4_48 0x11 +#define PV32P5_48 0x05 +#define PV32P4_UT48 0x11 +#define PV32P5_UT48 0x0d +#define PV32P4_96 0x11 +#define PV32P5_96 0x03 +#define PV32P4_UT96 0x11 +#define PV32P5_UT96 0x0f +#define PV32P4_B96 0x91 +#define PV32P5_B96 0x0b +#define PV32P4_UTB96 0xd1 +#define PV32P5_UTB96 0x0f +#define PV32P4_120 0xb1 +#define PV32P5_120 0x09 +#define PV32P4_UT120 0xf1 +#define PV32P5_UT120 0x0f +#define PV32P4_144 0x99 +#define PV32P5_144 0x09 +#define PV32P4_UT144 0xf9 +#define PV32P5_UT144 0x0f #define PV32P6_CTN 0x01 #define PV32P6_ATN 0x02 + #define PFAXP2_CTN 0x01 #define PFAXP2_ATN 0x04 @@ -156,7 +164,7 @@ #define S_P1_CHS_6 0x01 #define S_P1_CHS_5 0x00 -#define S_P2_BFT_DEF 30 +#define S_P2_BFT_DEF 0x10 #define IOM_CTRL_ENA 0x80 #define IOM_CTRL_NOPCM 0x00 @@ -170,15 +178,15 @@ #define HDLC_FSD 0x20 #define HDLC_FST 0x20 #define HDLC_ERROR 0x1c +#define SART_NMD 0x01 #define BSTAT_RDM0 0x1 #define BSTAT_RDM1 0x2 #define BSTAT_RDM2 0x4 #define BSTAT_RDM3 0x8 - extern int ISARVersion(struct IsdnCardState *cs, char *s); -extern int isar_load_firmware(struct IsdnCardState *cs, u_char *buf); extern void isar_int_main(struct IsdnCardState *cs); extern void initisar(struct IsdnCardState *cs); extern void isar_fill_fifo(struct BCState *bcs); +extern int isar_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic); diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c index 9ed3106727cb..c819c4811b58 100644 --- a/drivers/isdn/hisax/isdnl1.c +++ b/drivers/isdn/hisax/isdnl1.c @@ -1,4 +1,4 @@ -/* $Id: isdnl1.c,v 2.34 1999/07/09 13:50:15 keil Exp $ +/* $Id: isdnl1.c,v 2.36 1999/08/25 16:50:57 keil Exp $ * isdnl1.c common low level stuff for Siemens Chipsetbased isdn cards * based on the teles driver from Jan den Ouden @@ -15,6 +15,15 @@ * * * $Log: isdnl1.c,v $ + * Revision 2.36 1999/08/25 16:50:57 keil + * Fix bugs which cause 2.3.14 hangs (waitqueue init) + * + * Revision 2.35 1999/08/22 20:27:07 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 2.34 1999/07/09 13:50:15 keil * remove unused variable * @@ -129,7 +138,7 @@ * */ -const char *l1_revision = "$Revision: 2.34 $"; +const char *l1_revision = "$Revision: 2.36 $"; #define __NO_VERSION__ #include "hisax.h" @@ -390,7 +399,7 @@ BChannel_proc_rcv(struct BCState *bcs) } } -static void +void BChannel_bh(struct BCState *bcs) { if (!bcs) diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c index 24d468da2528..ca721ea864b5 100644 --- a/drivers/isdn/hisax/isdnl2.c +++ b/drivers/isdn/hisax/isdnl2.c @@ -1,4 +1,4 @@ -/* $Id: isdnl2.c,v 2.19 1999/08/05 20:40:26 keil Exp $ +/* $Id: isdnl2.c,v 2.20 1999/08/25 16:52:04 keil Exp $ * Author Karsten Keil (keil@isdn4linux.de) * based on the teles driver from Jan den Ouden @@ -11,6 +11,9 @@ * Fritz Elfert * * $Log: isdnl2.c,v $ + * Revision 2.20 1999/08/25 16:52:04 keil + * Make gcc on AXP happy + * * Revision 2.19 1999/08/05 20:40:26 keil * Fix interlayer communication * @@ -80,7 +83,7 @@ #include "hisax.h" #include "isdnl2.h" -const char *l2_revision = "$Revision: 2.19 $"; +const char *l2_revision = "$Revision: 2.20 $"; static void l2m_debug(struct FsmInst *fi, char *fmt, ...); @@ -1747,7 +1750,7 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg) } if(c) { FreeSkb(skb); - FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) c); + FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *)(long)c); ret = 0; } if (ret) diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c index a81bf07605e2..22e54fd8e92a 100644 --- a/drivers/isdn/hisax/isurf.c +++ b/drivers/isdn/hisax/isurf.c @@ -1,10 +1,20 @@ -/* $Id: isurf.c,v 1.3 1999/07/12 21:05:18 keil Exp $ +/* $Id: isurf.c,v 1.5 1999/08/25 17:00:02 keil Exp $ * isurf.c low level stuff for Siemens I-Surf/I-Talk cards * * Author Karsten Keil (keil@isdn4linux.de) * * $Log: isurf.c,v $ + * Revision 1.5 1999/08/25 17:00:02 keil + * Make ISAR V32bis modem running + * Make LL->HL interface open for additional commands + * + * Revision 1.4 1999/08/22 20:27:09 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.3 1999/07/12 21:05:18 keil * fix race in IRQ handling * added watchdog for lost IRQs @@ -24,7 +34,7 @@ extern const char *CardType[]; -static const char *ISurf_revision = "$Revision: 1.3 $"; +static const char *ISurf_revision = "$Revision: 1.5 $"; #define byteout(addr,val) outb(val,addr) #define bytein(addr) inb(addr) @@ -174,18 +184,26 @@ ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); case CARD_TEST: return(0); - case CARD_LOAD_FIRM: - if (isar_load_firmware(cs, arg)) - return(1); - ll_run(cs); + } + return(0); +} + +static int +isurf_auxcmd(struct IsdnCardState *cs, isdn_ctrl *ic) { + int ret; + + if ((ic->command == ISDN_CMD_IOCTL) && (ic->arg == 9)) { + ret = isar_auxcmd(cs, ic); + if (!ret) { reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET); initisac(cs); cs->writeisac(cs, ISAC_MASK, 0); cs->writeisac(cs, ISAC_CMDR, 0x41); - return(0); + } + return(ret); } - return(0); + return(isar_auxcmd(cs, ic)); } __initfunc(int @@ -228,6 +246,7 @@ setup_isurf(struct IsdnCard *card)) cs->cardmsg = &ISurf_card_msg; cs->irq_func = &isurf_interrupt; + cs->auxcmd = &isurf_auxcmd; cs->readisac = &ReadISAC; cs->writeisac = &WriteISAC; cs->readisacfifo = &ReadISACfifo; diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index 1c541033f0fd..22a5de9fa7ba 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -1,4 +1,4 @@ -/* $Id: l3dss1.c,v 2.18 1999/08/11 20:54:39 keil Exp $ +/* $Id: l3dss1.c,v 2.19 1999/08/25 16:55:23 keil Exp $ * EURO/DSS1 D-channel protocol * @@ -13,6 +13,9 @@ * Fritz Elfert * * $Log: l3dss1.c,v $ + * Revision 2.19 1999/08/25 16:55:23 keil + * Fix for test case TC10011 + * * Revision 2.18 1999/08/11 20:54:39 keil * High layer compatibility is valid in SETUP * @@ -87,7 +90,7 @@ #include extern char *HiSax_getrev(const char *revision); -const char *dss1_revision = "$Revision: 2.18 $"; +const char *dss1_revision = "$Revision: 2.19 $"; #define EXT_BEARER_CAPS 1 @@ -764,11 +767,6 @@ ie_in_set(struct l3_process *pc, u_char ie, int *checklist) { int ret = 1; while (*checklist != -1) { -#if 0 - if (pc->debug & L3_DEB_CHECK) - l3_debug(pc->st, "ie_in_set ie(%x) cl(%x)", - ie, *checklist); -#endif if ((*checklist & 0xff) == ie) { if (ie & 0x80) return(-ret); @@ -1737,15 +1735,12 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) return; } /* Now we are on none mandatory IEs */ -#if 1 -/* !!!!!! this check seems to be a problem ? info bugfix to Karsten */ err = check_infoelements(pc, skb, ie_SETUP); if (ERR_IE_COMPREHENSION == err) { pc->para.cause = 96; l3dss1_msg_without_setup(pc, pr, NULL); return; } -#endif p = skb->data; if ((p = findie(p, skb->len, 0x70, 0))) iecpy(pc->para.setup.eazmsn, p, 1); @@ -1787,29 +1782,10 @@ l3dss1_setup(struct l3_process *pc, u_char pr, void *arg) } else if (pc->debug & L3_DEB_WARN) l3_debug(pc->st, "wrong calling subaddress"); } - -#if 0 - if (bcfound) { - if ((pc->para.setup.si1 != 7) && (pc->debug & L3_DEB_WARN)) { - l3_debug(pc->st, "non-digital call: %s -> %s", - pc->para.setup.phone, pc->para.setup.eazmsn); - } - if ((pc->para.setup.si1 != 7) && - test_bit(FLG_PTP, &pc->st->l2.flag)) { - pc->para.cause = 88; /* incompatible destination */ - l3dss1_msg_without_setup(pc, pr, NULL); - return; - } - newl3state(pc, 6); - pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); - } else - dss1_release_l3_process(pc); -#else newl3state(pc, 6); if (err) /* STATUS for none mandatory IE errors after actions are taken */ l3dss1_std_ie_err(pc, err); pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); -#endif } static void @@ -2106,8 +2082,6 @@ l3dss1_status_enq(struct l3_process *pc, u_char pr, void *arg) ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY); l3dss1_std_ie_err(pc, ret); -// KKe 19.7.99 test eicon -// idev_kfree_skb(skb, FREE_READ); pc->para.cause = 30; /* response to STATUS_ENQUIRY */ l3dss1_status_send(pc, pr, NULL); } @@ -2862,7 +2836,8 @@ static struct stateentry datastatelist[] = MT_STATUS, l3dss1_status}, {SBIT(0), MT_SETUP, l3dss1_setup}, - {SBIT(6) | SBIT(7), + {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | + SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), MT_SETUP, l3dss1_dummy}, {SBIT(1) | SBIT(2), MT_CALL_PROCEEDING, l3dss1_call_proc}, @@ -2885,8 +2860,6 @@ static struct stateentry datastatelist[] = {SBIT(19), MT_RELEASE, l3dss1_release_ind}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25), MT_DISCONNECT, l3dss1_disconnect}, -// {SBIT(11), -// MT_DISCONNECT, l3dss1_release_req}, {SBIT(19), MT_DISCONNECT, l3dss1_dummy}, {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), diff --git a/drivers/isdn/hisax/md5sums.asc b/drivers/isdn/hisax/md5sums.asc index 7fe2bbbae56e..481a7dc720ea 100644 --- a/drivers/isdn/hisax/md5sums.asc +++ b/drivers/isdn/hisax/md5sums.asc @@ -6,16 +6,16 @@ # Eicon Technology Diva 2.01 PCI cards in the moment. # Read ../../../Documentation/isdn/HiSax.cert for more informations. # -d93f31e02c1b153ec04d16f69e5688b3 isac.c -e2a78c07f32c8ca7c88fc9f92a87dfab isdnl1.c -54490c4f46a998ff4ef34287bc262185 isdnl2.c +0cc164fadd4ec0e2983ec9735e209cbd isac.c +5fe8cb5526c78c91f61b0a94a423ea5d isdnl1.c +3b9522e8bf9e1c3e7848d729fc3dc05d isdnl2.c f4184a50e35e5b568608e6cb7a693319 isdnl3.c ef70f4269fdc2ca15100f9b776afaa0d tei.c -cf3923304983e9d64cf35bc5a3533f6c callc.c +65be616dd9d0e06c788d4fdd0fe5fe0a callc.c bf9605b36429898f7be6630034e83230 cert.c -309261e4c36d950db6978440e8bc8342 l3dss1.c +97c5e31c2739665b9c2976a30ce0b357 l3dss1.c b674eee9314a7cc413971c84003cf1d2 l3_1tr6.c -8f86d92f43ecc42f6457773168cfc114 elsa.c +51b2ef1efb221bb09fd08ab28bd2c565 elsa.c 24cda374da44b57f6a1bb215424267b5 diva.c # end of md5sums @@ -23,9 +23,9 @@ b674eee9314a7cc413971c84003cf1d2 l3_1tr6.c Version: 2.6.3i Charset: noconv -iQCVAwUBN7HnvDpxHvX/mS9tAQFANgP+LGuG98lvCv97vN2dc6T/6hZTxFW+WirJ -XMhU5NHoZ+8MISMOVKB7ugsGO9cJI0lUA0sOe8jtPCo5070nF1ZkNsxV/x7WK2dS -RwXfHy6+TAH7qIiBnkP9odB2lib+VFl/nnkkTwsXfVwRCD8bLaagMPv+nAveDoNE -uff0xxXEnJw= -=Wu2M +iQCVAwUBN8RgFjpxHvX/mS9tAQFzFQP/dOgnppDIm5ug1hnlWjQ/0BVurKEEJ64r +DYDHwkcog+0gVE/EB1A7WUDqpFEnj52OZeoVinCfdVuVjP8IkrAJ8dCONsnXjBXz +pzM+FunP1LFxuv2TVM0f642j98JxS8rObGWH8ZwY36P2QfNp47zorO2F9WvdCkuz +sxJUtMUOlQ8= +=8uEP -----END PGP SIGNATURE----- diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c index 25303b6e942b..3251aa9fe51a 100644 --- a/drivers/isdn/hisax/sedlbauer.c +++ b/drivers/isdn/hisax/sedlbauer.c @@ -1,4 +1,4 @@ -/* $Id: sedlbauer.c,v 1.14 1999/08/11 20:59:22 keil Exp $ +/* $Id: sedlbauer.c,v 1.15 1999/08/25 17:00:00 keil Exp $ * sedlbauer.c low level stuff for Sedlbauer cards * includes support for the Sedlbauer speed star (speed star II), @@ -17,6 +17,10 @@ * Edgar Toernig * * $Log: sedlbauer.c,v $ + * Revision 1.15 1999/08/25 17:00:00 keil + * Make ISAR V32bis modem running + * Make LL->HL interface open for additional commands + * * Revision 1.14 1999/08/11 20:59:22 keil * new PCI codefix * fix IRQ problem while unload @@ -99,7 +103,7 @@ extern const char *CardType[]; -const char *Sedlbauer_revision = "$Revision: 1.14 $"; +const char *Sedlbauer_revision = "$Revision: 1.15 $"; const char *Sedlbauer_Types[] = {"None", "speed card/win", "speed star", "speed fax+", @@ -530,19 +534,10 @@ Sedl_card_msg(struct IsdnCardState *cs, int mt, void *arg) return(0); case CARD_TEST: return(0); - case CARD_LOAD_FIRM: - if (cs->hw.sedl.chip == SEDL_CHIP_ISAC_ISAR) { - if (isar_load_firmware(cs, arg)) - return(1); - else - ll_run(cs); - } - return(0); } return(0); } - #ifdef SEDLBAUER_PCI #ifdef COMPAT_HAS_NEW_PCI static struct pci_dev *dev_sedl __initdata = NULL; @@ -743,7 +738,7 @@ setup_sedlbauer(struct IsdnCard *card)) cs->bcs[1].hw.isar.reg = &cs->hw.sedl.isar; test_and_set_bit(HW_ISAR, &cs->HW_Flags); cs->irq_func = &sedlbauer_interrupt_isar; - + cs->auxcmd = &isar_auxcmd; ISACVersion(cs, "Sedlbauer:"); cs->BC_Read_Reg = &ReadISAR; diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c index 0768ec0fce56..2d7b0413a7c7 100644 --- a/drivers/isdn/icn/icn.c +++ b/drivers/isdn/icn/icn.c @@ -1,4 +1,4 @@ -/* $Id: icn.c,v 1.57 1999/07/06 16:15:30 detabc Exp $ +/* $Id: icn.c,v 1.58 1999/08/25 16:44:17 keil Exp $ * ISDN low-level module for the ICN active ISDN-Card. * @@ -19,6 +19,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: icn.c,v $ + * Revision 1.58 1999/08/25 16:44:17 keil + * Support for new __setup function + * * Revision 1.57 1999/07/06 16:15:30 detabc * remove unused messages * @@ -232,7 +235,7 @@ #undef MAP_DEBUG static char -*revision = "$Revision: 1.57 $"; +*revision = "$Revision: 1.58 $"; static int icn_addcard(int, char *, char *); @@ -1846,13 +1849,25 @@ icn_addcard(int port, char *id1, char *id2) #ifdef MODULE #define icn_init init_module #else +#ifdef COMPAT_HAS_NEW_SETUP +#include +int +icn_setup(char *line) +{ + char *p, *str; + int ints[3]; + static char sid[20]; + static char sid2[20]; + + str = get_options(line, 2, ints); +#else void icn_setup(char *str, int *ints) { char *p; static char sid[20]; static char sid2[20]; - +#endif if (ints[0]) portbase = ints[1]; if (ints[0] > 1) @@ -1866,8 +1881,14 @@ icn_setup(char *str, int *ints) icn_id2 = sid2; } } +#ifdef COMPAT_HAS_NEW_SETUP + return(1); +} +__setup("icn=", icn_setup); +#else } #endif +#endif /* MODULES */ int icn_init(void) diff --git a/drivers/isdn/isdn_audio.c b/drivers/isdn/isdn_audio.c index a6f13ef76432..3599d2ada109 100644 --- a/drivers/isdn/isdn_audio.c +++ b/drivers/isdn/isdn_audio.c @@ -1,4 +1,4 @@ -/* $Id: isdn_audio.c,v 1.16 1999/08/06 12:47:35 calle Exp $ +/* $Id: isdn_audio.c,v 1.17 1999/08/17 11:10:52 paul Exp $ * Linux ISDN subsystem, audio conversion and compression (linklevel). * @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_audio.c,v $ + * Revision 1.17 1999/08/17 11:10:52 paul + * don't try to use x86 assembler on non-x86! + * * Revision 1.16 1999/08/06 12:47:35 calle * Using __GNUC__ == 2 && __GNUC_MINOR__ < 95 how to define * ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT @@ -92,7 +95,7 @@ #include "isdn_audio.h" #include "isdn_common.h" -char *isdn_audio_revision = "$Revision: 1.16 $"; +char *isdn_audio_revision = "$Revision: 1.17 $"; /* * Misc. lookup-tables. @@ -294,7 +297,7 @@ static char dtmf_matrix[4][4] = * egcs 2.95 complain about invalid asm statement: * "fixed or forbidden register 2 (cx) was spilled for class CREG." */ -#if ((CPU == 386) || (CPU == 486) || (CPU == 586)) || defined(__GNUC__) +#if ((CPU == 386) || (CPU == 486) || (CPU == 586)) && defined(__GNUC__) #if __GNUC__ == 2 && __GNUC_MINOR__ < 95 #define ISDN_AUDIO_OPTIMIZE_ON_X386_WITH_ASM_IF_GCC_ALLOW_IT #endif diff --git a/drivers/isdn/isdn_concap.c b/drivers/isdn/isdn_concap.c index 698fd34ff5fe..ca05f8bf315b 100644 --- a/drivers/isdn/isdn_concap.c +++ b/drivers/isdn/isdn_concap.c @@ -1,10 +1,16 @@ -/* $Id: isdn_concap.c,v 1.5 1998/10/30 18:44:48 he Exp $ +/* $Id: isdn_concap.c,v 1.6 1999/08/22 20:26:01 calle Exp $ * Stuff to support the concap_proto by isdn4linux. isdn4linux - specific * stuff goes here. Stuff that depends only on the concap protocol goes to * another -- protocol specific -- source file. * * $Log: isdn_concap.c,v $ + * Revision 1.6 1999/08/22 20:26:01 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.5 1998/10/30 18:44:48 he * pass return value from isdn_net_dial_req for dialmode change * diff --git a/drivers/isdn/isdn_net.c b/drivers/isdn/isdn_net.c index 1cda52f6d9ed..9d54f01274e8 100644 --- a/drivers/isdn/isdn_net.c +++ b/drivers/isdn/isdn_net.c @@ -1,4 +1,4 @@ -/* $Id: isdn_net.c,v 1.88 1999/07/07 10:13:31 detabc Exp $ +/* $Id: isdn_net.c,v 1.89 1999/08/22 20:26:03 calle Exp $ * Linux ISDN subsystem, network interfaces and related functions (linklevel). * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.c,v $ + * Revision 1.89 1999/08/22 20:26:03 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.88 1999/07/07 10:13:31 detabc * remove unused messages * @@ -360,7 +366,7 @@ int isdn_net_force_dial_lp(isdn_net_local *); static int isdn_net_start_xmit(struct sk_buff *, struct net_device *); static int isdn_net_xmit(struct net_device *, isdn_net_local *, struct sk_buff *); -char *isdn_net_revision = "$Revision: 1.88 $"; +char *isdn_net_revision = "$Revision: 1.89 $"; /* * Code for raw-networking over ISDN diff --git a/drivers/isdn/isdn_net.h b/drivers/isdn/isdn_net.h index c8ef6e0722c0..bd48c592c410 100644 --- a/drivers/isdn/isdn_net.h +++ b/drivers/isdn/isdn_net.h @@ -1,4 +1,4 @@ -/* $Id: isdn_net.h,v 1.9 1999/04/12 12:33:27 fritz Exp $ +/* $Id: isdn_net.h,v 1.10 1999/08/22 20:26:06 calle Exp $ * header for Linux ISDN subsystem, network related functions (linklevel). * @@ -21,6 +21,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_net.h,v $ + * Revision 1.10 1999/08/22 20:26:06 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.9 1999/04/12 12:33:27 fritz * Changes from 2.0 tree. * diff --git a/drivers/isdn/isdn_ppp.c b/drivers/isdn/isdn_ppp.c index e8ba71771f7f..78c71c7fe488 100644 --- a/drivers/isdn/isdn_ppp.c +++ b/drivers/isdn/isdn_ppp.c @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.c,v 1.49 1999/07/06 07:47:11 calle Exp $ +/* $Id: isdn_ppp.c,v 1.52 1999/08/22 20:26:07 calle Exp $ * * Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,18 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.c,v $ + * Revision 1.52 1999/08/22 20:26:07 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * + * Revision 1.51 1999/08/18 16:19:17 hipp + * applied MPPP-resize-headroom patch + * + * Revision 1.50 1999/08/16 07:11:41 hipp + * Additional VJ decomp-buffer-size increased from 40 to 128 + * * Revision 1.49 1999/07/06 07:47:11 calle * bugfix: dev_alloc_skb only reserve 16 bytes. We need to look at the * hdrlen the driver want. So I changed dev_alloc_skb calls @@ -269,7 +281,7 @@ static int isdn_ppp_fill_mpqueue(isdn_net_dev *, struct sk_buff **skb, static void isdn_ppp_free_mpqueue(isdn_net_dev *); #endif -char *isdn_ppp_revision = "$Revision: 1.49 $"; +char *isdn_ppp_revision = "$Revision: 1.52 $"; static struct ippp_struct *ippp_table[ISDN_MAX_CHANNELS]; static struct isdn_ppp_compressor *ipc_head = NULL; @@ -1352,7 +1364,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff { struct sk_buff *skb_old = skb; int pkt_len; - skb = dev_alloc_skb(skb_old->len + 40); + skb = dev_alloc_skb(skb_old->len + 128); if (!skb) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); @@ -1361,7 +1373,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff return; } skb->dev = dev; - skb_put(skb, skb_old->len + 40); + skb_put(skb, skb_old->len + 128); memcpy(skb->data, skb_old->data, skb_old->len); skb->mac.raw = skb->data; pkt_len = slhc_uncompress(ippp_table[net_dev->local->ppp_slot]->slcomp, @@ -1415,9 +1427,17 @@ static unsigned char *isdn_ppp_skb_push(struct sk_buff **skb_p,int len) struct sk_buff *skb = *skb_p; if(skb_headroom(skb) < len) { - printk(KERN_ERR "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len); + struct sk_buff *nskb = skb_realloc_headroom(skb, len); + + if (!nskb) { + printk(KERN_ERR "isdn_ppp_skb_push: can't realloc headroom!\n"); + dev_kfree_skb(skb); + return NULL; + } + printk(KERN_DEBUG "isdn_ppp_skb_push:under %d %d\n",skb_headroom(skb),len); dev_kfree_skb(skb); - return NULL; + *skb_p = nskb; + return skb_push(nskb, len); } return skb_push(skb,len); } diff --git a/drivers/isdn/isdn_ppp.h b/drivers/isdn/isdn_ppp.h index a24a8ce9efb6..1a1dcfcfe6e2 100644 --- a/drivers/isdn/isdn_ppp.h +++ b/drivers/isdn/isdn_ppp.h @@ -1,4 +1,4 @@ -/* $Id: isdn_ppp.h,v 1.13 1998/03/22 18:50:50 hipp Exp $ +/* $Id: isdn_ppp.h,v 1.14 1999/08/22 20:26:10 calle Exp $ * header for Linux ISDN subsystem, functions for synchronous PPP (linklevel). * @@ -19,6 +19,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ppp.h,v $ + * Revision 1.14 1999/08/22 20:26:10 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.13 1998/03/22 18:50:50 hipp * Added BSD Compression for syncPPP .. UNTESTED at the moment * diff --git a/drivers/isdn/isdn_tty.h b/drivers/isdn/isdn_tty.h index 62e723eafbed..87acd7be2fd3 100644 --- a/drivers/isdn/isdn_tty.h +++ b/drivers/isdn/isdn_tty.h @@ -1,4 +1,4 @@ -/* $Id: isdn_tty.h,v 1.15 1999/07/31 12:59:48 armin Exp $ +/* $Id: isdn_tty.h,v 1.16 1999/08/22 20:26:10 calle Exp $ * header for Linux ISDN subsystem, tty related functions (linklevel). * @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_tty.h,v $ + * Revision 1.16 1999/08/22 20:26:10 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.15 1999/07/31 12:59:48 armin * Added tty fax capabilities. * diff --git a/drivers/isdn/isdn_ttyfax.c b/drivers/isdn/isdn_ttyfax.c index cc7c14fc6a6d..7665aa812c26 100644 --- a/drivers/isdn/isdn_ttyfax.c +++ b/drivers/isdn/isdn_ttyfax.c @@ -1,4 +1,4 @@ -/* $Id: isdn_ttyfax.c,v 1.2 1999/08/05 10:36:10 armin Exp $ +/* $Id: isdn_ttyfax.c,v 1.3 1999/08/22 20:26:12 calle Exp $ * Linux ISDN subsystem, tty_fax AT-command emulator (linklevel). * * Copyright 1999 by Armin Schindler (mac@melware.de) @@ -20,6 +20,12 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn_ttyfax.c,v $ + * Revision 1.3 1999/08/22 20:26:12 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.2 1999/08/05 10:36:10 armin * Bugfix: kernel oops on getting revision. * @@ -40,7 +46,7 @@ #include "isdn_ttyfax.h" -static char *isdn_tty_fax_revision = "$Revision: 1.2 $"; +static char *isdn_tty_fax_revision = "$Revision: 1.3 $"; #define PARSE_ERROR1 { isdn_tty_fax_modem_result(1, info); return 1; } diff --git a/drivers/isdn/isdn_x25iface.c b/drivers/isdn/isdn_x25iface.c index 63f7c521f119..9a50748015c5 100644 --- a/drivers/isdn/isdn_x25iface.c +++ b/drivers/isdn/isdn_x25iface.c @@ -1,4 +1,4 @@ -/* $Id: isdn_x25iface.c,v 1.6 1999/01/27 22:53:19 he Exp $ +/* $Id: isdn_x25iface.c,v 1.7 1999/08/22 20:26:13 calle Exp $ * stuff needed to support the Linux X.25 PLP code on top of devices that * can provide a lab_b service using the concap_proto mechanism. * This module supports a network interface wich provides lapb_sematics @@ -10,6 +10,12 @@ * goes to another -- device related -- concap_proto support source file. * * $Log: isdn_x25iface.c,v $ + * Revision 1.7 1999/08/22 20:26:13 calle + * backported changes from kernel 2.3.14: + * - several #include "config.h" gone, others come. + * - "struct device" changed to "struct net_device" in 2.3.14, added a + * define in isdn_compat.h for older kernel versions. + * * Revision 1.6 1999/01/27 22:53:19 he * minor updates (spellings, jiffies wrap around in isdn_tty) * diff --git a/drivers/isdn/pcbit/module.c b/drivers/isdn/pcbit/module.c index 33aee3360eb3..ae4abb590d49 100644 --- a/drivers/isdn/pcbit/module.c +++ b/drivers/isdn/pcbit/module.c @@ -102,10 +102,21 @@ void cleanup_module(void) } #else -void pcbit_setup(char *str, int *ints) +#ifdef COMPAT_HAS_NEW_SETUP +#define MAX_PARA (MAX_PCBIT_CARDS * 2) +#include +int pcbit_setup(char *line) { int i, j, argc; + char *str; + int ints[MAX_PARA+1]; + str = get_options(line, MAX_PARA, ints); +#else +void pcbit_setup(char *str, int *ints) +{ + int i, j, argc; +#endif argc = ints[0]; i = 0; j = 1; @@ -124,8 +135,14 @@ void pcbit_setup(char *str, int *ints) i++; } +#ifdef COMPAT_HAS_NEW_SETUP + return(1); +} +__setup("pcbit=", pcbit_setup); +#else } #endif +#endif diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index eb46520e95fb..0c4cd584676a 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -313,7 +313,7 @@ ppp_async_ioctl(struct tty_struct *tty, struct file *file, switch (cmd) { case PPPIOCGFLAGS: val = ap->flags | ap->rbits; - if (put_user(ap->flags, (int *) arg)) + if (put_user(val, (int *) arg)) break; err = 0; break; diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index 26839d47cb0a..346830ec6541 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -34,7 +34,6 @@ static char version[] = "sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)\n"; -#include #include #include diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c index cdee2d6e6886..c112489584a0 100644 --- a/drivers/net/sk_mca.c +++ b/drivers/net/sk_mca.c @@ -71,7 +71,6 @@ History: #include #include -#include #include #include #include diff --git a/drivers/pci/names.c b/drivers/pci/names.c index eb5ff58f49bb..d16940e03190 100644 --- a/drivers/pci/names.c +++ b/drivers/pci/names.c @@ -57,8 +57,6 @@ void __init pci_name_device(struct pci_dev *dev) int i = VENDORS; char *name = dev->name; - name += sprintf(name, "PCI<%02x:%02x.%d>", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - do { if (vendor_p->vendor == dev->vendor) goto match_vendor; @@ -66,7 +64,7 @@ void __init pci_name_device(struct pci_dev *dev) } while (--i); /* Couldn't find either the vendor nor the device */ - sprintf(name, " %04x:%04x", dev->vendor, dev->device); + sprintf(name, "PCI device %04x:%04x", dev->vendor, dev->device); return; match_vendor: { @@ -81,7 +79,7 @@ void __init pci_name_device(struct pci_dev *dev) } /* Ok, found the vendor, but unknown device */ - sprintf(name, " %04x:%04x (%s)", dev->vendor, dev->device, vendor_p->name); + sprintf(name, " PCI device %04x:%04x (%s)", dev->vendor, dev->device, vendor_p->name); return; /* Full match */ diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 25b78e15f3a5..d8ab783b4213 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -274,11 +274,7 @@ static unsigned int __init pci_do_scan_bus(struct pci_bus *bus) dev_cache = NULL; dev->vendor = l & 0xffff; dev->device = (l >> 16) & 0xffff; -#ifdef CONFIG_PCI_NO_NAMES - sprintf(dev->name, "pci:%02x:%02x.%d", bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn)); -#else pci_name_device(dev); -#endif /* non-destructively determine if device can be a master: */ pci_read_config_byte(dev, PCI_COMMAND, &cmd); diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 724d431a0311..3ff88302e946 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -12,7 +12,6 @@ * use the PowerTweak utility (see http://linux.powertweak.com/). */ -#include #include #include #include diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 762572e45d96..e5c36cd8893d 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -127,7 +127,6 @@ #define MEGARAID_VERSION "v1.04 (August 16, 1999)" -#include #include #ifdef MODULE diff --git a/drivers/sound/esssolo1.c b/drivers/sound/esssolo1.c index 452df756cf68..4189dc37c2fa 100644 --- a/drivers/sound/esssolo1.c +++ b/drivers/sound/esssolo1.c @@ -59,7 +59,6 @@ /*****************************************************************************/ -#include #include #include #include diff --git a/drivers/sound/vwsnd.c b/drivers/sound/vwsnd.c index 664f38bdba98..ef2cf7f366ea 100644 --- a/drivers/sound/vwsnd.c +++ b/drivers/sound/vwsnd.c @@ -138,7 +138,6 @@ * This happens in pcm_copy_{in,out}(). */ -#include #include #include #include diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in index 636eda6fbc82..1df611294023 100644 --- a/drivers/usb/Config.in +++ b/drivers/usb/Config.in @@ -24,6 +24,8 @@ if [ ! "$CONFIG_USB" = "n" ]; then bool ' OHCI-HCD Virtual Root Hub' CONFIG_USB_OHCI_VROOTHUB fi + bool 'Enable lots of ISOC debugging output' CONFIG_USB_DEBUG_ISOC + dep_tristate 'USB hub support' CONFIG_USB_HUB $CONFIG_USB dep_tristate 'USB mouse support' CONFIG_USB_MOUSE $CONFIG_USB dep_tristate 'USB keyboard support' CONFIG_USB_KBD $CONFIG_USB diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index c65dd0647186..f2a98c3b3c79 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -18,14 +18,14 @@ L_OBJS := MOD_LIST_NAME := USB_MODULES ifeq ($(CONFIG_USB),y) - L_OBJS +=usbcore.o + L_OBJS += usbcore.o ifeq ($(CONFIG_USB_PROC),y) L_OBJS += proc_usb.o endif endif ifeq ($(CONFIG_USB),m) - M_OBJS +=usbcore.o - MIX_OBJS +=usb.o usb-debug.o usb-core.o + M_OBJS += usbcore.o + MIX_OBJS += usb.o usb-debug.o usb-core.o ifeq ($(CONFIG_USB_PROC),y) MIX_OBJS += proc_usb.o endif @@ -60,16 +60,16 @@ ifeq ($(CONFIG_USB_MOUSE),y) L_OBJS += mouse.o endif ifeq ($(CONFIG_USB_MOUSE),m) - M_OBJS +=mouse.o - MIX_OBJS +=mouse.o + M_OBJS += mouse.o + MIX_OBJS += mouse.o endif ifeq ($(CONFIG_USB_HUB),y) L_OBJS += hub.o endif ifeq ($(CONFIG_USB_HUB),m) - M_OBJS +=hub.o - MIX_OBJS +=hub.o + M_OBJS += hub.o + MIX_OBJS += hub.o endif ifeq ($(CONFIG_USB_ACM),y) @@ -77,7 +77,7 @@ ifeq ($(CONFIG_USB_ACM),y) endif ifeq ($(CONFIG_USB_ACM),m) M_OBJS += acm.o - MIX_OBJS +=acm.o + MIX_OBJS += acm.o endif ifeq ($(CONFIG_USB_PRINTER),y) @@ -89,15 +89,6 @@ ifeq ($(CONFIG_USB_PRINTER),m) MIX_OBJS += printer.o endif -ifeq ($(CONFIG_USB_CPIA),y) - L_OBJS += cpia.o -endif - -ifeq ($(CONFIG_USB_CPIA),m) - M_OBJS += cpia.o - MIX_OBJS += cpia.o -endif - ifeq ($(CONFIG_USB_KBD),y) L_OBJS += keyboard.o keymap.o endif diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c index db61c2ea801c..fb18b5cf9521 100644 --- a/drivers/usb/acm.c +++ b/drivers/usb/acm.c @@ -468,15 +468,15 @@ static void rs_unthrottle(struct tty_struct * tty) Set_Control_Line_Status (acm->ctrlstate | CTRL_STAT_RTS, acm); } -static int get_free_acm() +static int get_free_acm(void) { - int i; + int i; - for (i=0;idescriptor.bDeviceProtocol != 0) return -1; - /*Now scan all configs for a ACM configuration*/ + /* Now scan all configs for a ACM configuration */ for (cfgnum=0;cfgnumdescriptor.bNumConfigurations;cfgnum++) { /* The first one should be Communications interface? */ - interface = &dev->config[cfgnum].altsetting[0].interface[0]; + interface = &dev->config[cfgnum].interface[0].altsetting[0]; if (interface->bInterfaceClass != 2 || interface->bInterfaceSubClass != 2 || interface->bInterfaceProtocol != 1 || @@ -517,7 +517,7 @@ static int acm_probe(struct usb_device *dev) continue; /* The second one should be a Data interface? */ - interface = &dev->config[cfgnum].altsetting[0].interface[1]; + interface = &dev->config[cfgnum].interface[1].altsetting[0]; if (interface->bInterfaceClass != 10 || interface->bInterfaceSubClass != 0 || interface->bInterfaceProtocol != 0 || @@ -542,18 +542,18 @@ static int acm_probe(struct usb_device *dev) acm->dev=dev; dev->private=acm; - acm->readendp=dev->config[cfgnum].altsetting[0].interface[1].endpoint[0].bEndpointAddress; + acm->readendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[0].bEndpointAddress; acm->readpipe=usb_rcvbulkpipe(dev,acm->readendp); - acm->readbuffer=kmalloc(acm->readsize=dev->config[cfgnum].altsetting[0].interface[1].endpoint[0].wMaxPacketSize,GFP_KERNEL); + acm->readbuffer=kmalloc(acm->readsize=dev->config[cfgnum].interface[1].altsetting[0].endpoint[0].wMaxPacketSize,GFP_KERNEL); acm->reading=0; if (!acm->readbuffer) { printk("ACM: Couldn't allocate readbuffer\n"); return -1; } - acm->writeendp=dev->config[cfgnum].altsetting[0].interface[1].endpoint[1].bEndpointAddress; + acm->writeendp=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1].bEndpointAddress; acm->writepipe=usb_sndbulkpipe(dev,acm->writeendp); - acm->writebuffer=kmalloc(acm->writesize=dev->config[cfgnum].altsetting[0].interface[1].endpoint[1].wMaxPacketSize, GFP_KERNEL); + acm->writebuffer=kmalloc(acm->writesize=dev->config[cfgnum].interface[1].altsetting[0].endpoint[1].wMaxPacketSize, GFP_KERNEL); acm->writing=0; if (!acm->writebuffer) { printk("ACM: Couldn't allocate writebuffer\n"); @@ -561,11 +561,11 @@ static int acm_probe(struct usb_device *dev) return -1; } - acm->ctrlendp=dev->config[cfgnum].altsetting[0].interface[0].endpoint[0].bEndpointAddress; + acm->ctrlendp=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bEndpointAddress; acm->ctrlpipe=usb_rcvctrlpipe(acm->dev,acm->ctrlendp); - acm->ctrlinterval=dev->config[cfgnum].altsetting[0].interface[0].endpoint[0].bInterval; + acm->ctrlinterval=dev->config[cfgnum].interface[0].altsetting[0].endpoint[0].bInterval; - acm->present=1; + acm->present=1; MOD_INC_USE_COUNT; return 0; } @@ -699,4 +699,4 @@ void cleanup_module(void) { usb_acm_cleanup(); } -#endif \ No newline at end of file +#endif diff --git a/drivers/usb/audio.c b/drivers/usb/audio.c index 704ec051f503..cba0e774fc44 100644 --- a/drivers/usb/audio.c +++ b/drivers/usb/audio.c @@ -15,6 +15,8 @@ static LIST_HEAD(usb_audio_list); struct usb_audio { struct usb_device *dev; struct list_head list; + + void *irq_handle; }; static struct usb_driver usb_audio_driver = { @@ -25,42 +27,43 @@ static struct usb_driver usb_audio_driver = { }; +#if 0 static int usb_audio_irq(int state, void *buffer, int len, void *dev_id) { +#if 0 struct usb_audio *aud = (struct usb_audio *)dev_id; printk("irq on %p\n", aud); +#endif return 1; } +#endif static int usb_audio_probe(struct usb_device *dev) { - struct usb_interface_descriptor *intf_desc; - struct usb_endpoint_descriptor *endpoint; + struct usb_interface_descriptor *interface; struct usb_audio *aud; - int bEndpointAddress = 0; int i; int na=0; - for (i=0; iconfig[0].bNumInterfaces; i++) { - intf_desc = &dev->config->interface[i].altsetting[0]; + interface = &dev->config->interface[i].altsetting[0]; - if(intf_desc->bInterfaceClass != 1) + if (interface->bInterfaceClass != 1) continue; printk(KERN_INFO "USB audio device detected.\n"); - switch(intf_desc->bInterfaceSubClass) { + switch(interface->bInterfaceSubClass) { case 0x01: - printk(KERN_INFO "audio: Control device.\n"); + printk(KERN_INFO "audio: control device\n"); break; case 0x02: - printk(KERN_INFO "audio: streaming.\n"); + printk(KERN_INFO "audio: streaming\n"); break; case 0x03: - printk(KERN_INFO "audio: nonstreaming.\n"); + printk(KERN_INFO "audio: nonstreaming\n"); break; } na++; @@ -70,44 +73,49 @@ static int usb_audio_probe(struct usb_device *dev) return -1; aud = kmalloc(sizeof(struct usb_audio), GFP_KERNEL); - if (aud) { - memset(aud, 0, sizeof(*aud)); - aud->dev = dev; - dev->private = aud; - -// if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { -// printk (KERN_INFO " Failed usb_set_configuration: Audio\n"); -// break; -// } -// usb_set_protocol(dev, 0); -// usb_set_idle(dev, 0, 0); - -// usb_request_irq(dev, -// usb_rcvctrlpipe(dev, bEndpointAddress), -// usb_audio_irq, -// endpoint->bInterval, -// aud); + if (!aud) + return -1; - list_add(&aud->list, &usb_audio_list); - - return 0; + memset(aud, 0, sizeof(*aud)); + aud->dev = dev; + dev->private = aud; + +/* + if (usb_set_configuration(dev, dev->config[0].bConfigurationValue)) { + printk (KERN_INFO "Failed usb_set_configuration: Audio\n"); + break; } - - if (aud) - kfree (aud); - return -1; + usb_set_protocol(dev, 0); + usb_set_idle(dev, 0, 0); +*/ + +/* + aud->irq_handle = usb_request_irq(dev, + usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), + usb_audio_irq, + endpoint->bInterval, + aud); +*/ + + list_add(&aud->list, &usb_audio_list); + + return 0; } static void usb_audio_disconnect(struct usb_device *dev) { struct usb_audio *aud = (struct usb_audio*) dev->private; - if (aud) { - dev->private = NULL; - list_del(&aud->list); - kfree(aud); - } - printk(KERN_INFO "USB audio driver removed.\n"); + if (!aud) + return; + + list_del(&aud->list); + + usb_release_irq(aud->dev, aud->irq_handle); + aud->irq_handle = NULL; + + kfree(aud); + dev->private = NULL; } int usb_audio_init(void) diff --git a/drivers/usb/cpia.c b/drivers/usb/cpia.c index 9e7f0acd8c8d..6c2ed4db94cd 100644 --- a/drivers/usb/cpia.c +++ b/drivers/usb/cpia.c @@ -1,11 +1,12 @@ /* * USB CPiA Video Camera driver * - * Supports CPiA based Video Camera's. Many manufacturers use this chipset. + * Supports CPiA based Video Cameras. Many manufacturers use this chipset. * There's a good chance, if you have a USB video camera, it's a CPiA based - * one + * one. * * (C) Copyright 1999 Johannes Erdfelt + * (C) Copyright 1999 Randy Dunlap */ #include @@ -453,6 +454,31 @@ static void cpia_parse_data(struct usb_cpia *cpia) cpia->scratchlen = l; } +/* + * For the moment there is no actual data compression (making blocks + * of data contiguous). This just checks the "frames" array for errors. + */ +static int cpia_compress_isochronous(struct usb_isoc_desc *isodesc) +{ + char *data = isodesc->data; + int i, totlen = 0; + + for (i = 0; i < isodesc->frame_count; i++) { + int n = isodesc->frames [i].frame_length; + int st = isodesc->frames [i].frame_status; + +#ifdef CPIA_DEBUG + /* Debugging */ + if (st) + printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n", + i, n, st); +#endif + + } + + return totlen; +} + static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id) { struct usb_cpia *cpia = dev_id; @@ -489,10 +515,10 @@ static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id) sbuf = &cpia->sbuf[cpia->receivesbuf]; - usb_unschedule_isochronous(dev, sbuf->isodesc); + usb_kill_isoc(sbuf->isodesc); /* Do something to it now */ - sbuf->len = usb_compress_isochronous(dev, sbuf->isodesc); + sbuf->len = cpia_compress_isochronous(sbuf->isodesc); #ifdef CPIA_DEBUG if (sbuf->len) @@ -511,7 +537,12 @@ static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id) } /* Reschedule this block of Isochronous desc */ + /* + usb_run_isoc(sbuf->isodesc, NULL); + */ +/* usb_schedule_isochronous(dev, sbuf->isodesc, cpia->sbuf[(cpia->receivesbuf + 2) % 3].isodesc); +*/ /* Move to the next one */ cpia->receivesbuf = (cpia->receivesbuf + 1) % 3; @@ -522,6 +553,8 @@ static int cpia_isoc_irq(int status, void *__buffer, int len, void *dev_id) int cpia_init_isoc(struct usb_cpia *cpia) { struct usb_device *dev = cpia->dev; + struct usb_isoc_desc *id; + int fx, err; cpia->receivesbuf = 0; @@ -529,21 +562,66 @@ int cpia_init_isoc(struct usb_cpia *cpia) cpia->curline = 0; cpia->state = STATE_SCANNING; - /* Allocate all of the memory necessary */ + /* ALT_ISOC is only doing double-buffering, not triple. */ + err = usb_init_isoc (dev, usb_rcvisocpipe (dev, 1), FRAMES_PER_DESC, cpia, + &cpia->sbuf[0].isodesc); + if (err) + printk ("cpia_init_isoc: usb_init_isoc() ret. %d\n", err); + err = usb_init_isoc (dev, usb_rcvisocpipe (dev, 1), FRAMES_PER_DESC, cpia, + &cpia->sbuf[1].isodesc); + if (err) + printk ("cpia_init_isoc: usb_init_isoc() ret. %d\n", err); + + if (!cpia->sbuf[0].isodesc || !cpia->sbuf[1].isodesc) { + if (cpia->sbuf[0].isodesc) + usb_free_isoc (cpia->sbuf[0].isodesc); + if (cpia->sbuf[1].isodesc) + usb_free_isoc (cpia->sbuf[1].isodesc); + return -ENOMEM; + } +#if 0 cpia->sbuf[0].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[0].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia); cpia->sbuf[1].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[1].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia); cpia->sbuf[2].isodesc = usb_allocate_isochronous(dev, usb_rcvisocpipe(dev,1), cpia->sbuf[2].data, STREAM_BUF_SIZE, 960, cpia_isoc_irq, cpia); +#endif #ifdef CPIA_DEBUG printk("isodesc[0] @ %p\n", cpia->sbuf[0].isodesc); printk("isodesc[1] @ %p\n", cpia->sbuf[1].isodesc); +#if 0 printk("isodesc[2] @ %p\n", cpia->sbuf[2].isodesc); +#endif #endif - /* Schedule the queues */ + /* Set the Isoc. desc. parameters. */ + /* First for desc. [0] */ + id = cpia->sbuf [0].isodesc; + id->start_type = START_ASAP; + id->callback_frames = 1; /* on every frame */ + id->callback_fn = cpia_isoc_irq; + id->data = cpia->sbuf [0].data; + id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) + id->frames [fx].frame_length = FRAME_SIZE_PER_DESC; + + /* and the desc. [1] */ + id = cpia->sbuf [1].isodesc; + id->start_type = 0; /* will follow the first desc. */ + id->callback_frames = 1; /* on every frame */ + id->callback_fn = cpia_isoc_irq; + id->data = cpia->sbuf [1].data; + id->buf_size = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + for (fx = 0; fx < FRAMES_PER_DESC; fx++) + id->frames [fx].frame_length = FRAME_SIZE_PER_DESC; + + usb_run_isoc (cpia->sbuf [0].isodesc, NULL); + usb_run_isoc (cpia->sbuf [1].isodesc, cpia->sbuf [0].isodesc); + +#if 0 usb_schedule_isochronous(dev, cpia->sbuf[0].isodesc, NULL); usb_schedule_isochronous(dev, cpia->sbuf[1].isodesc, cpia->sbuf[0].isodesc); usb_schedule_isochronous(dev, cpia->sbuf[2].isodesc, cpia->sbuf[1].isodesc); +#endif #ifdef CPIA_DEBUG printk("done scheduling\n"); @@ -582,19 +660,28 @@ void cpia_stop_isoc(struct usb_cpia *cpia) } /* Unschedule all of the iso td's */ + usb_kill_isoc (cpia->sbuf[1].isodesc); + usb_kill_isoc (cpia->sbuf[0].isodesc); +#if 0 usb_unschedule_isochronous(dev, cpia->sbuf[2].isodesc); usb_unschedule_isochronous(dev, cpia->sbuf[1].isodesc); usb_unschedule_isochronous(dev, cpia->sbuf[0].isodesc); +#endif /* Delete them all */ + usb_free_isoc (cpia->sbuf[1].isodesc); + usb_free_isoc (cpia->sbuf[0].isodesc); +#if 0 usb_delete_isochronous(dev, cpia->sbuf[2].isodesc); usb_delete_isochronous(dev, cpia->sbuf[1].isodesc); usb_delete_isochronous(dev, cpia->sbuf[0].isodesc); +#endif } /* Video 4 Linux API */ static int cpia_open(struct video_device *dev, int flags) { + int err = -ENOMEM; struct usb_cpia *cpia = (struct usb_cpia *)dev; #ifdef CPIA_DEBUG @@ -615,6 +702,15 @@ static int cpia_open(struct video_device *dev, int flags) printk("frame [1] @ %p\n", cpia->frame[1].data); #endif + cpia->sbuf[0].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!cpia->sbuf[0].data) + goto open_err_on0; + + cpia->sbuf[1].data = kmalloc (FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!cpia->sbuf[1].data) + goto open_err_on1; + +#if 0 cpia->sbuf[0].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL); if (!cpia->sbuf[0].data) goto open_err_on0; @@ -626,11 +722,14 @@ static int cpia_open(struct video_device *dev, int flags) cpia->sbuf[2].data = kmalloc(STREAM_BUF_SIZE, GFP_KERNEL); if (!cpia->sbuf[2].data) goto open_err_on2; +#endif #ifdef CPIA_DEBUG printk("sbuf[0] @ %p\n", cpia->sbuf[0].data); printk("sbuf[1] @ %p\n", cpia->sbuf[1].data); +#if 0 printk("sbuf[2] @ %p\n", cpia->sbuf[2].data); +#endif #endif cpia->curframe = -1; @@ -638,7 +737,9 @@ static int cpia_open(struct video_device *dev, int flags) usb_cpia_initstreamcap(cpia->dev, 0, 60); - cpia_init_isoc(cpia); + err = cpia_init_isoc(cpia); + if (err) + goto open_err_on2; return 0; @@ -649,7 +750,7 @@ open_err_on1: open_err_on0: rvfree(cpia->fbuf, 2 * MAX_FRAME_SIZE); open_err_ret: - return -ENOMEM; + return err; } static void cpia_close(struct video_device *dev) diff --git a/drivers/usb/cpia.h b/drivers/usb/cpia.h index 51ff43e79404..6fb914309872 100644 --- a/drivers/usb/cpia.h +++ b/drivers/usb/cpia.h @@ -82,6 +82,9 @@ #define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2) +#define FRAMES_PER_DESC 500 +#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */ + enum { STATE_SCANNING, /* Scanning for start */ STATE_HEADER, /* Parsing header */ @@ -93,7 +96,10 @@ struct usb_device; struct cpia_sbuf { char *data; int len; + struct usb_isoc_desc *isodesc; +#if 0 void *isodesc; +#endif }; enum { diff --git a/drivers/usb/ezusb.c b/drivers/usb/ezusb.c index 4df629732a45..e98423d09a87 100644 --- a/drivers/usb/ezusb.c +++ b/drivers/usb/ezusb.c @@ -31,7 +31,6 @@ /*****************************************************************************/ -#include #include #include #include @@ -68,9 +67,9 @@ struct isodesc { void *hcbuf[2]; void *hcisodesc[2]; unsigned char *buf; -}; +}; -#define ISOFLG_ACTIVE (1<<0) +#define ISOFLG_ACTIVE (1<<0) /* --------------------------------------------------------------------- */ @@ -231,7 +230,7 @@ static void iso_schedrcv(struct isodesc *isodesc) unsigned diff; if (!(isodesc->flags & ISOFLG_ACTIVE)) - return; + return; diff = (isodesc->buflen - 1 + isodesc->rd - isodesc->wr) % isodesc->buflen; if (diff < isodesc->framesperint * isodesc->pktsz) return; @@ -249,9 +248,9 @@ static void iso_schedsnd(struct isodesc *isodesc) { unsigned diff, bcnt, x; unsigned char *p1, *p2; - + if (!(isodesc->flags & ISOFLG_ACTIVE)) - return; + return; for (;;) { diff = (isodesc->schedcnt - isodesc->unschedcnt) & 3; if (diff >= 2) @@ -646,7 +645,7 @@ static int ezusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, else iso_schedsnd(isodesc); spin_unlock_irqrestore(&isodesc->lock, flags); - up(&ez->mutex); + up(&ez->mutex); return 0; } return -ENOIOCTLCMD; diff --git a/drivers/usb/ezusb.h b/drivers/usb/ezusb.h index 0ba383e249ff..44c57ba9dcef 100644 --- a/drivers/usb/ezusb.h +++ b/drivers/usb/ezusb.h @@ -76,11 +76,12 @@ struct ezusb_isodata { void *data; }; -#define EZUSB_STARTISO _IOR('E', 8, struct ezusb_isotransfer) -#define EZUSB_STOPISO _IOR('E', 9, unsigned int) -#define EZUSB_ISODATA _IOWR('E', 10, struct ezusb_isodata) -#define EZUSB_PAUSEISO _IOR('E', 11, unsigned int) -#define EZUSB_RESUMEISO _IOR('E', 12, unsigned int) +#define EZUSB_STARTISO _IOR('E', 8, struct ezusb_isotransfer) +#define EZUSB_STOPISO _IOR('E', 9, unsigned int) +#define EZUSB_ISODATA _IOWR('E', 10, struct ezusb_isodata) +#define EZUSB_PAUSEISO _IOR('E', 11, unsigned int) +#define EZUSB_RESUMEISO _IOR('E', 12, unsigned int) /* --------------------------------------------------------------------- */ #endif /* _LINUX_EZUSB_H */ + diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c index 072d769014b9..19f2fcfd3d6b 100644 --- a/drivers/usb/hub.c +++ b/drivers/usb/hub.c @@ -32,72 +32,35 @@ static int khubd_running = 0; static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) { - devrequest dr; - - dr.requesttype = USB_DIR_IN | USB_RT_HUB; - dr.request = USB_REQ_GET_DESCRIPTOR; - dr.value = (USB_DT_HUB << 8); - dr.index = 0; - dr.length = size; - - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, - data, size); + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB, + USB_DT_HUB << 8, 0, data, size); } static int usb_clear_port_feature(struct usb_device *dev, int port, int feature) { - devrequest dr; - - dr.requesttype = USB_RT_PORT; - dr.request = USB_REQ_CLEAR_FEATURE; - dr.value = feature; - dr.index = port; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, - NULL, 0); + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0); } static int usb_set_port_feature(struct usb_device *dev, int port, int feature) { - devrequest dr; - - dr.requesttype = USB_RT_PORT; - dr.request = USB_REQ_SET_FEATURE; - dr.value = feature; - dr.index = port; - dr.length = 0; - - return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, - NULL, 0); + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0); } static int usb_get_hub_status(struct usb_device *dev, void *data) { - devrequest dr; - - dr.requesttype = USB_DIR_IN | USB_RT_HUB; - dr.request = USB_REQ_GET_STATUS; - dr.value = 0; - dr.index = 0; - dr.length = 4; - - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, - data, 4); + /* FIXME: Don't hardcode 4 */ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0, data, 4); } static int usb_get_port_status(struct usb_device *dev, int port, void *data) { - devrequest dr; - - dr.requesttype = USB_DIR_IN | USB_RT_PORT; - dr.request = USB_REQ_GET_STATUS; - dr.value = 0; - dr.index = port; - dr.length = 4; - - return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, - data, 4); + /* FIXME: Don't hardcode 4 */ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port, data, 4); } /* @@ -110,37 +73,58 @@ static int hub_irq(int status, void *__buffer, int len, void *dev_id) struct usb_hub *hub = dev_id; unsigned long flags; - if (waitqueue_active(&khubd_wait)) { - /* Add the hub to the event queue */ - spin_lock_irqsave(&hub_event_lock, flags); - if (hub->event_list.next == &hub->event_list) { - list_add(&hub->event_list, &hub_event_list); - /* Wake up khubd */ - wake_up(&khubd_wait); + switch (status) { + case USB_ST_REMOVED: + /* Just ignore it */ + break; + case USB_ST_NOERROR: + /* Something happened, let khubd figure it out */ + if (waitqueue_active(&khubd_wait)) { + /* Add the hub to the event queue */ + spin_lock_irqsave(&hub_event_lock, flags); + if (hub->event_list.next == &hub->event_list) { + list_add(&hub->event_list, &hub_event_list); + /* Wake up khubd */ + wake_up(&khubd_wait); + } + spin_unlock_irqrestore(&hub_event_lock, flags); } - spin_unlock_irqrestore(&hub_event_lock, flags); + break; } return 1; } -static void usb_hub_configure(struct usb_hub *hub) +static int usb_hub_configure(struct usb_hub *hub) { struct usb_device *dev = hub->dev; - unsigned char hubdescriptor[8], buf[4]; - int charac, i; + unsigned char buffer[4], *bitmap; + struct usb_hub_descriptor *descriptor; + struct usb_descriptor_header *header; + int i; + /* Set it to the first configuration */ usb_set_configuration(dev, dev->config[0].bConfigurationValue); - if (usb_get_hub_descriptor(dev, hubdescriptor, 8)) - return; + /* Get the length first */ + if (usb_get_hub_descriptor(dev, buffer, 4)) + return -1; - hub->nports = dev->maxchild = hubdescriptor[2]; + header = (struct usb_descriptor_header *)buffer; + bitmap = kmalloc(header->bLength, GFP_KERNEL); + if (!bitmap) + return -1; + + if (usb_get_hub_descriptor(dev, bitmap, header->bLength)) + return -1; + + descriptor = (struct usb_hub_descriptor *)bitmap; + + hub->nports = dev->maxchild = descriptor->bNbrPorts; printk(KERN_INFO "hub: %d-port%s detected\n", hub->nports, (hub->nports == 1) ? "" : "s"); - charac = (hubdescriptor[4] << 8) + hubdescriptor[3]; - switch (charac & HUB_CHAR_LPSM) { + switch (descriptor->wHubCharacteristics & HUB_CHAR_LPSM) { case 0x00: printk(KERN_INFO "hub: ganged power switching\n"); break; @@ -153,12 +137,12 @@ static void usb_hub_configure(struct usb_hub *hub) break; } - if (charac & HUB_CHAR_COMPOUND) + if (descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) printk(KERN_INFO "hub: part of a compound device\n"); else printk(KERN_INFO "hub: standalone hub\n"); - switch (charac & HUB_CHAR_OCPM) { + switch (descriptor->wHubCharacteristics & HUB_CHAR_OCPM) { case 0x00: printk(KERN_INFO "hub: global over current protection\n"); break; @@ -172,34 +156,38 @@ static void usb_hub_configure(struct usb_hub *hub) } printk(KERN_INFO "hub: power on to power good time: %dms\n", - hubdescriptor[5] * 2); + descriptor->bPwrOn2PwrGood * 2); printk(KERN_INFO "hub: hub controller current requirement: %dmA\n", - hubdescriptor[6]); + descriptor->bHubContrCurrent); for (i = 0; i < dev->maxchild; i++) printk(KERN_INFO "hub: port %d is%s removable\n", i + 1, - hubdescriptor[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8)) + bitmap[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8)) ? " not" : ""); - if (usb_get_hub_status(dev, buf)) - return; + kfree(bitmap); + + if (usb_get_hub_status(dev, buffer)) + return -1; printk(KERN_INFO "hub: local power source is %s\n", - (buf[0] & 1) ? "lost (inactive)" : "good"); + (buffer[0] & 1) ? "lost (inactive)" : "good"); printk(KERN_INFO "hub: %sover current condition exists\n", - (buf[0] & 2) ? "" : "no "); + (buffer[0] & 2) ? "" : "no "); /* Enable power to the ports */ printk(KERN_INFO "hub: enabling power on all ports\n"); for (i = 0; i < hub->nports; i++) usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); + + return 0; } static int hub_probe(struct usb_device *dev) { - struct usb_interface_descriptor *intf_desc; + struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; struct usb_hub *hub; unsigned long flags; @@ -212,20 +200,23 @@ static int hub_probe(struct usb_device *dev) if (dev->config[0].bNumInterfaces != 1) return -1; - intf_desc = &dev->config[0].interface[0].altsetting[0]; + interface = &dev->config[0].interface[0].altsetting[0]; /* Is it a hub? */ - if (intf_desc->bInterfaceClass != 9) + if (interface->bInterfaceClass != USB_CLASS_HUB) return -1; - if ((intf_desc->bInterfaceSubClass != 0) && - (intf_desc->bInterfaceSubClass != 1)) + + /* Some hubs have a subclass of 1, which AFAICT according to the */ + /* specs is not defined, but it works */ + if ((interface->bInterfaceSubClass != 0) && + (interface->bInterfaceSubClass != 1)) return -1; /* Multiple endpoints? What kind of mutant ninja-hub is this? */ - if (intf_desc->bNumEndpoints != 1) + if (interface->bNumEndpoints != 1) return -1; - endpoint = &intf_desc->endpoint[0]; + endpoint = &interface->endpoint[0]; /* Output endpoint? Curiousier and curiousier.. */ if (!(endpoint->bEndpointAddress & USB_DIR_IN)) @@ -256,13 +247,13 @@ static int hub_probe(struct usb_device *dev) list_add(&hub->hub_list, &hub_list); spin_unlock_irqrestore(&hub_list_lock, flags); - usb_hub_configure(hub); - - hub->irq_handle = usb_request_irq(dev, usb_rcvctrlpipe(dev, - endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub); + if (usb_hub_configure(hub) >= 0) { + hub->irq_handle = usb_request_irq(dev, usb_rcvctrlpipe(dev, + endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub); - /* Wake up khubd */ - wake_up(&khubd_wait); + /* Wake up khubd */ + wake_up(&khubd_wait); + } return 0; } @@ -282,8 +273,10 @@ static void hub_disconnect(struct usb_device *dev) spin_unlock_irqrestore(&hub_event_lock, flags); - usb_release_irq(hub->dev, hub->irq_handle); - hub->irq_handle = NULL; + if (hub->irq_handle) { + usb_release_irq(hub->dev, hub->irq_handle); + hub->irq_handle = NULL; + } /* Free the memory */ kfree(hub); @@ -319,7 +312,7 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port) return; /* Allocate a new device struct for it */ - usb = hub->bus->op->allocate(hub); + usb = usb_alloc_dev(hub, hub->bus); if (!usb) { printk(KERN_ERR "couldn't allocate usb_device\n"); return; @@ -335,36 +328,47 @@ static void usb_hub_port_connect_change(struct usb_device *hub, int port) /* Run it through the hoops (find a driver, etc) */ if (usb_new_device(usb)) { /* Woops, disable the port */ - printk(KERN_DEBUG "hub: disabling malfunctioning port %d\n", + printk(KERN_DEBUG "hub: disabling port %d\n", port + 1); usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE); - usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_POWER); } } static void usb_hub_events(void) { unsigned long flags; - unsigned char buf[4]; - unsigned short portstatus, portchange; int i; - struct list_head *next, *tmp, *head = &hub_event_list; + struct list_head *tmp; struct usb_device *dev; struct usb_hub *hub; - spin_lock_irqsave(&hub_event_lock, flags); + /* + * We restart the list everytime to avoid a deadlock with + * deleting hubs downstream from this one. This should be + * safe since we delete the hub from the event list. + * Not the most efficient, but avoids deadlocks. + */ + while (1) { + spin_lock_irqsave(&hub_event_lock, flags); + + if (list_empty(&hub_event_list)) + goto he_unlock; + + /* Grab the next entry from the beginning of the list */ + tmp = hub_event_list.next; - tmp = head->next; - while (tmp != head) { hub = list_entry(tmp, struct usb_hub, event_list); dev = hub->dev; - next = tmp->next; - list_del(tmp); INIT_LIST_HEAD(tmp); + spin_unlock_irqrestore(&hub_event_lock, flags); + for (i = 0; i < hub->nports; i++) { + unsigned char buf[4]; + unsigned short portstatus, portchange; + if (usb_get_port_status(dev, i + 1, buf)) { printk(KERN_ERR "get_port_status failed\n"); continue; @@ -406,9 +410,9 @@ static void usb_hub_events(void) } } - tmp = next; } +he_unlock: spin_unlock_irqrestore(&hub_event_lock, flags); } @@ -464,7 +468,6 @@ int usb_hub_init(void) int pid; usb_register(&hub_driver); - printk(KERN_INFO "USB hub driver registered\n"); pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); @@ -482,15 +485,13 @@ int usb_hub_init(void) void usb_hub_cleanup(void) { - struct list_head *next, *tmp, *head = &hub_list; - struct usb_hub *hub; - unsigned long flags, flags2; int ret; /* Kill the thread */ ret = kill_proc(khubd_pid, SIGTERM, 1); if (!ret) { - int count = 10; + /* Wait 10 seconds */ + int count = 10 * 100; while (khubd_running && --count) { current->state = TASK_INTERRUPTIBLE; diff --git a/drivers/usb/hub.h b/drivers/usb/hub.h index 62f4c0ef93d2..a4c40769d3e4 100644 --- a/drivers/usb/hub.h +++ b/drivers/usb/hub.h @@ -46,6 +46,24 @@ #define HUB_CHAR_COMPOUND 0x0004 #define HUB_CHAR_OCPM 0x0018 +/* Hub descriptor */ +struct usb_hub_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bNbrPorts; + __u16 wHubCharacteristics; +#if 0 + __u8 wHubCharacteristics[2]; /* __u16 but not aligned! */ +#endif + __u8 bPwrOn2PwrGood; + __u8 bHubContrCurrent; + /* DeviceRemovable and PortPwrCtrlMask want to be variable-length + bitmaps that hold max 256 entries, but for now they're ignored */ +#if 0 + __u8 filler; +#endif +} __attribute__ ((packed)); + struct usb_device; typedef enum { @@ -69,7 +87,7 @@ struct usb_hub { struct usb_device *dev; /* Reference to the hub's polling IRQ */ - void* irq_handle; + void *irq_handle; /* List of hubs */ struct list_head hub_list; diff --git a/drivers/usb/mouse.c b/drivers/usb/mouse.c index 60d454048282..f46c3ab64c5d 100644 --- a/drivers/usb/mouse.c +++ b/drivers/usb/mouse.c @@ -256,7 +256,7 @@ static struct miscdevice usb_mouse = { static int mouse_probe(struct usb_device *dev) { - struct usb_interface_descriptor *intf_desc; + struct usb_interface_descriptor *interface; struct usb_endpoint_descriptor *endpoint; struct mouse_state *mouse = &static_mouse_state; @@ -269,19 +269,19 @@ static int mouse_probe(struct usb_device *dev) return -1; /* Is it a mouse interface? */ - intf_desc = &dev->config[0].interface[0].altsetting[0]; - if (intf_desc->bInterfaceClass != 3) + interface = &dev->config[0].interface[0].altsetting[0]; + if (interface->bInterfaceClass != 3) return -1; - if (intf_desc->bInterfaceSubClass != 1) + if (interface->bInterfaceSubClass != 1) return -1; - if (intf_desc->bInterfaceProtocol != 2) + if (interface->bInterfaceProtocol != 2) return -1; /* Multiple endpoints? What kind of mutant ninja-mouse is this? */ - if (intf_desc->bNumEndpoints != 1) + if (interface->bNumEndpoints != 1) return -1; - endpoint = &intf_desc->endpoint[0]; + endpoint = &interface->endpoint[0]; /* Output endpoint? Curiousier and curiousier.. */ if (!(endpoint->bEndpointAddress & 0x80)) diff --git a/drivers/usb/printer.c b/drivers/usb/printer.c index 6a7cc53b1997..b82131568324 100644 --- a/drivers/usb/printer.c +++ b/drivers/usb/printer.c @@ -161,7 +161,7 @@ static ssize_t write_printer(struct file * file, unsigned long copy_size; unsigned long bytes_written = 0; unsigned long partial; - int result; + int result = USB_ST_NOERROR; int maxretry; do { diff --git a/drivers/usb/proc_usb.c b/drivers/usb/proc_usb.c index 565fb3923b7d..9c406fa3ef56 100644 --- a/drivers/usb/proc_usb.c +++ b/drivers/usb/proc_usb.c @@ -213,7 +213,7 @@ static int usb_dump_config (const struct usb_config_descriptor *config, const int active, char *buf, int *len) { int i, j; - struct usb_interface *intf; + struct usb_interface *interface; if (!config) { /* getting these some in 2.3.7; none in 2.3.6 */ *len += sprintf (buf + *len, "(null Cfg. desc.)\n"); @@ -224,12 +224,12 @@ static int usb_dump_config (const struct usb_config_descriptor *config, return -1; for (i = 0; i < config->bNumInterfaces; i++) { - intf = config->interface + i; - if ((intf) == NULL) + interface = config->interface + i; + if (!interface) break; - for (j = 0; j < intf->num_altsetting; j++) - if (usb_dump_interface (intf->altsetting + j, buf, len) < 0) + for (j = 0; j < interface->num_altsetting; j++) + if (usb_dump_interface (interface->altsetting + j, buf, len) < 0) return -1; } @@ -433,6 +433,250 @@ static int usb_driver_list_dump (char *buf, char **start, off_t offset, return (len); } +/* + * proc entry for every device + * sailer@ife.ee.ethz.ch + */ +#include +#include +#include +#include "ezusb.h" + +static long long usbdev_lseek(struct file * file, long long offset, int orig) +{ + switch (orig) { + case 0: + file->f_pos = offset; + return file->f_pos; + + case 1: + file->f_pos += offset; + return file->f_pos; + + case 2: + return -EINVAL; + + default: + return -EINVAL; + } +} + +static ssize_t usbdev_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + struct proc_dir_entry *dp = (struct proc_dir_entry *)inode->u.generic_ip; + struct usb_device *dev = (struct usb_device *)dp->data; + ssize_t ret = 0; + unsigned len; + + if (*ppos < 0) + return -EINVAL; + if (*ppos < sizeof(struct usb_device_descriptor)) { + len = sizeof(struct usb_device_descriptor); + if (len > nbytes) + len = nbytes; + copy_to_user_ret(buf, ((char *)&dev->descriptor) + *ppos, len, -EFAULT); + *ppos += len; + buf += len; + nbytes -= len; + ret += len; + } + return ret; +} + +static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + struct proc_dir_entry *dp = (struct proc_dir_entry *)inode->u.generic_ip; + struct usb_device *dev = (struct usb_device *)dp->data; + struct ezusb_ctrltransfer ctrl; + struct ezusb_bulktransfer bulk; + struct ezusb_setinterface setintf; + unsigned int len1, ep, pipe; + unsigned long len2; + unsigned char *tbuf; + int i; + + switch (cmd) { + case EZUSB_CONTROL: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT); + if (ctrl.dlen > PAGE_SIZE) + return -EINVAL; + if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) + return -ENOMEM; + if (ctrl.requesttype & 0x80) { + if (ctrl.dlen && !access_ok(VERIFY_WRITE, ctrl.data, ctrl.dlen)) { + free_page((unsigned long)tbuf); + return -EINVAL; + } + i = dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), (devrequest *)&ctrl, tbuf, ctrl.dlen); + if (!i && ctrl.dlen) { + copy_to_user_ret(ctrl.data, tbuf, ctrl.dlen, -EFAULT); + } + } else { + if (ctrl.dlen) { + copy_from_user_ret(tbuf, ctrl.data, ctrl.dlen, -EFAULT); + } + i = dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), (devrequest *)&ctrl, tbuf, ctrl.dlen); + } + free_page((unsigned long)tbuf); + if (i) { + printk(KERN_WARNING "procusb: EZUSB_CONTROL failed rqt %u rq %u len %u ret %d\n", + ctrl.requesttype, ctrl.request, ctrl.length, i); + return -ENXIO; + } + return 0; + + case EZUSB_BULK: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT); + if (bulk.ep & 0x80) + pipe = usb_rcvbulkpipe(dev, bulk.ep & 0x7f); + else + pipe = usb_sndbulkpipe(dev, bulk.ep & 0x7f); + if (!usb_maxpacket(dev, pipe, !(bulk.ep & 0x80))) + return -EINVAL; + len1 = bulk.len; + if (len1 > PAGE_SIZE) + len1 = PAGE_SIZE; + if (!(tbuf = (unsigned char *)__get_free_page(GFP_KERNEL))) + return -ENOMEM; + if (bulk.ep & 0x80) { + if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { + free_page((unsigned long)tbuf); + return -EINVAL; + } + i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2); + if (!i && len2) { + copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT); + } + } else { + if (len1) { + copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT); + } + i = dev->bus->op->bulk_msg(dev, pipe, tbuf, len1, &len2); + } + free_page((unsigned long)tbuf); + if (i) { + printk(KERN_WARNING "procusb: EZUSB_BULK failed ep 0x%x len %u ret %d\n", + bulk.ep, bulk.len, i); + return -ENXIO; + } + return len2; + + case EZUSB_RESETEP: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + get_user_ret(ep, (unsigned int *)arg, -EFAULT); + if ((ep & ~0x80) >= 16) + return -EINVAL; + usb_settoggle(dev, ep & 0xf, !(ep & 0x80), 0); + return 0; + + case EZUSB_SETINTERFACE: + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + copy_from_user_ret(&setintf, (void *)arg, sizeof(setintf), -EFAULT); + if (usb_set_interface(dev, setintf.interface, setintf.altsetting)) + return -EINVAL; + return 0; + } + return -ENOIOCTLCMD; +} + +static struct file_operations proc_usb_device_file_operations = { + usbdev_lseek, /* lseek */ + usbdev_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* poll */ + usbdev_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* flush */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +static struct inode_operations proc_usb_device_inode_operations = { + &proc_usb_device_file_operations, /* file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* get_block */ + NULL, /* readpage */ + NULL, /* writepage */ + NULL, /* flushpage */ + NULL, /* truncate */ + NULL, /* permission */ + NULL, /* smap */ + NULL /* revalidate */ +}; + +#define PROCUSB_MAXBUSSES 64 + +static unsigned long busnumbermap[(PROCUSB_MAXBUSSES+8 * sizeof(unsigned long)-1) / (8 * sizeof(unsigned long))] = { 0, }; + +void proc_usb_add_bus(struct usb_bus *bus) +{ + int bnum; + char buf[16]; + + bus->proc_busnum = -1; + bus->proc_entry = NULL; + if (!usbdir) + return; + bnum = find_first_zero_bit(busnumbermap, PROCUSB_MAXBUSSES); + if (bnum >= PROCUSB_MAXBUSSES) + return; + sprintf(buf, "%03d", bnum); + if (!(bus->proc_entry = create_proc_entry(buf, S_IFDIR, usbdir))) + return; + set_bit(bnum, busnumbermap); + bus->proc_busnum = bnum; + bus->proc_entry->data = bus; +} + +/* devices need already be removed! */ +void proc_usb_remove_bus(struct usb_bus *bus) +{ + if (!bus->proc_entry) + return; + remove_proc_entry(bus->proc_entry->name, usbdir); + clear_bit(bus->proc_busnum, busnumbermap); +} + +void proc_usb_add_device(struct usb_device *dev) +{ + char buf[16]; + + dev->proc_entry = NULL; + if (!dev->bus->proc_entry) + return; + sprintf(buf, "%03d", dev->devnum); + if (!(dev->proc_entry = create_proc_entry(buf, 0, dev->bus->proc_entry))) + return; + dev->proc_entry->ops = &proc_usb_device_inode_operations; + dev->proc_entry->data = dev; +} + +void proc_usb_remove_device(struct usb_device *dev) +{ + if (dev->proc_entry) + remove_proc_entry(dev->proc_entry->name, dev->bus->proc_entry); +} + + void proc_usb_cleanup (void) { if (driversdir) diff --git a/drivers/usb/uhci-debug.c b/drivers/usb/uhci-debug.c index b081842be3e9..39c326fedf8c 100644 --- a/drivers/usb/uhci-debug.c +++ b/drivers/usb/uhci-debug.c @@ -2,7 +2,11 @@ * UHCI-specific debugging code. Invaluable when something * goes wrong, but don't get in my face. * + * Kernel visible pointers are surrounded in []'s and bus + * visible pointers are surrounded in ()'s + * * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999 Johannes Erdfelt */ #include @@ -10,65 +14,66 @@ #include "uhci.h" -void show_td(struct uhci_td * td) +void uhci_show_td(struct uhci_td * td) { char *spid; printk("%08x ", td->link); - printk("%se%d %s%s%s%s%s%s%s%s%s%sLength=%x ", - ((td->status >> 29) & 1) ? "SPD " : "", + printk("e%d %s%s%s%s%s%s%s%s%s%sLength=%x ", ((td->status >> 27) & 3), - ((td->status >> 26) & 1) ? "LS " : "", - ((td->status >> 25) & 1) ? "IOS " : "", - ((td->status >> 24) & 1) ? "IOC " : "", - ((td->status >> 23) & 1) ? "Active " : "", - ((td->status >> 22) & 1) ? "Stalled " : "", - ((td->status >> 21) & 1) ? "DataBufErr " : "", - ((td->status >> 20) & 1) ? "Babble " : "", - ((td->status >> 19) & 1) ? "NAK " : "", - ((td->status >> 18) & 1) ? "CRC/Timeo " : "", - ((td->status >> 17) & 1) ? "BitStuff " : "", + (td->status & TD_CTRL_SPD) ? "SPD " : "", + (td->status & TD_CTRL_LS) ? "LS " : "", + (td->status & TD_CTRL_IOC) ? "IOC " : "", + (td->status & TD_CTRL_ACTIVE) ? "Active " : "", + (td->status & TD_CTRL_STALLED) ? "Stalled " : "", + (td->status & TD_CTRL_DBUFERR) ? "DataBufErr " : "", + (td->status & TD_CTRL_BABBLE) ? "Babble " : "", + (td->status & TD_CTRL_NAK) ? "NAK " : "", + (td->status & TD_CTRL_CRCTIMEO) ? "CRC/Timeo " : "", + (td->status & TD_CTRL_BITSTUFF) ? "BitStuff " : "", td->status & 0x7ff); + switch (td->info & 0xff) { - case 0x2d: - spid = "SETUP"; - break; - case 0xe1: - spid = "OUT"; - break; - case 0x69: - spid = "IN"; - break; - default: - spid = "?"; - break; + case USB_PID_SETUP: + spid = "SETUP"; + break; + case USB_PID_OUT: + spid = "OUT"; + break; + case USB_PID_IN: + spid = "IN"; + break; + default: + spid = "?"; + break; } + printk("MaxLen=%x DT%d EndPt=%x Dev=%x, PID=%x(%s) ", td->info >> 21, - ((td->info >> 19) & 1), - (td->info >> 15) & 15, - (td->info >> 8) & 127, - (td->info & 0xff), - spid); + ((td->info >> 19) & 1), + (td->info >> 15) & 15, + (td->info >> 8) & 127, + (td->info & 0xff), + spid); printk("(buf=%08x)\n", td->buffer); } -static void show_sc(int port, unsigned short status) +static void uhci_show_sc(int port, unsigned short status) { printk(" stat%d = %04x %s%s%s%s%s%s%s%s\n", port, status, - (status & (1 << 12)) ? " PortSuspend" : "", - (status & (1 << 9)) ? " PortReset" : "", - (status & (1 << 8)) ? " LowSpeed" : "", - (status & 0x40) ? " ResumeDetect" : "", - (status & 0x08) ? " EnableChange" : "", - (status & 0x04) ? " PortEnabled" : "", - (status & 0x02) ? " ConnectChange" : "", - (status & 0x01) ? " PortConnected" : ""); + (status & USBPORTSC_SUSP) ? "PortSuspend " : "", + (status & USBPORTSC_PR) ? "PortReset " : "", + (status & USBPORTSC_LSDA) ? "LowSpeed " : "", + (status & USBPORTSC_RD) ? "ResumeDetect " : "", + (status & USBPORTSC_PEC) ? "EnableChange " : "", + (status & USBPORTSC_PE) ? "PortEnabled " : "", + (status & USBPORTSC_CSC) ? "ConnectChange " : "", + (status & USBPORTSC_CCS) ? "PortConnected " : ""); } -void show_status(struct uhci *uhci) +void uhci_show_status(struct uhci *uhci) { unsigned int io_addr = uhci->io_addr; unsigned short usbcmd, usbstat, usbint, usbfrnum; @@ -87,30 +92,31 @@ void show_status(struct uhci *uhci) printk(" usbcmd = %04x %s%s%s%s%s%s%s%s\n", usbcmd, - (usbcmd & 0x80) ? " Maxp64" : " Maxp32", - (usbcmd & 0x40) ? " CF" : "", - (usbcmd & 0x20) ? " SWDBG" : "", - (usbcmd & 0x10) ? " FGR" : "", - (usbcmd & 0x08) ? " EGSM" : "", - (usbcmd & 0x04) ? " GRESET" : "", - (usbcmd & 0x02) ? " HCRESET" : "", - (usbcmd & 0x01) ? " RS" : ""); + (usbcmd & USBCMD_MAXP) ? "Maxp64 " : "Maxp32 ", + (usbcmd & USBCMD_CF) ? "CF " : "", + (usbcmd & USBCMD_SWDBG) ? "SWDBG " : "", + (usbcmd & USBCMD_FGR) ? "FGR " : "", + (usbcmd & USBCMD_EGSM) ? "EGSM " : "", + (usbcmd & USBCMD_GRESET) ? "GRESET " : "", + (usbcmd & USBCMD_HCRESET) ? "HCRESET " : "", + (usbcmd & USBCMD_RS) ? "RS " : ""); printk(" usbstat = %04x %s%s%s%s%s%s\n", usbstat, - (usbstat & 0x20) ? " HCHalted" : "", - (usbstat & 0x10) ? " HostControllerProcessError" : "", - (usbstat & 0x08) ? " HostSystemError" : "", - (usbstat & 0x04) ? " ResumeDetect" : "", - (usbstat & 0x02) ? " USBError" : "", - (usbstat & 0x01) ? " USBINT" : ""); + (usbstat & USBSTS_HCH) ? "HCHalted " : "", + (usbstat & USBSTS_HCPE) ? "HostControllerProcessError " : "", + (usbstat & USBSTS_HSE) ? "HostSystemError " : "", + (usbstat & USBSTS_RD) ? "ResumeDetect " : "", + (usbstat & USBSTS_ERROR) ? "USBError " : "", + (usbstat & USBSTS_USBINT) ? "USBINT " : ""); printk(" usbint = %04x\n", usbint); - printk(" usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1, 0xfff & (4*(unsigned int)usbfrnum)); + printk(" usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1, + 0xfff & (4*(unsigned int)usbfrnum)); printk(" flbaseadd = %08x\n", flbaseadd); printk(" sof = %02x\n", sof); - show_sc(1, portsc1); - show_sc(2, portsc2); + uhci_show_sc(1, portsc1); + uhci_show_sc(2, portsc2); } #define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x)) @@ -123,13 +129,13 @@ struct uhci_td *uhci_link_to_td(unsigned int link) return bus_to_virt(link & ~UHCI_PTR_BITS); } -void show_queue(struct uhci_qh *qh) +void uhci_show_queue(struct uhci_qh *qh) { - struct uhci_td *td; - int i = 0; + struct uhci_td *td, *first; + int i = 0, count = 1000; if (qh->element & UHCI_PTR_QH) - printk(" Element points to QH?\n"); + printk(" Element points to QH (bug?)\n"); if (qh->element & UHCI_PTR_DEPTH) printk(" Depth traverse\n"); @@ -138,19 +144,30 @@ void show_queue(struct uhci_qh *qh) printk(" Terminate\n"); if (!(qh->element & ~UHCI_PTR_BITS)) { - printk(" td 0 = NULL\n"); + printk(" td 0: [NULL]\n"); return; } - for(td = uhci_link_to_td(qh->element); td; - td = uhci_link_to_td(td->link)) { - printk(" td %d = %p\n", i++, td); + if (qh->first) + first = qh->first; + else + first = uhci_link_to_td(qh->element); + + /* Make sure it doesn't runaway */ + for (td = first; td && count > 0; + td = uhci_link_to_td(td->link), --count) { + printk(" td %d: [%p]\n", i++, td); printk(" "); - show_td(td); + uhci_show_td(td); + + if (td == uhci_link_to_td(td->link)) { + printk(KERN_ERR "td links to itself!\n"); + break; + } } } -int is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh) +static int uhci_is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh) { int j; @@ -166,7 +183,7 @@ static const char *qh_names[] = {"interrupt2", "interrupt4", "interrupt8", "interrupt128", "interrupt256", "control", "bulk"}; -void show_queues(struct uhci *uhci) +void uhci_show_queues(struct uhci *uhci) { int i; struct uhci_qh *qh; @@ -178,13 +195,13 @@ void show_queues(struct uhci *uhci) qh = uhci_link_to_qh(uhci->skelqh[i].link); for (; qh; qh = uhci_link_to_qh(qh->link)) { - if (is_skeleton_qh(uhci, qh)) + if (uhci_is_skeleton_qh(uhci, qh)) break; printk(" [%p] (%08X) (%08x)\n", qh, qh->link, qh->element); - show_queue(qh); + uhci_show_queue(qh); } } } diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c index 86a96c47fddb..9413ce67b925 100644 --- a/drivers/usb/uhci.c +++ b/drivers/usb/uhci.c @@ -3,6 +3,7 @@ * * (C) Copyright 1999 Linus Torvalds * (C) Copyright 1999 Johannes Erdfelt + * (C) Copyright 1999 Randy Dunlap * * Intel documents this fairly well, and as far as I know there * are no royalties or anything like that, but even so there are @@ -63,32 +64,51 @@ static LIST_HEAD(uhci_list); #define UHCI_DEBUG /* - * Map status to standard result codes. + * function prototypes + */ + +static int uhci_get_current_frame_number (struct usb_device *usb_dev); + +static int uhci_init_isoc (struct usb_device *usb_dev, + unsigned int pipe, + int frame_count, + void *context, + struct usb_isoc_desc **isocdesc); + +static void uhci_free_isoc (struct usb_isoc_desc *isocdesc); + +static int uhci_run_isoc (struct usb_isoc_desc *isocdesc, + struct usb_isoc_desc *pr_isocdesc); + +static int uhci_kill_isoc (struct usb_isoc_desc *isocdesc); + +/* + * Map status to standard result codes * - * is ((td->status >> 16) & 0xff) [a.k.a. uhci_status_bits(td->status)] + * is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status) * is True for output TDs and False for input TDs. */ static int uhci_map_status(int status, int dir_out) { if (!status) return USB_ST_NOERROR; - if (status & 0x02) /* Bitstuff error*/ + if (status & TD_CTRL_BITSTUFF) /* Bitstuff error */ return USB_ST_BITSTUFF; - if (status & 0x04) { /* CRC/Timeout */ + if (status & TD_CTRL_CRCTIMEO) { /* CRC/Timeout */ if (dir_out) - return USB_ST_NORESPONSE; + return USB_ST_NORESPONSE; else return USB_ST_CRC; } - if (status & 0x08) /* NAK */ + if (status & TD_CTRL_NAK) /* NAK */ return USB_ST_TIMEOUT; - if (status & 0x10) /* Babble */ + if (status & TD_CTRL_BABBLE) /* Babble */ return USB_ST_STALL; - if (status & 0x20) /* Buffer error */ + if (status & TD_CTRL_DBUFERR) /* Buffer error */ return USB_ST_BUFFERUNDERRUN; - if (status & 0x40) /* Stalled */ + if (status & TD_CTRL_STALLED) /* Stalled */ return USB_ST_STALL; - if (status & 0x80) /* Active */ + if (status & TD_CTRL_ACTIVE) /* Active */ return USB_ST_NOERROR; return USB_ST_INTERNALERROR; @@ -96,77 +116,83 @@ static int uhci_map_status(int status, int dir_out) /* * Return the result of a TD.. */ -static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned long *rval) +static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned long *rval, int debug) { unsigned int status; struct uhci_td *tmp; - - if (!td->qh) - tmp = td; - else - tmp = uhci_ptr_to_virt(td->qh->element); + int count = 1000; if (rval) *rval = 0; - /* locate the first failing td, if any */ + /* Start at the TD first in the chain, if possible */ + if (td->qh && td->qh->first) + tmp = td->qh->first; + else + tmp = td; + if (!tmp) + return USB_ST_INTERNALERROR; + + /* Locate the first failing td, if any */ do { status = uhci_status_bits(tmp->status); + if (status) { - /* must reset the toggle on first error */ - if (uhci_debug) { - printk(KERN_DEBUG "Set toggle from %x rval %ld\n", - (unsigned int)tmp, rval ? *rval : 0); + if (debug) { + /* Must reset the toggle on first error */ + if (uhci_debug) { + printk(KERN_DEBUG "Set toggle from %x rval %ld\n", + (unsigned int)tmp, rval ? *rval : 0); + } + + usb_settoggle(dev->usb, uhci_endpoint(tmp->info), + uhci_packetout(tmp->info) ^ 1, + uhci_toggle(tmp->info)); + break; } - usb_settoggle(dev->usb, uhci_endpoint(tmp->info), - uhci_packetout(tmp->info), uhci_toggle(tmp->info)); - break; } else { - if (rval) - *rval += uhci_actual_length(tmp->status); + if (rval && ((tmp->info & 0xFF) == USB_PID_IN)) + *rval += uhci_actual_length(tmp->status); } + if ((tmp->link & UHCI_PTR_TERM) || (tmp->link & UHCI_PTR_QH)) break; + tmp = uhci_ptr_to_virt(tmp->link); - } while (1); + } while (--count); - if (!status) + if (!count) { + printk(KERN_ERR "runaway td's in uhci_td_result!\n"); + /* Force debugging on */ + debug = 1; + } else if (!status) return USB_ST_NOERROR; /* Some debugging code */ - if (uhci_debug) { - int count = 10; - - if (!td->qh) - tmp = td; - else - tmp = uhci_ptr_to_virt(td->qh->element); + if (debug && uhci_debug) { printk(KERN_DEBUG "uhci_td_result() failed with status %x\n", status); - do { - show_td(tmp); - if ((tmp->link & UHCI_PTR_TERM) || - (tmp->link & UHCI_PTR_QH)) - break; - tmp = uhci_ptr_to_virt(tmp->link); - } while (--count); + + /* Print the chain for debugging purposes */ + if (td->qh) + uhci_show_queue(td->qh); + else + uhci_show_td(td); } - if (status & 0x40) { + if (status & TD_CTRL_STALLED) { /* endpoint has stalled - mark it halted */ usb_endpoint_halt(dev->usb, uhci_endpoint(tmp->info), uhci_packetout(tmp->info)); return USB_ST_STALL; } - if (status == 0x80) { - /* still active */ - if (!rval) - return USB_ST_DATAUNDERRUN; - } - return uhci_map_status(status, uhci_packetout(tmp->info)); + if ((status == TD_CTRL_ACTIVE) && (!rval)) + return USB_ST_DATAUNDERRUN; + + return uhci_map_status(status, usb_pipeout(tmp->info) ^ 1); } /* @@ -194,6 +220,7 @@ static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *first, str :"=q" (success), "=a" (link) :"m" (qh->element), "1" (link), "r" (new) :"memory"); + if (success) { /* Was there a successor entry? Fix it's backpointer */ if ((link & UHCI_PTR_TERM) == 0) { @@ -203,6 +230,10 @@ static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *first, str break; } } + + qh->first = first; + first->qh = qh; + last->qh = qh; } static inline void uhci_insert_td_in_qh(struct uhci_qh *qh, struct uhci_td *td) @@ -279,6 +310,54 @@ static void uhci_remove_td(struct uhci_td *td) : :"r" (link), "m" (*backptr), "a" (me) :"memory"); + + /* Reset it just in case */ + td->link = UHCI_PTR_TERM; +} + +/* + * Only the USB core should call uhci_alloc_dev and uhci_free_dev + */ +static int uhci_alloc_dev(struct usb_device *usb_dev) +{ + struct uhci_device *dev; + + /* Allocate the UHCI device private data */ + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -1; + + /* Initialize "dev" */ + memset(dev, 0, sizeof(*dev)); + + usb_dev->hcpriv = dev; + dev->usb = usb_dev; + atomic_set(&dev->refcnt, 1); + + if (usb_dev->parent) + dev->uhci = usb_to_uhci(usb_dev->parent)->uhci; + + return 0; +} + +static int uhci_free_dev(struct usb_device *usb_dev) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + + if (atomic_dec_and_test(&dev->refcnt)) + kfree(dev); + + return 0; +} + +static void uhci_inc_dev_use(struct uhci_device *dev) +{ + atomic_inc(&dev->refcnt); +} + +static void uhci_dec_dev_use(struct uhci_device *dev) +{ + uhci_free_dev(dev->usb); } static struct uhci_td *uhci_td_alloc(struct uhci_device *dev) @@ -305,13 +384,19 @@ static struct uhci_td *uhci_td_alloc(struct uhci_device *dev) INIT_LIST_HEAD(&td->irq_list); atomic_set(&td->refcnt, 1); + uhci_inc_dev_use(dev); + return td; } static void uhci_td_free(struct uhci_td *td) { - if (atomic_dec_and_test(&td->refcnt)) + if (atomic_dec_and_test(&td->refcnt)) { kmem_cache_free(uhci_td_cachep, td); + + if (td->dev) + uhci_dec_dev_use(td->dev); + } } static struct uhci_qh *uhci_qh_alloc(struct uhci_device *dev) @@ -332,16 +417,23 @@ static struct uhci_qh *uhci_qh_alloc(struct uhci_device *dev) qh->dev = dev; qh->skel = NULL; + qh->first = NULL; init_waitqueue_head(&qh->wakeup); atomic_set(&qh->refcnt, 1); + uhci_inc_dev_use(dev); + return qh; } static void uhci_qh_free(struct uhci_qh *qh) { - if (atomic_dec_and_test(&qh->refcnt)) + if (atomic_dec_and_test(&qh->refcnt)) { kmem_cache_free(uhci_qh_cachep, qh); + + if (qh->dev) + uhci_dec_dev_use(qh->dev); + } } /* @@ -371,9 +463,9 @@ static void uhci_remove_irq_list(struct uhci_td *td) } /* - * This function removes and disallcoates all structures set up for an transfer. + * This function removes and disallocates all structures set up for a transfer. * It takes the qh out of the skeleton, removes the tq and the td's. - * It only removes the associated interrupt handler if removeirq ist set. + * It only removes the associated interrupt handler if removeirq is set. * The *td argument is any td in the list of td's. */ static void uhci_remove_transfer(struct uhci_td *td, char removeirq) @@ -382,10 +474,10 @@ static void uhci_remove_transfer(struct uhci_td *td, char removeirq) struct uhci_td *curtd; unsigned int nextlink; - if (!td->qh) - curtd = td; + if (td->qh && td->qh->first) + curtd = td->qh->first; else - curtd = uhci_ptr_to_virt(td->qh->element); + curtd = td; /* Remove it from the skeleton */ uhci_remove_qh(td->qh->skel, td->qh); @@ -436,7 +528,8 @@ static void *uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb td->link = UHCI_PTR_TERM; /* Terminate */ td->status = status; /* In */ td->info = destination | ((usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)) - 1) << 21) | - (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE); + (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)) << TD_TOKEN_TOGGLE); + td->buffer = virt_to_bus(dev->data); td->qh = qh; td->dev = dev; @@ -471,10 +564,6 @@ int uhci_release_irq(struct usb_device *usb, void *handle) struct uhci_td *td; struct uhci_qh *qh; -#ifdef UHCI_DEBUG - printk(KERN_DEBUG "usb-uhci: releasing irq handle %p\n", handle); -#endif - td = (struct uhci_td *)handle; if (!td) return USB_ST_INTERNALERROR; @@ -498,190 +587,327 @@ int uhci_release_irq(struct usb_device *usb, void *handle) } /* uhci_release_irq() */ /* - * Isochronous operations + * uhci_get_current_frame_number() + * + * returns the current frame number for a USB bus/controller. */ -static int uhci_compress_isochronous(struct usb_device *usb_dev, void *_isodesc) +static int uhci_get_current_frame_number(struct usb_device *usb_dev) { - struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; - char *data = isodesc->data; - int i, totlen = 0; + return inw (usb_to_uhci(usb_dev)->uhci->io_addr + USBFRNUM) & 0x3ff; +} - for (i = 0; i < isodesc->num; i++) { - struct uhci_td *td = &isodesc->td[i]; - char *cdata = uhci_ptr_to_virt(td->buffer); - int n = uhci_actual_length(td->status); - if ((cdata != data) && (n)) - memmove(data, cdata, n); +/* + * uhci_init_isoc() + * + * Checks bus bandwidth allocation for this USB bus. + * Allocates some data structures. + * Initializes parts of them from the function parameters. + * + * It does not associate any data/buffer pointers or + * driver (caller) callback functions with the allocated + * data structures. Such associations are left until + * uhci_run_isoc(). + * + * Returns 0 for success or negative value for error. + * Sets isocdesc before successful return. + */ +static int uhci_init_isoc (struct usb_device *usb_dev, + unsigned int pipe, + int frame_count, /* bandwidth % = 100 * this / 1000 */ + void *context, + struct usb_isoc_desc **isocdesc) +{ + struct usb_isoc_desc *id; -#ifdef UHCI_DEBUG - /* Debugging */ - if (uhci_status_bits(td->status)) - printk(KERN_DEBUG "error: %d %X\n", i, - (td->status >> 16)); +#ifdef BANDWIDTH_ALLOCATION + /* TBD: add bandwidth allocation/checking/management HERE. */ + /* TBD: some way to factor in frame_spacing ??? */ #endif - data += n; - totlen += n; - } + *isocdesc = NULL; - return totlen; -} - -static int uhci_unschedule_isochronous(struct usb_device *usb_dev, void *_isodesc) -{ - struct uhci_device *dev = usb_to_uhci(usb_dev); - struct uhci *uhci = dev->uhci; - struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; - int i; - - if ((isodesc->frame < 0) || (isodesc->frame > 1023)) { - printk(KERN_ERR "illegal frame number %d\n", isodesc->frame); - return 1; + /* Check some parameters. */ + if ((frame_count < 0) || (frame_count > UHCI_NUMFRAMES)) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: invalid frame_count (%d)\n", + frame_count); +#endif + return -EINVAL; } - /* FIXME: Use uhci_remove_td */ + if (!usb_pipeisoc (pipe)) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: NOT an Isoc. pipe\n"); +#endif + return -EINVAL; + } - /* Remove from previous frames */ - for (i = 0; i < isodesc->num; i++) { - struct uhci_td *td = &isodesc->td[i]; + id = kmalloc (sizeof (*id) + + (sizeof (struct isoc_frame_desc) * frame_count), GFP_KERNEL); + if (!id) + return -ENOMEM; - /* Turn off Active and IOC bits */ - td->status &= ~(3 << 23); - td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC); - - uhci->fl->frame[(isodesc->frame + i) % 1024] = td->link; + id->td = kmalloc (sizeof (struct uhci_td) * frame_count, GFP_KERNEL); + if (!id->td) { + kfree (id); + return -ENOMEM; } - isodesc->frame = -1; - + memset (id, 0, sizeof (*id) + + (sizeof (struct isoc_frame_desc) * frame_count)); + memset (id->td, 0, sizeof (struct uhci_td) * frame_count); + + id->frame_count = frame_count; + id->frame_size = usb_maxpacket (usb_dev, pipe, usb_pipeout(pipe)); + /* TBD: or make this a parameter to allow for frame_size + that is less than maxpacketsize */ + id->start_frame = -1; + id->end_frame = -1; + id->usb_dev = usb_dev; + id->pipe = pipe; + id->context = context; + + *isocdesc = id; return 0; -} - -/* td points to the one td we allocated for isochronous transfers */ -static int uhci_schedule_isochronous(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc) +} /* end uhci_init_isoc */ + +/* + * uhci_run_isoc() + * + * Associates data/buffer pointers/lengths and + * driver (caller) callback functions with the + * allocated Isoc. data structures and TDs. + * + * Then inserts the TDs into the USB controller frame list + * for its processing. + * And inserts the callback function into its TD. + * + * pr_isocdesc (previous Isoc. desc.) may be NULL. + * It is used only for chaining one list of TDs onto the + * end of the previous list of TDs. + * + * Returns 0 (success) or error code (negative value). + */ +static int uhci_run_isoc (struct usb_isoc_desc *isocdesc, + struct usb_isoc_desc *pr_isocdesc) { - struct uhci_device *dev = usb_to_uhci(usb_dev); + struct uhci_device *dev = usb_to_uhci (isocdesc->usb_dev); struct uhci *uhci = dev->uhci; - struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; - struct uhci_iso_td *pisodesc = (struct uhci_iso_td *)_pisodesc; - int frame, i; - - if (isodesc->frame != -1) { - printk(KERN_ERR "isoc queue not removed\n"); - uhci_unschedule_isochronous(usb_dev, isodesc); + unsigned long destination, status; + struct uhci_td *td; + int ix, cur_frame, pipeinput, frlen; + int cb_frames = 0; + struct isoc_frame_desc *fd; + unsigned char *bufptr; + + if (!isocdesc->callback_fn) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_run_isoc: caller must have a callback function\n"); +#endif + return -EINVAL; } - /* Insert TD into list */ - if (!pisodesc) { - /* It's not guaranteed to be 1-1024 */ - frame = inw(uhci->io_addr + USBFRNUM) % 1024; - - /* HACK: Start 2 frames from now */ - frame = (frame + 2) % 1024; - } else - frame = (pisodesc->endframe + 1) % 1024; - - for (i = 0; i < isodesc->num; i++) { - struct uhci_td *td = &isodesc->td[i]; - - /* Active */ - td->status |= TD_CTRL_ACTIVE; - td->backptr = &uhci->fl->frame[(frame + i) % 1024]; - td->link = uhci->fl->frame[(frame + i) % 1024]; - uhci->fl->frame[(frame + i) % 1024] = virt_to_bus(td); + /* Check buffer size large enough for maxpacketsize * frame_count. */ + if (isocdesc->buf_size < (isocdesc->frame_count * isocdesc->frame_size)) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: buf_size too small (%d < %d)\n", + isocdesc->buf_size, isocdesc->frame_count * isocdesc->frame_size); +#endif + return -EINVAL; } - /* IOC on the last TD */ - isodesc->td[i - 1].status |= TD_CTRL_IOC; + /* Check buffer ptr for Null. */ + if (!isocdesc->data) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: data ptr is null\n"); +#endif + return -EINVAL; + } - isodesc->frame = frame; - isodesc->endframe = (frame + isodesc->num - 1) % 1024; +#ifdef NEED_ALIGNMENT + /* Check data page alignment. */ + if (((int)(isocdesc->data) & (PAGE_SIZE - 1)) != 0) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: buffer must be page-aligned (%p)\n", + isocdesc->data); +#endif + return -EINVAL; + } +#endif /* NEED_ALIGNMENT */ - return 0; -} + /* + * Check start_type unless pr_isocdesc is used. + */ + if (!pr_isocdesc && (isocdesc->start_type > START_TYPE_MAX)) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_run_isoc: invalid start_type (%d)\n", + isocdesc->start_type); +#endif + return -EINVAL; + } -/* - * Initialize isochronous queue - */ -static void *uhci_allocate_isochronous(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id) -{ - struct uhci_device *dev = usb_to_uhci(usb_dev); - unsigned long destination, status; - struct uhci_td *td; - struct uhci_iso_td *isodesc; - int i; + /* if not START_ASAP (i.e., RELATIVE or ABSOLUTE): */ + if (!pr_isocdesc && (isocdesc->start_type != START_ASAP)) + if ((isocdesc->start_frame < 0) || (isocdesc->start_frame > 1000)) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_init_isoc: bad start_frame value (%d)\n", + isocdesc->start_frame); +#endif + return -EINVAL; + } - isodesc = kmalloc(sizeof(*isodesc), GFP_KERNEL); - if (!isodesc) { - printk(KERN_ERR "Couldn't allocate isodesc!\n"); - return NULL; + /* + * Set the start/end frame numbers. + */ + if (!pr_isocdesc) + cur_frame = uhci_get_current_frame_number (isocdesc->usb_dev); + + if (pr_isocdesc) { + isocdesc->start_frame = pr_isocdesc->end_frame + 1; + } else if (isocdesc->start_type == START_ABSOLUTE) { + /* Use start_frame as is. */ + } else if (isocdesc->start_type == START_RELATIVE) { + if (isocdesc->start_frame < START_FRAME_FUDGE) + isocdesc->start_frame = START_FRAME_FUDGE; + isocdesc->start_frame += cur_frame; + } else if (isocdesc->start_type == START_ASAP) { + isocdesc->start_frame = cur_frame + START_FRAME_FUDGE; } - memset(isodesc, 0, sizeof(*isodesc)); + /* and see if start_frame needs any correction */ + if (isocdesc->start_frame >= 1000) + isocdesc->start_frame -= 1000; - /* Carefully work around the non contiguous pages */ - isodesc->num = len / maxsze; - isodesc->td = kmalloc(sizeof(struct uhci_td) * isodesc->num, GFP_KERNEL); - isodesc->frame = isodesc->endframe = -1; - isodesc->data = data; - isodesc->maxsze = maxsze; - - if (!isodesc->td) { - printk(KERN_ERR "couldn't allocate td's\n"); - kfree(isodesc); - return NULL; - } + /* and fix the end_frame value */ + isocdesc->end_frame = isocdesc->start_frame + isocdesc->frame_count - 1; + if (isocdesc->end_frame >= 1000) + isocdesc->end_frame -= 1000; - isodesc->frame = isodesc->endframe = -1; + isocdesc->prev_completed_frame = -1; + isocdesc->cur_completed_frame = -1; + + destination = (isocdesc->pipe & PIPE_DEVEP_MASK) | + usb_packetid (isocdesc->pipe); + status = TD_CTRL_ACTIVE | TD_CTRL_IOS; /* mark Isoc.; can't be low speed */ + pipeinput = usb_pipein (isocdesc->pipe); + cur_frame = isocdesc->start_frame; + bufptr = isocdesc->data; /* - * Build the DATA TD's + * Build the Data TDs. + * TBD: Not using frame_spacing (Yet). Defaults to 1 (every frame). + * (frame_spacing is a way to request less bandwidth.) + * This can also be done by using frame_length = 0 in the + * frame_desc array, but this way won't take less bandwidth + * allocation into account. */ - i = 0; - do { - /* Build the TD for control status */ - td = &isodesc->td[i]; - /* The "pipe" thing contains the destination in bits 8--18 */ - destination = (pipe & PIPE_DEVEP_MASK) - | usb_packetid (pipe); /* add IN or OUT */ + if (isocdesc->frame_spacing <= 0) + isocdesc->frame_spacing = 1; + + for (ix = 0, td = isocdesc->td, fd = isocdesc->frames; + ix < isocdesc->frame_count; ix++, td++, fd++, cur_frame++) { + frlen = fd->frame_length; + if (frlen > isocdesc->frame_size) + frlen = isocdesc->frame_size; - status = (pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOS; +#ifdef NOTDEF + td->info = destination | /* use Actual len on OUT; max. on IN */ + (pipeinput ? ((isocdesc->frame_size - 1) << 21) + : ((frlen - 1) << 21)); +#endif + + td->dev_id = isocdesc; /* can get dev_id or context from isocdesc */ + td->status = status; + td->info = destination | ((frlen - 1) << 21); + td->buffer = virt_to_bus (bufptr); + td->dev = dev; + td->isoc_td_number = ix; /* 0-based; does not wrap 999 -> 0 */ + + if (isocdesc->callback_frames && + (++cb_frames >= isocdesc->callback_frames)) { + td->status |= TD_CTRL_IOC; + td->completed = isocdesc->callback_fn; + cb_frames = 0; + } + + bufptr += fd->frame_length; /* or isocdesc->frame_size; */ /* - * Build the TD for the control request + * Insert the TD in the frame list. */ - td->status = status; - td->info = destination | ((maxsze - 1) << 21); - td->buffer = virt_to_bus(data); - td->backptr = NULL; + td->backptr = &uhci->fl->frame [cur_frame]; + td->link = uhci->fl->frame [cur_frame]; + uhci->fl->frame [cur_frame] = virt_to_bus (td); - i++; + if (cur_frame >= 999) + cur_frame = -1; + } /* end for ix */ - data += maxsze; - len -= maxsze; - } while (i < isodesc->num); + /* + * Add IOC on the last TD. + */ + td--; + td->status |= TD_CTRL_IOC; + uhci_add_irq_list (dev->uhci, td, isocdesc->callback_fn, isocdesc->context); /* TBD: D.K. ??? */ - uhci_add_irq_list(dev->uhci, td, completed, dev_id); + return 0; +} /* end uhci_run_isoc */ - return isodesc; -} +/* + * uhci_kill_isoc() + * + * Marks a TD list as Inactive and removes it from the Isoc. + * TD frame list. + * + * Does not free any memory resources. + * + * Returns 0 for success or negative value for error. + */ +static int uhci_kill_isoc (struct usb_isoc_desc *isocdesc) +{ + struct uhci_device *dev = usb_to_uhci (isocdesc->usb_dev); + struct uhci *uhci = dev->uhci; + struct uhci_td *td; + int ix, cur_frame; + + if ((isocdesc->start_frame < 0) || (isocdesc->start_frame >= 1000)) { +#ifdef CONFIG_USB_DEBUG_ISOC + printk (KERN_DEBUG "uhci_kill_isoc: invalid start_frame (%d)\n", + isocdesc->start_frame); +#endif + return -EINVAL; + } + + for (ix = 0, td = isocdesc->td, cur_frame = isocdesc->start_frame; + ix < isocdesc->frame_count; ix++, td++) { + td->status &= ~(TD_CTRL_ACTIVE | TD_CTRL_IOC); + uhci->fl->frame [cur_frame] = td->link; -static void uhci_delete_isochronous(struct usb_device *usb_dev, void *_isodesc) + if (++cur_frame >= 1000) + cur_frame = 0; + } /* end for ix */ + + isocdesc->start_frame = -1; + return 0; +} /* end uhci_kill_isoc */ + +static void uhci_free_isoc (struct usb_isoc_desc *isocdesc) { - struct uhci_iso_td *isodesc = (struct uhci_iso_td *)_isodesc; + /* If still Active, kill it. */ + if (isocdesc->start_frame >= 0) + uhci_kill_isoc (isocdesc); - /* If it's still scheduled, unschedule them */ - if (isodesc->frame) - uhci_unschedule_isochronous(usb_dev, isodesc); + /* Remove it from the IRQ list. */ + uhci_remove_irq_list ((struct uhci_td *)&(isocdesc->td [isocdesc->frame_count - 1])); - /* Remove it from the IRQ list */ - uhci_remove_irq_list(&isodesc->td[isodesc->num - 1]); + /* Free the associate memory. */ + if (isocdesc->td) + kfree (isocdesc->td); - kfree(isodesc->td); - kfree(isodesc); -} + kfree (isocdesc); +} /* end uhci_free_isoc */ /* * Control thread operations: we just mark the last TD @@ -718,26 +944,6 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru uhci_add_irq_list(dev->uhci, last, uhci_generic_completed, &qh->wakeup); -#if 0 - /* FIXME: This is kinda kludged */ - /* Walk the TD list and update the QH pointer */ - { - struct uhci_td *curtd; - int count = 100; - - curtd = first; - do { - curtd->qh = ctrl_qh; - if (curtd->link & TD_CTRL_TERM) - break; - - curtd = uhci_ptr_to_virt(curtd->link); - } while (--count); - if (!count) - printk(KERN_DEBUG "runaway tds!\n"); - } -#endif - uhci_insert_tds_in_qh(qh, first, last); /* Add it into the skeleton */ @@ -755,7 +961,7 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru uhci_qh_free(qh); - return uhci_td_result(dev, last, NULL); + return uhci_td_result(dev, last, NULL, 1); } /* @@ -778,6 +984,11 @@ static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, stru * 29 TD's is a minimum of 232 bytes worth of control * information, that's just ridiculously high. Most * control messages have just a few bytes of data. + * + * 232 is not ridiculously high with many of the + * configurations on audio devices, etc. anyway, + * there is no restriction on length of transfers + * anymore */ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devrequest *cmd, void *data, int len) { @@ -787,12 +998,14 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre int ret, count; int maxsze = usb_maxpacket(usb_dev, pipe, usb_pipeout(pipe)); __u32 nextlink; + unsigned long bytesrequested = len; + unsigned long bytesread = 0; first = td = uhci_td_alloc(dev); if (!td) return -ENOMEM; - /* The "pipe" thing contains the destination in bits 8--18. */ + /* The "pipe" thing contains the destination in bits 8--18 */ destination = (pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP; /* 3 errors */ @@ -811,7 +1024,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre */ destination ^= (USB_PID_SETUP ^ USB_PID_IN); /* SETUP -> IN */ if (usb_pipeout(pipe)) - destination ^= (USB_PID_OUT ^ USB_PID_IN); /* IN -> OUT */ + destination ^= (USB_PID_IN ^ USB_PID_OUT); /* IN -> OUT */ prevtd = td; td = uhci_td_alloc(dev); @@ -851,7 +1064,13 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre /* * Build the final TD for control status */ - destination ^= (USB_PID_OUT ^ USB_PID_IN); /* OUT -> IN */ + /* It's only IN if the pipe is out AND we aren't expecting data */ + destination &= ~0xFF; + if (usb_pipeout(pipe) | (bytesrequested == 0)) + destination |= USB_PID_IN; + else + destination |= USB_PID_OUT; + destination |= 1 << TD_TOKEN_TOGGLE; /* End in Data1 */ td->status = status | TD_CTRL_IOC; /* no limit on errors on final packet */ @@ -863,9 +1082,13 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre /* Start it up.. */ ret = uhci_run_control(dev, first, td); - count = 100; + count = 1000; td = first; do { + if (!uhci_status_bits(td->status) && ((td->info & 0xFF) == + USB_PID_IN)) + bytesread += uhci_actual_length(td->status); + nextlink = td->link; uhci_remove_td(td); uhci_td_free(td); @@ -879,6 +1102,12 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre if (!count) printk(KERN_ERR "runaway td's!?\n"); + if (ret && (bytesread >= bytesrequested)) { + printk(KERN_DEBUG "Recovered sufficient data (asked for %ld, got %ld) from failed cmd\n", + bytesrequested, bytesread); + ret = 0; + } + if (uhci_debug && ret) { __u8 *p = (__u8 *)cmd; @@ -911,32 +1140,12 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_add_irq_list(dev->uhci, last, uhci_generic_completed, &qh->wakeup); -#if 0 - /* FIXME: This is kinda kludged */ - /* Walk the TD list and update the QH pointer */ - { - struct uhci_td *curtd; - int count = 100; - - curtd = first; - do { - curtd->qh = bulk_qh; - if (curtd->link & UHCI_PTR_TERM) - break; - - curtd = uhci_ptr_to_virt(curtd->link); - } while (--count); - if (!count) - printk(KERN_ERR "runaway tds!\n"); - } -#endif - uhci_insert_tds_in_qh(qh, first, last); /* Add it into the skeleton */ uhci_insert_qh(&dev->uhci->skel_bulk_qh, qh); - schedule_timeout(HZ*5); /* 5 seconds */ + schedule_timeout(HZ * 5); /* 5 seconds */ remove_wait_queue(&qh->wakeup, &wait); @@ -947,7 +1156,7 @@ static int uhci_run_bulk(struct uhci_device *dev, struct uhci_td *first, struct uhci_qh_free(qh); - return uhci_td_result(dev, last, rval); + return uhci_td_result(dev, last, rval, 1); } /* @@ -1107,82 +1316,36 @@ static void * uhci_request_bulk(struct usb_device *usb_dev, unsigned int pipe, u } /* - *Remove a handler from a pipe. This terminates the transfer. - *We have some assumptions here: + * Remove a handler from a pipe. This terminates the transfer. + * We have some assumptions here: * There is only one queue using this pipe. (the one we remove) * Any data that is in the queue is useless for us, we throw it away. */ -static int uhci_terminate_bulk(struct usb_device *dev, void * first) +static int uhci_terminate_bulk(struct usb_device *dev, void *first) { /* none found? there is nothing to remove! */ if (!first) return 0; - uhci_remove_transfer(first,1); + uhci_remove_transfer(first, 1); return 1; } -static struct usb_device *uhci_usb_alloc(struct usb_device *parent) -{ - struct usb_device *usb_dev; - struct uhci_device *dev; - - /* Allocate the USB device */ - usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL); - if (!usb_dev) - return NULL; - - memset(usb_dev, 0, sizeof(*usb_dev)); - - /* Allocate the UHCI device private data */ - dev = kmalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - kfree(usb_dev); - return NULL; - } - - /* Initialize "dev" */ - memset(dev, 0, sizeof(*dev)); - - usb_dev->hcpriv = dev; - dev->usb = usb_dev; - - usb_dev->parent = parent; - - if (parent) { - usb_dev->bus = parent->bus; - dev->uhci = usb_to_uhci(parent)->uhci; - } - - return usb_dev; -} - -static int uhci_usb_free(struct usb_device *usb_dev) -{ - struct uhci_device *dev = usb_to_uhci(usb_dev); - - kfree(dev); - usb_destroy_configuration(usb_dev); - kfree(usb_dev); - - return 0; -} - struct usb_operations uhci_device_operations = { - uhci_usb_alloc, - uhci_usb_free, + uhci_alloc_dev, + uhci_free_dev, uhci_control_msg, uhci_bulk_msg, uhci_request_irq, uhci_release_irq, uhci_request_bulk, uhci_terminate_bulk, - uhci_allocate_isochronous, - uhci_delete_isochronous, - uhci_schedule_isochronous, - uhci_unschedule_isochronous, - uhci_compress_isochronous + uhci_get_current_frame_number, + uhci_init_isoc, + uhci_free_isoc, + uhci_run_isoc, + uhci_kill_isoc }; /* @@ -1207,7 +1370,7 @@ static void uhci_reset_port(unsigned int port) wait_ms(10); status = inw(port); - if(!(status & USBPORTSC_PE)) { + if (!(status & USBPORTSC_PE)) { outw(status | USBPORTSC_PE, port); /* one more try at enabling port */ wait_ms(50); } @@ -1251,7 +1414,7 @@ static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned i * Ok, we got a new connection. Allocate a device to it, * and find out what it wants to do.. */ - usb_dev = uhci_usb_alloc(root_hub->usb); + usb_dev = usb_alloc_dev(root_hub->usb, root_hub->usb->bus); if (!usb_dev) return; @@ -1303,6 +1466,58 @@ static void uhci_check_configuration(struct uhci *uhci) } while (nr < maxchild); } +static int fixup_isoc_desc (struct uhci_td *td) +{ + struct usb_isoc_desc *isocdesc = td->dev_id; + struct uhci_td *prtd; + struct isoc_frame_desc *frm; + int first_comp = isocdesc->cur_completed_frame + 1; /* 0-based */ + int cur_comp = td->isoc_td_number; /* 0-based */ + int ix, fx; + int num_comp; + + if (first_comp >= isocdesc->frame_count) + first_comp = 0; + num_comp = cur_comp - first_comp + 1; + +#ifdef CONFIG_USB_DEBUG_ISOC + printk ("fixup_isoc_desc.1: td = %p, id = %p, first_comp = %d, cur_comp = %d, num_comp = %d\n", + td, isocdesc, first_comp, cur_comp, num_comp); +#endif + + for (ix = 0, fx = first_comp, prtd = &isocdesc->td [first_comp], frm = &isocdesc->frames [first_comp]; + ix < num_comp; ix++) { + frm->frame_length = uhci_actual_length (prtd->status); + isocdesc->total_length += frm->frame_length; + + if ((frm->frame_status = uhci_map_status (uhci_status_bits (prtd->status), + uhci_packetout (prtd->info)))) + isocdesc->error_count++; + + prtd++; + frm++; + if (++fx >= isocdesc->frame_count) { /* wrap fx, prtd, and frm */ + fx = 0; + prtd = isocdesc->td; + frm = isocdesc->frames; + } /* end wrap */ + } /* end for */ + + /* + * Update some other fields for drivers. + */ + isocdesc->prev_completed_frame = isocdesc->cur_completed_frame; + isocdesc->cur_completed_frame = cur_comp; + isocdesc->total_completed_frames += num_comp; /* 1-based */ + +#ifdef CONFIG_USB_DEBUG_ISOC + printk ("fixup_isoc_desc.2: total_comp_frames = %d, total_length = %d, error_count = %d\n", + isocdesc->total_completed_frames, isocdesc->total_length, isocdesc->error_count); +#endif /* CONFIG_USB_DEBUG_ISOC */ + + return 0; +} + static void uhci_interrupt_notify(struct uhci *uhci) { struct list_head *tmp, *head = &uhci->interrupt_list; @@ -1311,57 +1526,43 @@ static void uhci_interrupt_notify(struct uhci *uhci) spin_lock(&irqlist_lock); tmp = head->next; while (tmp != head) { - struct uhci_td *first, *td = list_entry(tmp, - struct uhci_td, irq_list); + struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list); + unsigned long rval; tmp = tmp->next; - /* We check the TD which had the IOC bit as well as the */ - /* first TD */ - /* XXX: Shouldn't we check all of the TD's in the chain? */ - if ((td->qh) && (td->qh->element & ~UHCI_PTR_BITS)) - first = uhci_link_to_td(td->qh->element); - else - first = NULL; - - /* If any of the error bits are set OR the active is NOT set */ - /* then we're interested in this TD */ - status = td->status & 0xF60000; - - if ((!(status ^ TD_CTRL_ACTIVE)) && (first) && - (!(first->status & TD_CTRL_ACTIVE))) - status = first->status & 0xF60000; + /* We're interested if there was an error or if the chain of */ + /* TD's completed successfully */ + status = uhci_td_result(td->dev, td, &rval, 0); - if (!(status ^ TD_CTRL_ACTIVE)) + if ((status == USB_ST_NOERROR) && (td->status & TD_CTRL_ACTIVE)) continue; - /* remove from IRQ list */ list_del(&td->irq_list); INIT_LIST_HEAD(&td->irq_list); - if (td->completed(uhci_map_status(uhci_status_bits(status), uhci_packetout(td->info)), - bus_to_virt(td->buffer), -1, td->dev_id)) { + if (td->completed(status, bus_to_virt(td->buffer), rval, + td->dev_id)) { + struct usb_device *usb_dev = td->dev->usb; + list_add(&td->irq_list, &uhci->interrupt_list); - /* Isochronous TD's don't need this */ - if (!(td->status & TD_CTRL_IOS)) { - struct usb_device *usb_dev = td->dev->usb; - - usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info)); - td->info &= ~(1 << TD_TOKEN_TOGGLE); /* clear data toggle */ - td->info |= usb_gettoggle(usb_dev, uhci_endpoint(td->info), - uhci_packetout(td->info)) << TD_TOKEN_TOGGLE; /* toggle between data0 and data1 */ - td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC; - /* The HC removes it, so re-add it */ - uhci_insert_td_in_qh(td->qh, td); - } + usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1); + td->info &= ~(1 << 19); /* clear data toggle */ + td->info |= usb_gettoggle(usb_dev, usb_pipeendpoint(td->info), + usb_pipeout(td->info) ^ 1) << 19; /* toggle between data0 and data1 */ + td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC; + /* The HC only removes it when it completed */ + /* successfully, so force remove and readd it */ + uhci_remove_td(td); + uhci_insert_td_in_qh(td->qh, td); } else if (td->flags & UHCI_TD_REMOVE) { struct usb_device *usb_dev = td->dev->usb; /* marked for removal */ td->flags &= ~UHCI_TD_REMOVE; - usb_dotoggle(usb_dev, uhci_endpoint(td->info), uhci_packetout(td->info)); + usb_dotoggle(usb_dev, usb_pipeendpoint(td->info), usb_pipeout(td->info) ^ 1); uhci_remove_qh(td->qh->skel, td->qh); uhci_qh_free(td->qh); uhci_td_free(td); @@ -1406,7 +1607,8 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs) unsigned short status; /* - * Read the interrupt status, and write it back to clear the interrupt cause + * Read the interrupt status, and write it back to clear the + * interrupt cause */ status = inw(io_addr + USBSTS); outw(status, io_addr + USBSTS); @@ -1511,9 +1713,9 @@ static void start_hc(struct uhci *uhci) * Queues are dynamically allocated for devices now, * this code only sets up the skeleton queue */ -static struct uhci *alloc_uhci(unsigned int io_addr) +static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size) { - int i; + int i, port; struct uhci *uhci; struct usb_bus *bus; struct uhci_device *dev; @@ -1527,6 +1729,7 @@ static struct uhci *alloc_uhci(unsigned int io_addr) uhci->irq = -1; uhci->io_addr = io_addr; + uhci->io_size = io_size; INIT_LIST_HEAD(&uhci->interrupt_list); /* We need exactly one page (per UHCI specs), how convenient */ @@ -1544,7 +1747,7 @@ static struct uhci *alloc_uhci(unsigned int io_addr) /* * Allocate the root_hub */ - usb = uhci_usb_alloc(NULL); + usb = usb_alloc_dev(NULL, bus); if (!usb) goto au_free_bus; @@ -1556,10 +1759,29 @@ static struct uhci *alloc_uhci(unsigned int io_addr) uhci->bus->root_hub = uhci_to_usb(dev); /* Initialize the root hub */ + /* UHCI specs says devices must have 2 ports, but goes on to say */ /* they may have more but give no way to determine how many they */ /* have, so default to 2 */ - usb->maxchild = 2; + /* According to the UHCI spec, Bit 7 is always set to 1. So we try */ + /* to use this to our advantage */ + for (port = 0; port < (io_size - 0x10) / 2; port++) { + unsigned int portstatus; + + portstatus = inw(io_addr + 0x10 + (port * 2)); + if (!(portstatus & 0x0080)) + break; + } + printk(KERN_DEBUG "Detected %d ports\n", port); + + /* This is experimental so anything less than 2 or greater than 8 is */ + /* something weird and we'll ignore it */ + if (port < 2 || port > 8) { + printk(KERN_DEBUG "Port count misdetected, forcing to 2 ports\n"); + port = 2; + } + + usb->maxchild = port; usb_init_root_hub(usb); /* 8 Interrupt queues */ @@ -1650,7 +1872,7 @@ static void release_uhci(struct uhci *uhci) kfree(uhci); } -static int uhci_control_thread(void * __uhci) +static int uhci_control_thread(void *__uhci) { struct uhci *uhci = (struct uhci *)__uhci; @@ -1693,7 +1915,7 @@ static int uhci_control_thread(void * __uhci) if (signr == SIGUSR1) { printk(KERN_DEBUG "UHCI queue dump:\n"); - show_queues(uhci); + uhci_show_queues(uhci); } else if (signr == SIGUSR2) { uhci_debug = !uhci_debug; printk(KERN_DEBUG "UHCI debug toggle = %x\n", @@ -1716,19 +1938,19 @@ static int uhci_control_thread(void * __uhci) * If we've successfully found a UHCI, now is the time to increment the * module usage count, start the control thread, and return success.. */ -static int found_uhci(int irq, unsigned int io_addr) +static int found_uhci(int irq, unsigned int io_addr, unsigned int io_size) { int retval; struct uhci *uhci; - uhci = alloc_uhci(io_addr); + uhci = alloc_uhci(io_addr, io_size); if (!uhci) return -ENOMEM; INIT_LIST_HEAD(&uhci->uhci_list); list_add(&uhci->uhci_list, &uhci_list); - request_region(uhci->io_addr, 32, "usb-uhci"); + request_region(uhci->io_addr, io_size, "usb-uhci"); reset_hc(uhci); @@ -1754,7 +1976,7 @@ static int found_uhci(int irq, unsigned int io_addr) } reset_hc(uhci); - release_region(uhci->io_addr, 32); + release_region(uhci->io_addr, uhci->io_size); release_uhci(uhci); return retval; @@ -1767,18 +1989,18 @@ static int start_uhci(struct pci_dev *dev) /* Search for the IO base address.. */ for (i = 0; i < 6; i++) { unsigned int io_addr = dev->resource[i].start; + unsigned int io_size = + dev->resource[i].end - dev->resource[i].start; /* IO address? */ if (!(dev->resource[i].flags & 1)) continue; -#if 0 /* Is it already in use? */ - if (check_region(io_addr, 32)) + if (check_region(io_addr, io_size)) break; -#endif - return found_uhci(dev->irq, io_addr); + return found_uhci(dev->irq, io_addr, io_size); } return -1; } @@ -1819,30 +2041,15 @@ int uhci_init(void) int retval; struct pci_dev *dev = NULL; u8 type; - char *name; - /* FIXME: This is lame, but I guess it's better to leak memory than */ - /* crash */ - name = kmalloc(10, GFP_KERNEL); - if (!name) - return -ENOMEM; - - strcpy(name, "uhci_td"); - - uhci_td_cachep = kmem_cache_create(name, + uhci_td_cachep = kmem_cache_create("uhci_td", sizeof(struct uhci_td), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!uhci_td_cachep) return -ENOMEM; - name = kmalloc(10, GFP_KERNEL); - if (!name) - return -ENOMEM; - - strcpy(name, "uhci_qh"); - - uhci_qh_cachep = kmem_cache_create(name, + uhci_qh_cachep = kmem_cache_create("uhci_qh", sizeof(struct uhci_qh), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); @@ -1854,10 +2061,12 @@ int uhci_init(void) dev = pci_find_class(PCI_CLASS_SERIAL_USB << 8, dev); if (!dev) break; + /* Is it UHCI */ pci_read_config_byte(dev, PCI_CLASS_PROG, &type); - if(type != 0) + if (type != 0) continue; + /* Ok set it up */ retval = start_uhci(dev); if (retval < 0) @@ -1889,7 +2098,8 @@ void uhci_cleanup(void) /* Check if the process is still running */ ret = kill_proc(uhci->control_pid, 0, 1); if (!ret) { - int count = 10; + /* Try a maximum of 10 seconds */ + int count = 10 * 100; uhci->control_continue = 0; wake_up(&uhci_configure); @@ -1910,7 +2120,7 @@ void uhci_cleanup(void) usb_deregister_bus(uhci->bus); reset_hc(uhci); - release_region(uhci->io_addr, 32); + release_region(uhci->io_addr, uhci->io_size); release_uhci(uhci); diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h index 1432b6909fe6..f1a2d35c023c 100644 --- a/drivers/usb/uhci.h +++ b/drivers/usb/uhci.h @@ -60,6 +60,10 @@ #define UHCI_PTR_QH 0x0002 #define UHCI_PTR_DEPTH 0x0004 +#define UHCI_NUMFRAMES 1024 + +struct uhci_td; + struct uhci_qh { /* Hardware fields */ __u32 link; /* Next queue */ @@ -70,6 +74,8 @@ struct uhci_qh { struct uhci_device *dev; /* The owning device */ struct uhci_qh *skel; /* Skeleton head */ + struct uhci_td *first; /* First TD in the chain */ + wait_queue_head_t wakeup; } __attribute__((aligned(16))); @@ -81,6 +87,7 @@ struct uhci_framelist { * for TD : */ #define TD_CTRL_SPD (1 << 29) /* Short Packet Detect */ +#define TD_CTRL_C_ERR_MASK (3 << 27) /* Error Counter bits */ #define TD_CTRL_LS (1 << 26) /* Low Speed Device */ #define TD_CTRL_IOS (1 << 25) /* Isochronous Select */ #define TD_CTRL_IOC (1 << 24) /* Interrupt on Complete */ @@ -89,14 +96,14 @@ struct uhci_framelist { #define TD_CTRL_DBUFERR (1 << 21) /* Data Buffer Error */ #define TD_CTRL_BABBLE (1 << 20) /* Babble Detected */ #define TD_CTRL_NAK (1 << 19) /* NAK Received */ -#define TD_CTRL_CRCTIME (1 << 18) /* CTC/Time Out Error */ +#define TD_CTRL_CRCTIMEO (1 << 18) /* CRC/Time Out Error */ #define TD_CTRL_BITSTUFF (1 << 17) /* Bit Stuff Error */ #define TD_CTRL_ACTLEN_MASK 0x7ff /* actual length, encoded as n - 1 */ #define TD_CTRL_ANY_ERROR (TD_CTRL_STALLED | TD_CTRL_DBUFERR | \ TD_CTRL_BABBLE | TD_CTRL_CRCTIME | TD_CTRL_BITSTUFF) -#define uhci_status_bits(ctrl_sts) ((ctrl_sts >> 16) & 0xff) +#define uhci_status_bits(ctrl_sts) (ctrl_sts & 0xFE0000) #define uhci_actual_length(ctrl_sts) ((ctrl_sts + 1) & TD_CTRL_ACTLEN_MASK) /* 1-based */ #define uhci_ptr_to_virt(x) bus_to_virt(x & ~UHCI_PTR_BITS) @@ -120,6 +127,20 @@ struct uhci_framelist { #define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN) #define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN) +/* + * for TD : (a.k.a. Token) + */ +#define TD_TOKEN_TOGGLE 19 + +#define uhci_maxlen(token) ((token) >> 21) +#define uhci_toggle(token) (((token) >> TD_TOKEN_TOGGLE) & 1) +#define uhci_endpoint(token) (((token) >> 15) & 0xf) +#define uhci_devaddr(token) (((token) >> 8) & 0x7f) +#define uhci_devep(token) (((token) >> 8) & 0x7ff) +#define uhci_packetid(token) ((token) & 0xff) +#define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN) +#define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN) + /* * The documentation says "4 words for hardware, 4 words for software". @@ -152,6 +173,7 @@ struct uhci_td { struct uhci_device *dev; /* The owning device */ struct uhci_qh *qh; /* QH this TD is a part of (ignored for Isochronous) */ int flags; /* Remove, etc */ + int isoc_td_number; /* 0-relative number within a usb_isoc_desc. */ } __attribute__((aligned(16))); struct uhci_iso_td { @@ -180,10 +202,12 @@ struct uhci; #define UHCI_MAXQH 16 #endif -/* The usb device part must be first! */ +/* The usb device part must be first! Not anymore -jerdfelt */ struct uhci_device { struct usb_device *usb; + atomic_t refcnt; + struct uhci *uhci; #if 0 struct uhci_qh qh[UHCI_MAXQH]; /* These are the "common" qh's for each device */ @@ -260,6 +284,7 @@ struct uhci_device { struct uhci { int irq; unsigned int io_addr; + unsigned int io_size; int control_pid; int control_running; @@ -281,9 +306,10 @@ struct uhci { struct uhci_td *uhci_link_to_td(unsigned int element); /* Debugging code */ -void show_td(struct uhci_td * td); -void show_status(struct uhci *uhci); -void show_queues(struct uhci *uhci); +void uhci_show_td(struct uhci_td *td); +void uhci_show_status(struct uhci *uhci); +void uhci_show_queue(struct uhci_qh *qh); +void uhci_show_queues(struct uhci *uhci); #endif diff --git a/drivers/usb/usb-debug.c b/drivers/usb/usb-debug.c index 36010f24c6a1..501a726da713 100644 --- a/drivers/usb/usb-debug.c +++ b/drivers/usb/usb-debug.c @@ -18,24 +18,27 @@ static void usb_show_interface(struct usb_interface_descriptor *altsetting) int i; usb_show_interface_descriptor(altsetting); - for (i = 0 ; i < altsetting->bNumEndpoints; i++) + + for (i = 0; i < altsetting->bNumEndpoints; i++) usb_show_endpoint(altsetting->endpoint + i); } static void usb_show_config(struct usb_config_descriptor *config) { - int i, j; - struct usb_interface *intf; - - usb_show_config_descriptor(config); - for (i = 0; i < config->bNumInterfaces; i++) { - intf = config->interface + i; - if ((intf) == NULL) - break; - printk("\n Interface: %d\n", i); - for (j = 0 ; j < intf->num_altsetting; j++) - usb_show_interface(intf->altsetting + j); - } + int i, j; + struct usb_interface *ifp; + + usb_show_config_descriptor(config); + for (i = 0; i < config->bNumInterfaces; i++) { + ifp = config->interface + i; + + if (!ifp) + break; + + printk("\n Interface: %d\n", i); + for (j = 0; j < ifp->num_altsetting; j++) + usb_show_interface(ifp->altsetting + j); + } } void usb_show_device(struct usb_device *dev) @@ -47,7 +50,6 @@ void usb_show_device(struct usb_device *dev) usb_show_config(dev->config + i); } - /* * Parse and show the different USB descriptors. */ @@ -72,10 +74,25 @@ void usb_show_device_descriptor(struct usb_device_descriptor *desc) case 0: printk(" Per-interface classes\n"); break; - case 9: + case USB_CLASS_AUDIO: + printk(" Audio device class\n"); + break; + case USB_CLASS_COMM: + printk(" Communications class\n"); + break; + case USB_CLASS_HID: + printk(" Human Interface Devices class\n"); + break; + case USB_CLASS_PRINTER: + printk(" Printer device class\n"); + break; + case USB_CLASS_MASS_STORAGE: + printk(" Mass Storage device class\n"); + break; + case USB_CLASS_HUB: printk(" Hub device class\n"); break; - case 0xff: + case USB_CLASS_VENDOR_SPEC: printk(" Vendor class\n"); break; default: @@ -83,7 +100,7 @@ void usb_show_device_descriptor(struct usb_device_descriptor *desc) } } -void usb_show_config_descriptor(struct usb_config_descriptor * desc) +void usb_show_config_descriptor(struct usb_config_descriptor *desc) { printk("Configuration:\n"); printk(" bLength = %4d%s\n", desc->bLength, @@ -97,7 +114,7 @@ void usb_show_config_descriptor(struct usb_config_descriptor * desc) printk(" MaxPower = %4dmA\n", desc->MaxPower * 2); } -void usb_show_interface_descriptor(struct usb_interface_descriptor * desc) +void usb_show_interface_descriptor(struct usb_interface_descriptor *desc) { printk(" Alternate Setting: %2d\n", desc->bAlternateSetting); printk(" bLength = %4d%s\n", desc->bLength, @@ -111,15 +128,33 @@ void usb_show_interface_descriptor(struct usb_interface_descriptor * desc) printk(" iInterface = %02x\n", desc->iInterface); } -void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor * desc) +void usb_show_hid_descriptor(struct usb_hid_descriptor * desc) { - char *bLengthCommentString = (USB_DT_AUCLSTEP_SIZE == desc->bLength) ? - " (!Audio)" : " (!!!)"; + int i; + + printk(" HID:\n"); + printk(" HID version %x.%02x\n", desc->bcdHID >> 8, desc->bcdHID & 0xff); + printk(" bLength = %4d\n", desc->bLength); + printk(" bDescriptorType = %02x\n", desc->bDescriptorType); + printk(" bCountryCode = %02x\n", desc->bCountryCode); + printk(" bNumDescriptors = %02x\n", desc->bNumDescriptors); + + for (i=0; ibNumDescriptors; i++) { + printk(" %d:\n", i); + printk(" bDescriptorType = %02x\n", desc->desc[i].bDescriptorType); + printk(" wDescriptorLength = %04x\n", desc->desc[i].wDescriptorLength); + } +} +void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *desc) +{ + char *LengthCommentString = (desc->bLength == + USB_DT_ENDPOINT_AUDIO_SIZE) ? " (Audio)" : (desc->bLength == + USB_DT_ENDPOINT_SIZE) ? "" : " (!!!)"; char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" }; printk(" Endpoint:\n"); printk(" bLength = %4d%s\n", desc->bLength, - desc->bLength == USB_DT_ENDPOINT_SIZE ? "" : bLengthCommentString); + LengthCommentString); printk(" bDescriptorType = %02x\n", desc->bDescriptorType); printk(" bEndpointAddress = %02x (%s)\n", desc->bEndpointAddress, (desc->bEndpointAddress & 0x80) ? "in" : "out"); @@ -127,29 +162,19 @@ void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor * desc) EndpointType[3 & desc->bmAttributes]); printk(" wMaxPacketSize = %04x\n", desc->wMaxPacketSize); printk(" bInterval = %02x\n", desc->bInterval); - if (USB_DT_AUCLSTEP_SIZE == desc->bLength) { - printk(" bRefresh = %04x\n", desc->bRefresh); - printk(" bSynchAddress = %02x\n", desc->bSynchAddress); - } -} - -void usb_show_hub_descriptor(struct usb_hub_descriptor * desc) -{ - int len = 7; - unsigned char *ptr = (unsigned char *) desc; - printk("Interface:"); - while (len) { - printk(" %02x", *ptr); - ptr++; len--; + /* Audio extensions to the endpoint descriptor */ + if (desc->bLength == USB_DT_ENDPOINT_AUDIO_SIZE) { + printk(" bRefresh = %02x\n", desc->bRefresh); + printk(" bSynchAddress = %02x\n", desc->bSynchAddress); } - printk("\n"); } -void usb_show_string(struct usb_device* dev, char *id, int index) +void usb_show_string(struct usb_device *dev, char *id, int index) { char *p = usb_string(dev, index); if (p != 0) printk(KERN_INFO "%s: %s\n", id, p); } + diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c index a6ba923b2e3d..b028f4bf1e0a 100644 --- a/drivers/usb/usb.c +++ b/drivers/usb/usb.c @@ -2,6 +2,7 @@ * drivers/usb/usb.c * * (C) Copyright Linus Torvalds 1999 + * (C) Copyright Johannes Erdfelt 1999 * * NOTE! This is not actually a driver at all, rather this is * just a collection of helper routines that implement the @@ -12,30 +13,6 @@ * are evil. */ -/* - * Table 9-2 - * - * Offset Field Size Value Desc - * 0 bmRequestType 1 Bitmap D7: Direction - * 0 = Host-to-device - * 1 = Device-to-host - * D6..5: Type - * 0 = Standard - * 1 = Class - * 2 = Vendor - * 3 = Reserved - * D4..0: Recipient - * 0 = Device - * 1 = Interface - * 2 = Endpoint - * 3 = Other - * 4..31 = Reserved - * 1 bRequest 1 Value Specific request (9-3) - * 2 wValue 2 Value Varies - * 4 wIndex 2 Index/Offset Varies - * 6 wLength 2 Count Bytes for data - */ - #include #include #include @@ -67,7 +44,7 @@ int usb_register(struct usb_driver *new_driver) */ tmp = usb_bus_list.next; while (tmp != &usb_bus_list) { - struct usb_bus *bus = list_entry(tmp,struct usb_bus,bus_list); + struct usb_bus *bus = list_entry(tmp,struct usb_bus, bus_list); tmp = tmp->next; usb_check_support(bus->root_hub); @@ -96,12 +73,13 @@ void usb_deregister(struct usb_driver *driver) } } -/* This function is part of a depth-first search down the device tree, +/* + * This function is part of a depth-first search down the device tree, * removing any instances of a device driver. */ -void usb_driver_purge(struct usb_driver *driver,struct usb_device *dev) +static void usb_driver_purge(struct usb_driver *driver,struct usb_device *dev) { - int i; + int i; if (!dev) { printk(KERN_ERR "usbcore: null device being purged!!!\n"); @@ -158,16 +136,16 @@ void usb_free_bus(struct usb_bus *bus) if (!bus) return; - if (bus->bus_list.next != &bus->bus_list) - printk(KERN_ERR "usbcore: freeing non-empty bus\n"); - kfree(bus); } -void usb_register_bus(struct usb_bus *new_bus) +void usb_register_bus(struct usb_bus *bus) { + proc_usb_add_bus(bus); + /* Add it to the list of buses */ - list_add(&new_bus->bus_list, &usb_bus_list); + list_add(&bus->bus_list, &usb_bus_list); + printk("New USB bus registered\n"); } @@ -179,13 +157,15 @@ void usb_deregister_bus(struct usb_bus *bus) * itself up */ list_del(&bus->bus_list); + + proc_usb_remove_bus(bus); } /* * This function is for doing a depth-first search for devices which * have support, for dynamic loading of driver modules. */ -void usb_check_support(struct usb_device *dev) +static void usb_check_support(struct usb_device *dev) { int i; @@ -209,7 +189,7 @@ void usb_check_support(struct usb_device *dev) * looking for one that will accept this device as * his.. */ -int usb_find_driver(struct usb_device *dev) +static int usb_find_driver(struct usb_device *dev) { struct list_head *tmp = usb_driver_list.next; @@ -231,283 +211,311 @@ int usb_find_driver(struct usb_device *dev) } /* - * Parse the fairly incomprehensible output of - * the USB configuration data, and build up the - * USB device database. + * Only HC's should call usb_alloc_dev and usb_free_dev directly + * Anybody may use usb_inc_dev_use or usb_dec_dev_use */ -static int usb_expect_descriptor(unsigned char *ptr, int len, unsigned char desctype, unsigned char descindex) +struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus) { - int parsed = 0; - int n_len; - unsigned short n_desc; + struct usb_device *dev; - for (;;) { - int i; + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return NULL; - if (len < descindex) - return -1; - n_desc = le16_to_cpup((unsigned short *)ptr); - n_len = ptr[0]; + memset(dev, 0, sizeof(*dev)); - if (n_desc == ((desctype << 8) + descindex)) - break; + dev->bus = bus; + dev->parent = parent; + atomic_set(&dev->refcnt, 1); - if (((n_desc >> 8)&0xFF) == desctype && - n_len > descindex) - { - printk("bug: oversized descriptor.\n"); - break; - } - - if (n_len < 2 || n_len > len) - { - printk("Short descriptor\n"); - return -1; - } - printk( - "Expected descriptor %02X/%02X, got %02X/%02X - skipping\n", - desctype, descindex, - (n_desc >> 8) & 0xFF, n_desc & 0xFF); - for (i = 0 ; i < n_len; i++) - printk(" %d %02x\n", i, ptr[i]); - len -= n_len; - ptr += n_len; - parsed += n_len; + dev->bus->op->allocate(dev); + + return dev; +} + +void usb_free_dev(struct usb_device *dev) +{ + if (atomic_dec_and_test(&dev->refcnt)) { + usb_destroy_configuration(dev); + kfree(dev); + + dev->bus->op->deallocate(dev); } - - printk("Found %02X:%02X\n", - desctype, descindex); - return parsed; } -/* - * Parse the even more incomprehensible mess made of the USB spec - * by USB audio having private magic to go with it. - */ - -static int usb_check_descriptor(unsigned char *ptr, int len, unsigned char desctype) +void usb_inc_dev_use(struct usb_device *dev) { - int n_len = ptr[0]; + atomic_inc(&dev->refcnt); +} - if (len <= 0) - return -1; +static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size) +{ + struct usb_descriptor_header *header; + int parsed = 0; + + header = (struct usb_descriptor_header *)buffer; - if (n_len < 2 || n_len > len) { - int i; - printk("Short descriptor. (%d, %d):\n", len, n_len); - for (i = 0; i < len; ++i) - printk(" %d: %x\n", i, ptr[i]); + /* Everything should be fine being passed into here, but we sanity */ + /* check JIC */ + if (header->bLength > size) { + printk(KERN_ERR "usb: ran out of descriptors parsing\n"); return -1; } - - if (ptr[1] == desctype) - return 0; - return -1; -} + if (header->bDescriptorType != USB_DT_ENDPOINT) { + printk(KERN_INFO "usb: unexpected descriptor 0x%X\n", + endpoint->bDescriptorType); + return parsed; + } + memcpy(endpoint, buffer, USB_DT_ENDPOINT_SIZE); + le16_to_cpus(&endpoint->wMaxPacketSize); -static int usb_parse_endpoint(struct usb_device *dev, struct usb_endpoint_descriptor *endpoint, unsigned char *ptr, int len) -{ - int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, USB_DT_ENDPOINT_SIZE); - int i; + buffer += header->bLength; + size -= header->bLength; + parsed += header->bLength; - if (parsed < 0) - return parsed; - memcpy(endpoint, ptr + parsed, ptr[parsed]); - le16_to_cpus(&endpoint->wMaxPacketSize); + /* Skip over the rest of the Class Specific or Vendor Specific */ + /* descriptors */ + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; - parsed += ptr[parsed]; - len -= parsed; + if (header->bLength < 2) { + printk(KERN_ERR "usb: invalid descriptor length of %d\n", header->bLength); + return -1; + } + + /* If we find another descriptor which is at or below us */ + /* in the descriptor heirarchy then return */ + if ((header->bDescriptorType == USB_DT_ENDPOINT) || + (header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE)) + return parsed; - while((i = usb_check_descriptor(ptr+parsed, len, 0x25)) >= 0) { - usb_audio_endpoint(endpoint, ptr+parsed+i); - len -= ptr[parsed+i]; - parsed += ptr[parsed+i]; + printk(KERN_INFO "usb: skipping descriptor 0x%X\n", + header->bDescriptorType); + + buffer += header->bLength; + size -= header->bLength; + parsed += header->bLength; } - - return parsed;// + ptr[parsed]; + + return parsed; } -static int usb_parse_altsetting(struct usb_device *dev, struct usb_interface_descriptor *altsetting, unsigned char *ptr, int len) +#if 0 +static int usb_parse_hid(struct usb_device *dev, struct usb_hid_descriptor *hid, unsigned char *ptr, int len) { + int parsed = usb_expect_descriptor(ptr, len, USB_DT_HID, ptr[0]); int i; - int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, USB_DT_INTERFACE_SIZE); - int retval; if (parsed < 0) return parsed; - memcpy(altsetting, ptr + parsed, *ptr); - len -= ptr[parsed]; - parsed += ptr[parsed]; + memcpy(hid, ptr + parsed, ptr[parsed]); + le16_to_cpus(&hid->bcdHID); - while((i=usb_check_descriptor(ptr+parsed, len, 0x24)) >= 0) { - usb_audio_interface(altsetting, ptr+parsed+i); - len -= ptr[parsed+i]; - parsed += ptr[parsed+i]; - } - - if (altsetting->bNumEndpoints > USB_MAXENDPOINTS) { - printk(KERN_WARNING "usb: too many endpoints.\n"); - return -1; - } + for (i=0; ibNumDescriptors; i++) + le16_to_cpus(&(hid->desc[i].wDescriptorLength)); - altsetting->endpoint = (struct usb_endpoint_descriptor *) - kmalloc(altsetting->bNumEndpoints * sizeof(struct usb_endpoint_descriptor), GFP_KERNEL); - if (!altsetting->endpoint) { - printk(KERN_WARNING "usb: out of memory.\n"); - return -1; - } - memset(altsetting->endpoint, 0, altsetting->bNumEndpoints*sizeof(struct usb_endpoint_descriptor)); - - for (i = 0; i < altsetting->bNumEndpoints; i++) { -// if(((USB_DT_HID << 8) | 9) == *(unsigned short*)(ptr + parsed)) { -// parsed += 9; /* skip over the HID descriptor for now */ -// len -= 9; -// } - retval = usb_parse_endpoint(dev, altsetting->endpoint + i, ptr + parsed, len); - if (retval < 0) - return retval; - parsed += retval; - len -= retval; - } - return parsed; + return parsed + ptr[parsed]; } +#endif -static int usb_parse_config(struct usb_device *dev, struct usb_config_descriptor *config, unsigned char *ptr, int len) +static int usb_parse_interface(struct usb_device *dev, struct usb_interface *interface, unsigned char *buffer, int size) { int i; - int retval; - struct usb_interface *intf; - struct usb_interface_descriptor as; /* This is needing for copying. */ - int parsed = usb_expect_descriptor(ptr, len, USB_DT_CONFIG, 9); - unsigned short bNumInterfaces; - unsigned short bIntfaceNum = 0, bAltSetting = 0; + int retval, parsed = 0; + struct usb_descriptor_header *header; + struct usb_interface_descriptor *ifp; - if (parsed < 0) - return parsed; - - memcpy(config, ptr + parsed, *ptr); - len -= *ptr; - parsed += *ptr; - le16_to_cpus(&config->wTotalLength); - bNumInterfaces = config->bNumInterfaces; + interface->act_altsetting = 0; + interface->num_altsetting = 0; - if (bNumInterfaces > USB_MAXINTERFACES) { - printk(KERN_WARNING "usb: too many interfaces.\n"); + interface->altsetting = kmalloc(sizeof(struct usb_interface_descriptor) * USB_MAXALTSETTING, GFP_KERNEL); + if (!interface->altsetting) { + printk("couldn't kmalloc interface->altsetting\n"); return -1; } - config->interface = (struct usb_interface *) - kmalloc(bNumInterfaces * sizeof(struct usb_interface), GFP_KERNEL); - if (!config->interface) { - printk(KERN_WARNING "usb: out of memory.\n"); - return -1; - } - memset(config->interface, - 0, (bNumInterfaces) * sizeof(struct usb_interface)); - - for (i = 0; i < bNumInterfaces; i++) { - intf = (config->interface) +i; - /* We have at least one interface */ - intf->num_altsetting = 1; - intf->altsetting = (struct usb_interface_descriptor*) - kmalloc((USB_MAXALTSETTING +1) * sizeof(struct usb_interface_descriptor), GFP_KERNEL); - if (!config->interface[i].altsetting) { - printk(KERN_WARNING "usb: out of memory.\n"); - return -1; - } - memset(intf->altsetting, - 0, (USB_MAXALTSETTING+1) * sizeof(struct usb_interface_descriptor)); - } - - /* Ok, we now have allocated the necessary structures, now decide - * where to put the parsed interface descriptors - sort by - * bAltSetting and bInterfaceNumber. - */ - while (len > 0) { - retval = usb_parse_altsetting(dev, &as, ptr + parsed, len); - if (retval < 0) - return parsed; // HACK - // return retval; - parsed += retval; - len -= retval; - bIntfaceNum = as.bInterfaceNumber; - if (bIntfaceNum > config->bNumInterfaces) { - printk(KERN_WARNING "usb: bInterfaceNumber %2u exceeding config->bNumINterfaces.\n", bIntfaceNum); + while (size > 0) { + ifp = interface->altsetting + interface->num_altsetting; + interface->num_altsetting++; + + if (interface->num_altsetting >= USB_MAXALTSETTING) { + printk(KERN_WARNING "usb: too many alternate settings\n"); return -1; } - bAltSetting = as.bAlternateSetting; - if (bAltSetting > USB_MAXALTSETTING) { - printk(KERN_WARNING "usb: illegal bAlternateSetting %2u.\n", bAltSetting); + memcpy(ifp, buffer, USB_DT_INTERFACE_SIZE); + + /* Skip over the interface */ + buffer += ifp->bLength; + parsed += ifp->bLength; + size -= ifp->bLength; + + /* Skip over at Interface class or vendor descriptors */ + while (size >= sizeof(struct usb_descriptor_header)) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength < 2) { + printk(KERN_ERR "usb: invalid descriptor length of %d\n", header->bLength); + return -1; + } + + /* If we find another descriptor which is at or below us */ + /* in the descriptor heirarchy then return */ + if ((header->bDescriptorType == USB_DT_INTERFACE) || + (header->bDescriptorType == USB_DT_ENDPOINT)) + break; + + if ((header->bDescriptorType == USB_DT_CONFIG) || + (header->bDescriptorType == USB_DT_DEVICE)) + return parsed; + + if (header->bDescriptorType == USB_DT_HID) + printk(KERN_INFO "usb: skipping HID descriptor\n"); + else + printk(KERN_INFO "usb: unexpected descriptor 0x%X\n", + header->bDescriptorType); + + buffer += header->bLength; + parsed += header->bLength; + size -= header->bLength; + } + + if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { + printk(KERN_WARNING "usb: too many endpoints\n"); return -1; } - if (bAltSetting > config->interface[bIntfaceNum].num_altsetting) { - config->interface[bIntfaceNum].num_altsetting = bAltSetting +1; + + ifp->endpoint = (struct usb_endpoint_descriptor *) + kmalloc(ifp->bNumEndpoints * + sizeof(struct usb_endpoint_descriptor), GFP_KERNEL); + if (!ifp->endpoint) { + printk(KERN_WARNING "usb: out of memory\n"); + return -1; } - memcpy( &(config->interface[bIntfaceNum].altsetting[bAltSetting]), - &as, sizeof(struct usb_interface_descriptor)); + + memset(ifp->endpoint, 0, ifp->bNumEndpoints * + sizeof(struct usb_endpoint_descriptor)); + + for (i = 0; i < ifp->bNumEndpoints; i++) { + header = (struct usb_descriptor_header *)buffer; + + if (header->bLength > size) { + printk(KERN_ERR "usb: ran out of descriptors parsing\n"); + return -1; + } + + retval = usb_parse_endpoint(dev, ifp->endpoint + i, buffer, size); + if (retval < 0) + return retval; + + buffer += retval; + parsed += retval; + size -= retval; + } + + /* We check to see if it's an alternate to this one */ + ifp = (struct usb_interface_descriptor *)buffer; + if (size < USB_DT_INTERFACE_SIZE || + ifp->bDescriptorType != USB_DT_INTERFACE || + !ifp->bAlternateSetting) + return parsed; } - printk("parsed = %d len = %d\n", parsed, len); return parsed; } -int usb_parse_configuration(struct usb_device *dev, void *__buf, int bytes) +static int usb_parse_configuration(struct usb_device *dev, struct usb_config_descriptor *config, char *buffer) { int i; - unsigned char *ptr = __buf; + int retval; + int size; + struct usb_descriptor_header *header; - if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) { - printk(KERN_WARNING "usb: too many configurations.\n"); + memcpy(config, buffer, USB_DT_INTERFACE_SIZE); + + le16_to_cpus(&config->wTotalLength); + size = config->wTotalLength; + + if (config->bNumInterfaces > USB_MAXINTERFACES) { + printk(KERN_WARNING "usb: too many interfaces\n"); return -1; } - dev->config = (struct usb_config_descriptor *) - kmalloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor), GFP_KERNEL); - if (!dev->config) { - printk(KERN_WARNING "usb: out of memory.\n"); + config->interface = (struct usb_interface *) + kmalloc(config->bNumInterfaces * + sizeof(struct usb_interface), GFP_KERNEL); + if (!config->interface) { + printk(KERN_WARNING "usb: out of memory\n"); return -1; } - memset(dev->config, 0, dev->descriptor.bNumConfigurations*sizeof(struct usb_config_descriptor)); - for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { - int retval = usb_parse_config(dev, dev->config + i, ptr, bytes); + + memset(config->interface, 0, + config->bNumInterfaces*sizeof(struct usb_interface_descriptor)); + + buffer += config->bLength; + size -= config->bLength; + + for (i = 0; i < config->bNumInterfaces; i++) { + header = (struct usb_descriptor_header *)buffer; + if (header->bLength > size) { + printk(KERN_ERR "usb: ran out of descriptors parsing\n"); + return -1; + } + + if (header->bDescriptorType != USB_DT_INTERFACE) { + printk(KERN_INFO "usb: unexpected descriptor 0x%X\n", + header->bDescriptorType); + + buffer += header->bLength; + size -= header->bLength; + continue; + } + + retval = usb_parse_interface(dev, config->interface + i, buffer, size); if (retval < 0) return retval; - ptr += retval; - bytes -= retval; + + buffer += retval; + size -= retval; } - if (bytes) - printk(KERN_WARNING "usb: %d bytes of extra configuration data left\n", bytes); - return 0; + + return size; } void usb_destroy_configuration(struct usb_device *dev) { - int c, a, i; - struct usb_config_descriptor *cf; - struct usb_interface *intf; - struct usb_interface_descriptor *as; + int c, i, j; if (!dev->config) return; for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { - cf = &dev->config[c]; + struct usb_config_descriptor *cf = &dev->config[c]; + if (!cf->interface) break; - for (a = 0; a < cf->bNumInterfaces; a++) { - intf = &cf->interface[a]; - if (intf->altsetting == NULL) + + for (i = 0; i < cf->bNumInterfaces; i++) { + struct usb_interface *ifp = + &cf->interface[i]; + + if (!ifp->altsetting) break; - for(i=0; i <= USB_MAXALTSETTING ;i++) { - as = &intf->altsetting[i]; - if(as->endpoint==NULL) - break; + + for (j = 0; j < ifp->num_altsetting; j++) { + struct usb_interface_descriptor *as = + &ifp->altsetting[j]; + + if (!as->endpoint) + break; + kfree(as->endpoint); } - kfree(intf->altsetting); + kfree(ifp->altsetting); } kfree(cf->interface); } @@ -531,29 +539,33 @@ void usb_init_root_hub(struct usb_device *dev) void usb_disconnect(struct usb_device **pdev) { struct usb_device * dev = *pdev; + int i; - if (dev) { - int i; - - *pdev = NULL; + if (!dev) + return; - printk("USB disconnect on device %d\n", dev->devnum); + *pdev = NULL; - if(dev->driver) dev->driver->disconnect(dev); + printk("USB disconnect on device %d\n", dev->devnum); - /* Free up all the children.. */ - for (i = 0; i < USB_MAXCHILDREN; i++) { - struct usb_device **child = dev->children + i; - usb_disconnect(child); - } + if (dev->driver) + dev->driver->disconnect(dev); - /* Free up the device itself, including its device number */ - if (dev->devnum > 0) - clear_bit(dev->devnum, &dev->bus->devmap.devicemap); - dev->bus->op->deallocate(dev); + /* Free up all the children.. */ + for (i = 0; i < USB_MAXCHILDREN; i++) { + struct usb_device **child = dev->children + i; + usb_disconnect(child); } -} + /* remove /proc/bus/usb entry */ + proc_usb_remove_device(dev); + + /* Free up the device itself, including its device number */ + if (dev->devnum > 0) + clear_bit(dev->devnum, &dev->bus->devmap.devicemap); + + usb_free_dev(dev); +} /* * Connect a new USB device. This basically just initializes @@ -704,12 +716,13 @@ int usb_set_idle(struct usb_device *dev, int duration, int report_id) static void usb_set_maxpacket(struct usb_device *dev) { int i, j; - struct usb_interface *intf; + struct usb_interface *ifp; for (i=0; iactconfig->bNumInterfaces; i++) { - intf = (dev->actconfig->interface) +i; - for (j = 0; j < intf->num_altsetting; j++) { - struct usb_interface_descriptor *as = intf->altsetting +j; + ifp = dev->actconfig->interface + i; + + for (j = 0; j < ifp->num_altsetting; j++) { + struct usb_interface_descriptor *as = ifp->altsetting + j; struct usb_endpoint_descriptor *ep = as->endpoint; int e; @@ -718,7 +731,7 @@ static void usb_set_maxpacket(struct usb_device *dev) dev->epmaxpacketout[ep[e].bEndpointAddress & 0x0f] = ep[e].wMaxPacketSize; else - dev->epmaxpacketin[ep[e].bEndpointAddress & 0x0f] = + dev->epmaxpacketin [ep[e].bEndpointAddress & 0x0f] = ep[e].wMaxPacketSize; } } @@ -823,60 +836,78 @@ int usb_set_configuration(struct usb_device *dev, int configuration) return 0; } -int usb_get_report(struct usb_device *dev) +int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size) { - unsigned char buf[8]; devrequest dr; dr.requesttype = USB_RT_HIDD | 0x80; dr.request = USB_REQ_GET_REPORT; - dr.value = 0x100; - dr.index = 1; - dr.length = 3; + dr.value = (type << 8) + id; + dr.index = index; + dr.length = size; - if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 3)) + if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, size)) return -1; - return buf[0]; + return 0; } int usb_get_configuration(struct usb_device *dev) { unsigned int cfgno; - unsigned char * bufptr; - unsigned char * buffer; - int parse; + unsigned char buffer[8]; + unsigned char *bigbuffer; + struct usb_config_descriptor *desc = + (struct usb_config_descriptor *)buffer; - buffer = (unsigned char *) __get_free_page (GFP_KERNEL); - if (!buffer) + if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) { + printk(KERN_WARNING "usb: too many configurations\n"); return -1; + } - bufptr = buffer; - for (cfgno = 0 ; cfgno < dev->descriptor.bNumConfigurations ; cfgno++) { - unsigned int size; - /* Get the first 8 bytes - guaranteed */ - if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, 8)) { - __free_page ((struct page *) buffer); + dev->config = (struct usb_config_descriptor *) + kmalloc(dev->descriptor.bNumConfigurations * + sizeof(struct usb_config_descriptor), GFP_KERNEL); + if (!dev->config) { + printk(KERN_WARNING "usb: out of memory.\n"); + return -1; + } + memset(dev->config, 0, dev->descriptor.bNumConfigurations * + sizeof(struct usb_config_descriptor)); + + for (cfgno = 0; cfgno < dev->descriptor.bNumConfigurations; cfgno++) { + int result; + + /* We grab the first 8 bytes so we know how long the whole */ + /* configuration is */ + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8); + if (result) return -1; - } /* Get the full buffer */ - size = le16_to_cpup((unsigned short *)(bufptr+2)); - if (bufptr+size > buffer+PAGE_SIZE) { - printk(KERN_INFO "usb: truncated DT_CONFIG (want %d).\n", size); - size = buffer+PAGE_SIZE-bufptr; - } - if (usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bufptr, size)) { - __free_page ((struct page *) buffer); + le16_to_cpus(&desc->wTotalLength); + + bigbuffer = kmalloc(desc->wTotalLength, GFP_KERNEL); + if (!bigbuffer) + return -1; + + /* Now that we know the length, get the whole thing */ + result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, desc->wTotalLength); + if (result) { + kfree(bigbuffer); return -1; } - /* Prepare for next configuration */ - bufptr += size; + result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer); + kfree(bigbuffer); + + if (result > 0) + printk(KERN_INFO "usb: descriptor data left\n"); + else if (result < 0) + return -1; } - parse = usb_parse_configuration(dev, buffer, bufptr - buffer); - __free_page ((struct page *) buffer); - return parse; + + return 0; } @@ -903,14 +934,15 @@ char *usb_string(struct usb_device *dev, int index) dev->string_langid |= 0x10000; /* so it's non-zero */ } - if (usb_get_string(dev, dev->string_langid, index, u.buffer, 2) - || usb_get_string(dev, dev->string_langid, index, u.buffer, + if (usb_get_string(dev, dev->string_langid, index, u.buffer, 2) || + usb_get_string(dev, dev->string_langid, index, u.buffer, u.desc.bLength)) return 0; len = u.desc.bLength / 2; /* includes terminating null */ + ptr = kmalloc(len, GFP_KERNEL); - if (ptr == 0) + if (!ptr) return 0; for (i = 0; i < len - 1; ++i) @@ -943,7 +975,7 @@ int usb_new_device(struct usb_device *dev) /* Slow devices */ if (usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8)) { - printk(KERN_ERR "USB device not responding, giving up\n"); + printk(KERN_ERR "usbcore: USB device not responding, giving up\n"); dev->devnum = -1; return 1; } @@ -960,7 +992,7 @@ int usb_new_device(struct usb_device *dev) dev->devnum = addr; if (usb_set_address(dev)) { - printk(KERN_ERR "USB device not accepting new address\n"); + printk(KERN_ERR "usbcore: USB device not accepting new address\n"); dev->devnum = -1; return 1; } @@ -968,13 +1000,13 @@ int usb_new_device(struct usb_device *dev) wait_ms(10); /* Let the SET_ADDRESS settle */ if (usb_get_device_descriptor(dev)) { - printk(KERN_ERR "Unable to get device descriptor\n"); + printk(KERN_ERR "usbcore: unable to get device descriptor\n"); dev->devnum = -1; return 1; } if (usb_get_configuration(dev)) { - printk(KERN_ERR "Unable to get configuration\n"); + printk(KERN_ERR "usbcore: unable to get configuration\n"); dev->devnum = -1; return 1; } @@ -987,6 +1019,9 @@ int usb_new_device(struct usb_device *dev) usb_show_string(dev, "Product", dev->descriptor.iProduct); usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber); + /* now that the basic setup is over, add a /proc/bus/usb entry */ + proc_usb_add_device(dev); + if (!usb_find_driver(dev)) { /* * Ok, no driver accepted the device, so show the info for @@ -999,7 +1034,21 @@ int usb_new_device(struct usb_device *dev) return 0; } -void* usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) +int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size) +{ + devrequest dr; + + dr.requesttype = requesttype; + dr.request = request; + dr.value = cpu_to_le16p(&value); + dr.index = cpu_to_le16p(&index); + dr.length = cpu_to_le16p(&size); + + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, + data, size); +} + +void *usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) { return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id); } @@ -1014,44 +1063,56 @@ int usb_terminate_bulk(struct usb_device *dev, void *first) return dev->bus->op->terminate_bulk(dev, first); } -void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id) +int usb_release_irq(struct usb_device *dev, void *handle) { - return usb_dev->bus->op->alloc_isoc (usb_dev, pipe, data, len, maxsze, completed, dev_id); + return dev->bus->op->release_irq(dev, handle); } -void usb_delete_isochronous (struct usb_device *dev, void *_isodesc) +/* + * usb_get_current_frame_number() + * + * returns the current frame number for the parent USB bus/controller + * of the given USB device. + */ +int usb_get_current_frame_number (struct usb_device *usb_dev) { - return dev->bus->op->delete_isoc (dev, _isodesc); + return usb_dev->bus->op->get_frame_number (usb_dev); } -int usb_schedule_isochronous (struct usb_device *usb_dev, void *_isodesc, void *_pisodesc) +int usb_init_isoc (struct usb_device *usb_dev, + unsigned int pipe, + int frame_count, + void *context, + struct usb_isoc_desc **isocdesc) { - return usb_dev->bus->op->sched_isoc (usb_dev, _isodesc, _pisodesc); + return usb_dev->bus->op->init_isoc (usb_dev, pipe, frame_count, context, isocdesc); } -int usb_unschedule_isochronous (struct usb_device *usb_dev, void *_isodesc) +void usb_free_isoc (struct usb_isoc_desc *isocdesc) { - return usb_dev->bus->op->unsched_isoc (usb_dev, _isodesc); + isocdesc->usb_dev->bus->op->free_isoc (isocdesc); } -int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc) +int usb_run_isoc (struct usb_isoc_desc *isocdesc, + struct usb_isoc_desc *pr_isocdesc) { - return usb_dev->bus->op->compress_isoc (usb_dev, _isodesc); + return isocdesc->usb_dev->bus->op->run_isoc (isocdesc, pr_isocdesc); } -int usb_release_irq(struct usb_device *dev, void* handle) +int usb_kill_isoc (struct usb_isoc_desc *isocdesc) { - return dev->bus->op->release_irq(dev, handle); + return isocdesc->usb_dev->bus->op->kill_isoc (isocdesc); } #ifdef CONFIG_PROC_FS -struct list_head * usb_driver_get_list (void) +struct list_head *usb_driver_get_list(void) { return &usb_driver_list; } -struct list_head * usb_bus_get_list (void) +struct list_head *usb_bus_get_list(void) { return &usb_bus_list; } #endif + diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h index fda4d7fcd79a..cf0e40e61df7 100644 --- a/drivers/usb/usb.h +++ b/drivers/usb/usb.h @@ -12,7 +12,7 @@ extern int usb_cpia_init(void); extern int usb_mouse_init(void); extern int usb_printer_init(void); -extern void hub_cleanup(void); +extern void usb_hub_cleanup(void); extern void usb_mouse_cleanup(void); static __inline__ void wait_ms(unsigned int ms) @@ -21,14 +21,13 @@ static __inline__ void wait_ms(unsigned int ms) schedule_timeout(1 + ms * HZ / 1000); } - typedef struct { - unsigned char requesttype; - unsigned char request; - unsigned short value; - unsigned short index; - unsigned short length; -} devrequest; + __u8 requesttype; + __u8 request; + __u16 value; + __u16 index; + __u16 length; +} devrequest __attribute__ ((packed)); /* * Device and/or Interface Class codes @@ -40,6 +39,7 @@ typedef struct { #define USB_CLASS_PRINTER 7 #define USB_CLASS_MASS_STORAGE 8 #define USB_CLASS_HUB 9 +#define USB_CLASS_DATA 10 #define USB_CLASS_VENDOR_SPEC 0xff /* @@ -53,6 +53,8 @@ typedef struct { #define USB_DT_HUB 0x29 #define USB_DT_HID 0x21 +#define USB_DT_REPORT 0x22 +#define USB_DT_PHYSICAL 0x23 /* * Descriptor sizes per descriptor type @@ -61,7 +63,7 @@ typedef struct { #define USB_DT_CONFIG_SIZE 9 #define USB_DT_INTERFACE_SIZE 9 #define USB_DT_ENDPOINT_SIZE 7 -#define USB_DT_AUCLSTEP_SIZE 9 /* Audio Classes are special */ +#define USB_DT_ENDPOINT_AUDIO_SIZE 9 /* Audio extension */ #define USB_DT_HUB_NONVAR_SIZE 7 /* @@ -114,6 +116,10 @@ typedef struct { #define USB_RECIP_ENDPOINT 0x02 #define USB_RECIP_OTHER 0x03 +#define USB_HID_RPT_INPUT 0x01 +#define USB_HID_RPT_OUTPUT 0x02 +#define USB_HID_RPT_FEATURE 0x03 + /* * Request target types. */ @@ -127,7 +133,7 @@ typedef struct { #define USB_RT_HIDD (USB_TYPE_CLASS | USB_RECIP_INTERFACE) /* - * Status codes (these follow an OHCI controllers condition codes) + * Status codes (these follow OHCI controllers condition codes) */ #define USB_ST_NOERROR 0x0 #define USB_ST_CRC 0x1 @@ -151,6 +157,7 @@ typedef struct { #define USB_ST_TIMEOUT 0x110 #define USB_ST_INTERNALERROR -1 #define USB_ST_NOTSUPPORTED -2 +#define USB_ST_BANDWIDTH_ERROR -3 /* * USB device number allocation bitmap. There's one bitmap @@ -164,14 +171,21 @@ struct usb_devmap { * This is a USB device descriptor. * * USB device information - * */ +/* Everything but the endpoint maximums are aribtrary */ #define USB_MAXCONFIG 8 -#define USB_MAXALTSETTING 6 +#define USB_MAXALTSETTING 16 #define USB_MAXINTERFACES 32 #define USB_MAXENDPOINTS 32 +/* All standard descriptors have these 2 fields in common */ +struct usb_descriptor_header { + __u8 bLength; + __u8 bDescriptorType; +} __attribute__ ((packed)); + +/* Device descriptor */ struct usb_device_descriptor { __u8 bLength; __u8 bDescriptorType; @@ -187,7 +201,7 @@ struct usb_device_descriptor { __u8 iProduct; __u8 iSerialNumber; __u8 bNumConfigurations; -}; +} __attribute__ ((packed)); /* Endpoint descriptor */ struct usb_endpoint_descriptor { @@ -199,8 +213,23 @@ struct usb_endpoint_descriptor { __u8 bInterval; __u8 bRefresh; __u8 bSynchAddress; - void *audio; -}; +} __attribute__ ((packed)); + +/* HID descriptor */ +struct usb_hid_class_descriptor { + __u8 bDescriptorType; + __u16 wDescriptorLength; +} __attribute__ ((packed)); + +struct usb_hid_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u16 bcdHID; + __u8 bCountryCode; + __u8 bNumDescriptors; + + struct usb_hid_class_descriptor desc[1]; +} __attribute__ ((packed)); /* Interface descriptor */ struct usb_interface_descriptor { @@ -214,14 +243,15 @@ struct usb_interface_descriptor { __u8 bInterfaceProtocol; __u8 iInterface; + struct usb_hid_descriptor *hid; struct usb_endpoint_descriptor *endpoint; - void *audio; -}; +} __attribute__ ((packed)); struct usb_interface { - struct usb_interface_descriptor *altsetting; - int act_altsetting; /* active alternate setting */ - int num_altsetting; /* number of alternate settings */ + struct usb_interface_descriptor *altsetting; + + int act_altsetting; /* active alternate setting */ + int num_altsetting; /* number of alternate settings */ }; /* Configuration descriptor information.. */ @@ -234,35 +264,25 @@ struct usb_config_descriptor { __u8 iConfiguration; __u8 bmAttributes; __u8 MaxPower; + struct usb_interface *interface; -}; +} __attribute__ ((packed)); /* String descriptor */ struct usb_string_descriptor { __u8 bLength; __u8 bDescriptorType; __u16 wData[1]; -}; - -/* Hub descriptor */ -struct usb_hub_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bNbrPorts; - __u8 wHubCharacteristics[2]; /* __u16 but not aligned! */ - __u8 bPwrOn2PwrGood; - __u8 bHubContrCurrent; - /* DeviceRemovable and PortPwrCtrlMask want to be variable-length - bitmaps that hold max 256 entries, but for now they're ignored */ - __u8 filler; -}; +} __attribute__ ((packed)); struct usb_device; struct usb_driver { - const char * name; + const char *name; + int (*probe)(struct usb_device *); void (*disconnect)(struct usb_device *); + struct list_head driver_list; }; @@ -284,21 +304,97 @@ struct usb_driver { */ typedef int (*usb_device_irq)(int, void *, int, void *); +/* + * Isoc. support additions + */ +#define START_FRAME_FUDGE 3 + +/* for start_type: */ +enum { + START_ASAP = 0, + START_ABSOLUTE, + START_RELATIVE +}; +#define START_TYPE_MAX START_RELATIVE + +/* + * Completion/Callback routine returns an enum, + * which tells the interrupt handler what to do + * with the completed frames (TDs). + */ +enum { + CB_CONTINUE = 0, /* OK, remove all TDs; + needs to be 0 to be consistent with + current callback function ret. values */ + CB_REUSE, /* leave descriptors as NULL, not active */ + CB_RESTART, /* leave descriptors as they are, alive */ + CB_ABORT /* kill this USB transfer request */ +}; + +struct isoc_frame_desc { + int frame_length; /* may be 0 (i.e., allowed) */ + /* set by driver for OUTs to devices; + * set by USBD for INs from devices, + * after I/O complete */ + unsigned int frame_status; + /* set by USBD after I/O complete */ +}; + +struct usb_isoc_desc { + /* + * The following fields are set by the usb_init_isoc() call. + */ + struct usb_device *usb_dev; + unsigned int pipe; + int frame_count; + void *context; /* driver context (private) ptr */ + int frame_size; + /* + * The following fields are set by the driver between the + * usb_init_isoc() and usb_run_isoc() calls + * (along with the "frames" array for OUTput). + */ + int start_type; + int start_frame; /* optional, depending on start_type */ + int frame_spacing; /* not using (yet?) */ + int callback_frames; /* every # frames + last one */ + /* 0 means no callbacks until IOC on last frame */ + usb_device_irq callback_fn; + void *data; + int buf_size; + /* + * The following fields are set by the usb_run_isoc() call. + */ + int end_frame; + void *td; /* UHCI or OHCI TD ptr */ + /* + * The following fields are set by the USB HCD interrupt handler + * before calling the driver's callback function. + */ + int total_completed_frames; + int prev_completed_frame; /* from the previous callback */ + int cur_completed_frame; /* from this callback */ + int total_length; /* accumulated */ + int error_count; /* accumulated */ + struct isoc_frame_desc frames [0]; /* variable size: [frame_count] */ +}; + struct usb_operations { - struct usb_device *(*allocate)(struct usb_device *); + int (*allocate)(struct usb_device *); int (*deallocate)(struct usb_device *); int (*control_msg)(struct usb_device *, unsigned int, devrequest *, void *, int); int (*bulk_msg)(struct usb_device *, unsigned int, void *, int,unsigned long *); - void* (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *); - int (*release_irq)(struct usb_device *, void* handle); + void *(*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *); + int (*release_irq)(struct usb_device *, void *); void *(*request_bulk)(struct usb_device *, unsigned int, usb_device_irq, void *, int, void *); int (*terminate_bulk)(struct usb_device *, void *); - void *(*alloc_isoc)(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int maxsze, usb_device_irq completed, void *dev_id); - void (*delete_isoc)(struct usb_device *dev, void *_isodesc); - int (*sched_isoc)(struct usb_device *usb_dev, void *_isodesc, void *_pisodesc); - int (*unsched_isoc)(struct usb_device *usb_dev, void *_isodesc); - int (*compress_isoc)(struct usb_device *usb_dev, void *_isodesc); + int (*get_frame_number) (struct usb_device *usb_dev); + int (*init_isoc) (struct usb_device *usb_dev, unsigned int pipe, + int frame_count, void *context, struct usb_isoc_desc **isocdesc); + void (*free_isoc) (struct usb_isoc_desc *isocdesc); + int (*run_isoc) (struct usb_isoc_desc *isocdesc, struct usb_isoc_desc *pr_isocdesc); + int (*kill_isoc) (struct usb_isoc_desc *isocdesc); }; /* @@ -310,14 +406,20 @@ struct usb_bus { struct usb_device *root_hub; /* Root hub */ struct list_head bus_list; void *hcpriv; /* Host Controller private data */ -}; + /* procfs entry */ + int proc_busnum; + struct proc_dir_entry *proc_entry; +}; -#define USB_MAXCHILDREN (8) +#define USB_MAXCHILDREN (8) /* This is arbitrary */ struct usb_device { int devnum; /* Device number on USB bus */ int slow; /* Slow device? */ + + atomic_t refcnt; /* Reference count */ + int maxpacketsize; /* Maximum packet size; encoded as 0,1,2,3 = 8,16,32,64 */ unsigned int toggle[2]; /* one bit for each endpoint ([0] = IN, [1] = OUT) */ unsigned int halted[2]; /* endpoint halts; one bit per endpoint # & direction; */ @@ -326,14 +428,23 @@ struct usb_device { int epmaxpacketin[16]; /* INput endpoint specific maximums */ int epmaxpacketout[16]; /* OUTput endpoint specific maximums */ int ifnum; /* active interface number */ + + struct usb_device *parent; struct usb_bus *bus; /* Bus we're part of */ struct usb_driver *driver; /* Driver */ + struct usb_device_descriptor descriptor;/* Descriptor */ struct usb_config_descriptor *config; /* All of the configs */ - struct usb_device *parent; + char *string; /* pointer to the last string read from the device */ int string_langid; /* language ID for strings */ + void *hcpriv; /* Host Controller private data */ + void *private; /* Upper layer private data */ + + /* procfs entry */ + struct proc_dir_entry *proc_entry; + /* * Child devices - these can be either new devices * (if this is a hub device), or different instances @@ -344,20 +455,28 @@ struct usb_device { int maxchild; /* Number of ports if hub */ struct usb_device *children[USB_MAXCHILDREN]; - - void *hcpriv; /* Host Controller private data */ - void *private; /* Upper layer private data */ }; extern int usb_register(struct usb_driver *); extern void usb_deregister(struct usb_driver *); +int usb_find_driver(struct usb_device *); +void usb_check_support(struct usb_device *); +void usb_driver_purge(struct usb_driver *, struct usb_device *); + extern struct usb_bus *usb_alloc_bus(struct usb_operations *); extern void usb_free_bus(struct usb_bus *); extern void usb_register_bus(struct usb_bus *); extern void usb_deregister_bus(struct usb_bus *); -extern void* usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *); +extern struct usb_device *usb_alloc_dev(struct usb_device *parent, struct usb_bus *); +extern void usb_free_dev(struct usb_device *); +extern void usb_inc_dev_use(struct usb_device *); +#define usb_dec_dev_use usb_free_dev + +extern int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype, __u16 value, __u16 index, void *data, __u16 size); + +extern void *usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *); extern int usb_release_irq(struct usb_device *dev, void *handle); extern void *usb_request_bulk(struct usb_device *, unsigned int, usb_device_irq, void *, int, void *); @@ -367,10 +486,6 @@ extern void usb_init_root_hub(struct usb_device *dev); extern void usb_connect(struct usb_device *dev); extern void usb_disconnect(struct usb_device **); -extern int usb_find_driver(struct usb_device *dev); -void usb_check_support(struct usb_device *); -void usb_driver_purge(struct usb_driver *,struct usb_device *); -extern int usb_parse_configuration(struct usb_device *dev, void *buf, int len); extern void usb_destroy_configuration(struct usb_device *dev); extern void *usb_allocate_isochronous (struct usb_device *usb_dev, unsigned int pipe, void *data, int len, @@ -380,6 +495,21 @@ extern int usb_schedule_isochronous (struct usb_device *usb_dev, void *_isodesc, extern int usb_unschedule_isochronous (struct usb_device *usb_dev, void *_isodesc); extern int usb_compress_isochronous (struct usb_device *usb_dev, void *_isodesc); +int usb_get_current_frame_number (struct usb_device *usb_dev); + +int usb_init_isoc (struct usb_device *usb_dev, + unsigned int pipe, + int frame_count, + void *context, + struct usb_isoc_desc **isocdesc); + +void usb_free_isoc (struct usb_isoc_desc *isocdesc); + +int usb_run_isoc (struct usb_isoc_desc *isocdesc, + struct usb_isoc_desc *pr_isocdesc); + +int usb_kill_isoc (struct usb_isoc_desc *isocdesc); + /* * Calling this entity a "pipe" is glorifying it. A USB pipe * is something embarrassingly simple: it basically consists @@ -479,7 +609,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate); int usb_set_idle(struct usb_device *dev, int duration, int report_id); int usb_set_interface(struct usb_device *dev, int interface, int alternate); int usb_set_configuration(struct usb_device *dev, int configuration); -int usb_get_report(struct usb_device *dev); +int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size); char *usb_string(struct usb_device *dev, int index); int usb_clear_halt(struct usb_device *dev, int endp); @@ -489,21 +619,25 @@ int usb_clear_halt(struct usb_device *dev, int endp); void usb_show_device_descriptor(struct usb_device_descriptor *); void usb_show_config_descriptor(struct usb_config_descriptor *); void usb_show_interface_descriptor(struct usb_interface_descriptor *); +void usb_show_hid_descriptor(struct usb_hid_descriptor * desc); void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *); -void usb_show_hub_descriptor(struct usb_hub_descriptor *); void usb_show_device(struct usb_device *); -void usb_show_string(struct usb_device* dev, char *id, int index); +void usb_show_string(struct usb_device *dev, char *id, int index); /* - * Audio parsing helpers + * procfs stuff */ -#ifdef CONFIG_USB_AUDIO -void usb_audio_interface(struct usb_interface_descriptor *, u8 *); -void usb_audio_endpoint(struct usb_endpoint_descriptor *, u8 *); +#ifdef CONFIG_USB_PROC +void proc_usb_add_bus(struct usb_bus *bus); +void proc_usb_remove_bus(struct usb_bus *bus); +void proc_usb_add_device(struct usb_device *dev); +void proc_usb_remove_device(struct usb_device *dev); #else -extern inline void usb_audio_interface(struct usb_interface_descriptor *interface, u8 *data) {} -extern inline void usb_audio_endpoint(struct usb_endpoint_descriptor *interface, u8 *data) {} +extern inline void proc_usb_add_bus(struct usb_bus *bus) {} +extern inline void proc_usb_remove_bus(struct usb_bus *bus) {} +extern inline void proc_usb_add_device(struct usb_device *dev) {} +extern inline void proc_usb_remove_device(struct usb_device *dev) {} #endif #endif diff --git a/drivers/usb/usb_scsi.c b/drivers/usb/usb_scsi.c index fcd5f5da5ea3..7752d5bd41f3 100644 --- a/drivers/usb/usb_scsi.c +++ b/drivers/usb/usb_scsi.c @@ -1108,9 +1108,9 @@ static int scsi_probe(struct usb_device *dev) protocol = US_PR_CB; subclass = US_SC_8070; /* an assumption */ } else if (dev->descriptor.bDeviceClass != 0 || - dev->config->interface->altsetting->bInterfaceClass != 8 || - dev->config->interface->altsetting->bInterfaceSubClass < US_SC_MIN || - dev->config->interface->altsetting->bInterfaceSubClass > US_SC_MAX) { + dev->config[0].interface[0].altsetting[0].bInterfaceClass != 8 || + dev->config[0].interface[0].altsetting[0].bInterfaceSubClass < US_SC_MIN || + dev->config[0].interface[0].altsetting[0].bInterfaceSubClass > US_SC_MAX) { return -1; } @@ -1143,7 +1143,7 @@ static int scsi_probe(struct usb_device *dev) memset(ss, 0, sizeof(struct us_data)); } - interface = dev->config->interface->altsetting; + interface = &dev->config[0].interface[0].altsetting[0]; ss->filter = filter; ss->fdata = fdata; ss->flags = flags; diff --git a/drivers/usb/uss720.c b/drivers/usb/uss720.c index 3454cf6b943d..5d7421694109 100644 --- a/drivers/usb/uss720.c +++ b/drivers/usb/uss720.c @@ -36,7 +36,6 @@ /*****************************************************************************/ -#include #include #include #include @@ -561,8 +560,8 @@ static int uss720_probe(struct usb_device *usbdev) usbdev->descriptor.idVendor, usbdev->descriptor.idProduct); if ((usbdev->descriptor.idVendor != 0x047e || usbdev->descriptor.idProduct != 0x1001) && - (usbdev->descriptor.idVendor != 0x0557 || usbdev->descriptor.idProduct != 0x2001) && - (usbdev->descriptor.idVendor != 0x0729 || usbdev->descriptor.idProduct != 0x1284)) + (usbdev->descriptor.idVendor != 0x0557 || usbdev->descriptor.idProduct != 0x2001) && + (usbdev->descriptor.idVendor != 0x0729 || usbdev->descriptor.idProduct != 0x1284)) return -1; /* We don't handle multiple configurations */ diff --git a/drivers/video/Config.in b/drivers/video/Config.in index 13c1af45d114..339dc6d9f0e6 100644 --- a/drivers/video/Config.in +++ b/drivers/video/Config.in @@ -7,7 +7,7 @@ if [ "$CONFIG_FB" = "y" ]; then if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then if [ "$CONFIG_AMIGA" = "y" -o "$CONFIG_PCI" = "y" ]; then tristate 'Cirrus Logic suport (experimental)' CONFIG_FB_CLGEN - bool 'Permedia2 support (experimental)' CONFIG_FB_PM2 + tristate 'Permedia2 support (experimental)' CONFIG_FB_PM2 if [ "$CONFIG_FB_PM2" = "y" ]; then if [ "$CONFIG_PCI" = "y" ]; then bool ' enable FIFO disconnect feature' CONFIG_FB_PM2_FIFO_DISCONNECT diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 923ca5238f45..8a7c9853f317 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -82,6 +82,11 @@ endif ifeq ($(CONFIG_FB_PM2),y) L_OBJS += pm2fb.o CONFIG_FBGEN_BUILTIN = y +else + ifeq ($(CONFIG_FB_PM2),m) + M_OBJS += pm2fb.o + CONFIG_FBGEN_MODULE = y + endif endif ifeq ($(CONFIG_FB_APOLLO),y) diff --git a/drivers/video/atyfb.c b/drivers/video/atyfb.c index 68dab49ff42a..425199739c54 100644 --- a/drivers/video/atyfb.c +++ b/drivers/video/atyfb.c @@ -390,7 +390,9 @@ int atyfb_init(void); #ifdef CONFIG_FB_OF void atyfb_of_init(struct device_node *dp); #endif +#ifndef MODULE int atyfb_setup(char*); +#endif static int currcon = 0; @@ -411,7 +413,10 @@ static char noaccel __initdata = 0; static u32 default_vram __initdata = 0; static int default_pll __initdata = 0; static int default_mclk __initdata = 0; + +#ifndef MODULE static const char *mode_option __initdata = NULL; +#endif #if defined(CONFIG_PPC) static int default_vmode __initdata = VMODE_NVRAM; @@ -2869,7 +2874,7 @@ int __init atyfb_init(void) memset(info, 0, sizeof(struct fb_info_aty)); rp = &pdev->resource[0]; - if (rp->flags & IORESOURCE_IOPORT) + if (rp->flags & IORESOURCE_IO) rp = &pdev->resource[1]; addr = rp->start; if (!addr) @@ -2912,7 +2917,7 @@ int __init atyfb_init(void) base = rp->start; - io = (rp->flags & IORESOURCE_IOPORT); + io = (rp->flags & IORESOURCE_IO); size = rp->end - base + 1; @@ -3261,6 +3266,7 @@ void __init atyfb_of_init(struct device_node *dp) #endif /* CONFIG_FB_OF */ +#ifndef MODULE int __init atyfb_setup(char *options) { char *this_opt; @@ -3328,9 +3334,12 @@ int __init atyfb_setup(char *options) } } #endif + else + mode_option = this_opt; } return 0; } +#endif /* !MODULE */ #ifdef CONFIG_ATARI static int __init store_video_par(char *video_str, unsigned char m64_num) diff --git a/drivers/video/clgenfb.c b/drivers/video/clgenfb.c index c6d650463977..3009529aa416 100644 --- a/drivers/video/clgenfb.c +++ b/drivers/video/clgenfb.c @@ -31,8 +31,9 @@ * */ -#define CLGEN_VERSION "1.9.4.2" +#define CLGEN_VERSION "1.9.4.3" +#include #include #include #include @@ -324,6 +325,8 @@ struct clgenfb_info { #ifdef CONFIG_ZORRO int keyRAM; /* RAM, REG zorro board keys */ int keyREG; + unsigned long board_addr, + board_size; #endif #ifdef CONFIG_PCI @@ -338,7 +341,9 @@ static struct display disp; static struct clgenfb_info boards[MAX_NUM_BOARDS]; /* the boards */ -static unsigned clgen_def_mode = 0; +static unsigned clgen_def_mode = 1; + +static int release_io_ports = 0; @@ -1787,12 +1792,16 @@ static void __init init_vgachip (struct clgenfb_info *fb_info) break; } +#ifdef CLGEN_USE_HARDCODED_RAM_SETTINGS /* "pre-set" a RAMsize; if the test succeeds, double it */ if (fb_info->btype == BT_SD64 || fb_info->btype == BT_PICASSO4) fb_info->size = 0x400000; else fb_info->size = 0x200000; +#else + assert (fb_info->size > 0); /* make sure RAM size set by this point */ +#endif /* assume it's a "large memory" board (2/4 MB) */ fb_info->smallboard = FALSE; @@ -2362,7 +2371,7 @@ static void __init get_pci_addrs (const struct pci_dev *pdev, #else - if (pdev->resource[0].flags & IORESOURCE_IOPORT) { + if (pdev->resource[0].flags & IORESOURCE_IO) { *display = pdev->resource[1].start; *registers = pdev->resource[0].start; } else { @@ -2380,6 +2389,21 @@ static void __init get_pci_addrs (const struct pci_dev *pdev, +/* clgen_pci_unmap only used in modules */ +#ifdef MODULE +static void clgen_pci_unmap (struct clgenfb_info *info) +{ + iounmap (info->fbmem); +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) + __release_region (&iomem_resource, info->fbmem_phys, info->size); + __release_region (&iomem_resource, 0xA0000, 65535); + if (release_io_ports) + __release_region (&ioport_resource, 0x3C0, 32); +#endif +} +#endif /* MODULE */ + + static int __init clgen_pci_setup (struct clgenfb_info *info, clgen_board_t *btype) { @@ -2411,8 +2435,8 @@ static int __init clgen_pci_setup (struct clgenfb_info *info, pci_read_config_word (pdev, PCI_COMMAND, &tmp16); if (!(tmp16 & (PCI_COMMAND_MEMORY | PCI_COMMAND_IO))) { - tmp16 |= PCI_COMMAND_MEMORY | PCI_COMMAND_IO; - pci_write_config_word (pdev, PCI_COMMAND, tmp16); + u16 tmp16_o = tmp16 | PCI_COMMAND_MEMORY | PCI_COMMAND_IO; + pci_write_config_word (pdev, PCI_COMMAND, tmp16_o); } #ifdef CONFIG_FB_OF @@ -2453,10 +2477,33 @@ static int __init clgen_pci_setup (struct clgenfb_info *info, } else { board_size = clgen_get_memsize (info->regs); } + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) + + if (!__request_region (&iomem_resource, board_addr, + board_size, "clgenfb")) { + pci_write_config_word (pdev, PCI_COMMAND, tmp16); + printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n", + board_addr); + return -1; + } + if (!__request_region (&iomem_resource, 0xA0000, 65535, "clgenfb")) { + pci_write_config_word (pdev, PCI_COMMAND, tmp16); + printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n", + 0xA0000L); + __release_region(&iomem_resource, board_addr, board_size); + return -1; + } + if (__request_region(&ioport_resource, 0x3C0, 32, "clgenfb")) + release_io_ports = 1; + +#endif /* kernel > 2.3.13 */ + info->fbmem = ioremap (board_addr, board_size); info->fbmem_phys = board_addr; + info->size = board_size; - printk (" RAM (%lu MB) at $%lx, ", board_size / 0x100000, board_addr); + printk (" RAM (%lu MB) at 0x%lx, ", info->size / MB_, board_addr); printk (KERN_INFO "Cirrus Logic chipset on PCI bus\n"); @@ -2499,6 +2546,25 @@ static int __init clgen_zorro_find (int *key_o, int *key2_o, clgen_board_t *btyp +/* clgen_zorro_unmap only used in modules */ +#ifdef MODULE +static void clgen_zorro_unmap (struct clgenfb_info *info) +{ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,13) + __release_region(&iomem_resource, info->board_addr, info->board_size); +#endif + if (info->btype == BT_PICASSO4) { + iounmap (info->board_addr); + iounmap (info->fbmem_phys); + } else { + if (info->board_addr > 0x01000000) + iounmap (info->board_addr); + } +} +#endif /* MODULE */ + + + static int __init clgen_zorro_setup (struct clgenfb_info *info, clgen_board_t *btype) { @@ -2520,9 +2586,17 @@ static int __init clgen_zorro_setup (struct clgenfb_info *info, info->keyRAM = key; info->keyREG = key2; cd = zorro_get_board (key); - board_addr = (unsigned long) cd->cd_BoardAddr; - board_size = (unsigned long) cd->cd_BoardSize; - printk (" RAM (%lu MB) at $%lx, ", board_size / 0x100000, board_addr); + info->board_addr = board_addr = (unsigned long) cd->cd_BoardAddr; + info->board_size = board_size = (unsigned long) cd->cd_BoardSize; + + if (!__request_region(&iomem_resource, board_addr, + board_size, "clgenfb")) { + printk(KERN_ERR "clgen: cannot reserve region 0x%lu, abort\n", + board_addr); + return -1; + } + + printk (" RAM (%lu MB) at $%lx, ", board_size / MB_, board_addr); if (*btype == BT_PICASSO4) { printk (" REG at $%lx\n", board_addr + 0x600000); @@ -2683,9 +2757,13 @@ static void clgenfb_cleanup (struct clgenfb_info *info) #ifdef CONFIG_ZORRO switch_monitor (info, 0); + clgen_zorro_unmap (info); + zorro_unconfig_board (info->keyRAM, 0); if (info->btype != BT_PICASSO4) zorro_unconfig_board (info->keyREG, 0); +#else + clgen_pci_unmap (info); #endif /* CONFIG_ZORRO */ unregister_framebuffer ((struct fb_info *) info); diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index e333730c188e..0767c3b87c32 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c @@ -470,6 +470,14 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) return -ENODEV; if (fb->fb_mmap) return fb->fb_mmap(info, file, vma); + +#if defined(__sparc__) + /* Should never get here, all fb drivers should have their own + mmap routines */ + return -EINVAL; +#else + /* non-SPARC... */ + fb->fb_get_fix(&fix, PROC_CONSOLE(info), info); /* frame buffer memory */ @@ -505,9 +513,6 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE|_PAGE_GUARDED; #elif defined(__alpha__) /* Caching is off in the I/O space quadrant by design. */ -#elif defined(__sparc__) - /* Should never get here, all fb drivers should have their own - mmap routines */ #elif defined(__i386__) if (boot_cpu_data.x86 > 3) pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; @@ -528,6 +533,8 @@ fb_mmap(struct file *file, struct vm_area_struct * vma) vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; return 0; + +#endif /* defined(__sparc__) */ } static int diff --git a/drivers/video/matroxfb.c b/drivers/video/matroxfb.c index 1c27a49e91b0..999dbac30282 100644 --- a/drivers/video/matroxfb.c +++ b/drivers/video/matroxfb.c @@ -5152,7 +5152,10 @@ static unsigned int fv = 0; /* "matrox:fv:xxxxx" */ static unsigned int fh = 0; /* "matrox:fh:xxxxxk" */ static unsigned int maxclk = 0; /* "matrox:maxclk:xxxxM" */ static char fontname[64]; /* "matrox:font:xxxxx" */ + +#ifndef MODULE static char videomode[64]; /* "matrox:mode:xxxxx" or "matrox:xxxxx" */ +#endif #ifndef MODULE int __init matroxfb_setup(char *options) { @@ -5295,7 +5298,7 @@ int __init matroxfb_setup(char *options) { } return 0; } -#endif +#endif /* !MODULE */ static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int* realOffset, unsigned int *realSize){ vaddr_t vm; @@ -5884,7 +5887,7 @@ static int __init initMatrox2(WPMINFO struct display* d, struct board* b){ fb_find_mode(&vesafb_defined, &ACCESS_FBINFO(fbcon), videomode[0]?videomode:NULL, NULL, 0, &defaultmode, vesafb_defined.bits_per_pixel); } -#endif +#endif /* !MODULE */ /* mode modifiers */ if (hslen) diff --git a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c index 518d4e895b7b..343ad3f5228b 100644 --- a/drivers/video/pm2fb.c +++ b/drivers/video/pm2fb.c @@ -192,12 +192,12 @@ static struct pm2fb_info { int board; /* Permedia2 board index (see board_table[] below) */ struct { - unsigned char* fb_base; /* framebuffer memory base */ + unsigned long fb_base; /* physical framebuffer memory base */ u32 fb_size; /* framebuffer memory size */ - unsigned char* rg_base; /* register memory base */ - unsigned char* p_fb; /* physical address of frame buffer */ + unsigned long rg_base; /* physical register memory base */ + unsigned long p_fb; /* physical address of frame buffer */ unsigned char* v_fb; /* virtual address of frame buffer */ - unsigned char* p_regs; /* physical address of registers + unsigned long p_regs; /* physical address of registers region, must be rg_base or rg_base+PM2_REGS_SIZE depending on the host endianness */ @@ -750,13 +750,26 @@ static int __init pm2fb_conf(struct pm2fb_info* p){ return 0; } DPRINTK("found board: %s\n", board_table[p->board].name); + p->regions.p_fb=p->regions.fb_base; + if (!__request_region(&iomem_resource, p->regions.p_fb, + p->regions.fb_size, "pm2fb")) { + printk (KERN_ERR "pm2fb: cannot reserve fb memory, abort\n"); + return 0; + } p->regions.v_fb=MMAP(p->regions.p_fb, p->regions.fb_size); + #ifdef __LITTLE_ENDIAN p->regions.p_regs=p->regions.rg_base; #else p->regions.p_regs=p->regions.rg_base+PM2_REGS_SIZE; #endif + if (!__request_region(&iomem_resource, p->regions.p_regs, + PM2_REGS_SIZE, "pm2fb")) { + printk (KERN_ERR "pm2fb: cannot reserve mmio memory, abort\n"); + UNMAP(p->regions.v_fb, p->regions.fb_size); + return 0; + } p->regions.v_regs=MMAP(p->regions.p_regs, PM2_REGS_SIZE); return 1; } @@ -809,9 +822,9 @@ static int cvppc_detect(struct pm2fb_info* p) { if (!cvppc_PCI_init(&p->board_par.cvppc)) return 0; - p->regions.fb_base=(unsigned char* )CVPPC_FB_APERTURE_ONE; + p->regions.fb_base=CVPPC_FB_APERTURE_ONE; p->regions.fb_size=CVPPC_FB_SIZE; - p->regions.rg_base=(unsigned char* )CVPPC_REGS_REGION; + p->regions.rg_base=CVPPC_REGS_REGION; p->memclock=CVPPC_MEMCLOCK; return 1; } @@ -855,24 +868,18 @@ static int pm2pci_detect(struct pm2fb_info* p) { pci->dev->resource[0].start, pci->dev->resource[1].start, pci->dev->resource[2].start, - pci->dev->rom_address); + pci->dev->resource[PCI_ROM_RESOURCE].start); #ifdef __sparc__ - p->regions.rg_base=(unsigned char* ) - __pa(pci->dev->resource[0].start); - p->regions.fb_base=(unsigned char* ) - __pa(pci->dev->resource[1].start); + p->regions.rg_base= __pa(pci->dev->resource[0].start); + p->regions.fb_base= __pa(pci->dev->resource[1].start); #else if (pm2fb_options.flags & OPTF_VIRTUAL) { - p->regions.rg_base=(unsigned char* ) - __pa(pci->dev->resource[0].start); - p->regions.fb_base=(unsigned char* ) - __pa(pci->dev->resource[1].start); + p->regions.rg_base= __pa(pci->dev->resource[0].start); + p->regions.fb_base= __pa(pci->dev->resource[1].start); } else { - p->regions.rg_base=(unsigned char* ) - (pci->dev->resource[0].start); - p->regions.fb_base=(unsigned char* ) - (pci->dev->resource[0].start); + p->regions.rg_base= (pci->dev->resource[0].start); + p->regions.fb_base= (pci->dev->resource[0].start); } #endif #ifdef __BIG_ENDIAN @@ -1581,15 +1588,23 @@ static int pm2fb_release(struct fb_info* info, int user) { * Begin of public functions ***************************************************************************/ -void pm2fb_cleanup(struct fb_info* info) { - struct pm2fb_info* i=(struct pm2fb_info* )info; +#ifdef MODULE +static void pm2fb_cleanup(void) { + struct pm2fb_info* i = &fb_info; - unregister_framebuffer(info); + unregister_framebuffer((struct fb_info *)i); pm2fb_reset(i); - /* FIXME UNMAP()??? */ + + UNMAP(i->regions.v_fb, i->regions.fb_size); + __release_region(&iomem_resource, i->regions.p_fb, i->regions.fb_size); + + UNMAP(i->regions.v_regs, PM2_REGS_SIZE); + __release_region(&iomem_resource, i->regions.p_regs, PM2_REGS_SIZE); + if (board_table[i->board].cleanup) board_table[i->board].cleanup(i); } +#endif /* MODULE */ int __init pm2fb_init(void){ diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c index b808fd0a6b0b..bb98bd8c730b 100644 --- a/drivers/video/vesafb.c +++ b/drivers/video/vesafb.c @@ -41,7 +41,7 @@ */ /* card */ -char *video_base; +unsigned long video_base; /* physical addr */ int video_size; char *video_vbase; /* mapped */ @@ -530,7 +530,7 @@ int __init vesafb_init(void) if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return -ENXIO; - video_base = (char*)screen_info.lfb_base; + video_base = screen_info.lfb_base; video_bpp = screen_info.lfb_depth; video_width = screen_info.lfb_width; video_height = screen_info.lfb_height; @@ -538,9 +538,18 @@ int __init vesafb_init(void) video_size = screen_info.lfb_size * 65536; video_visual = (video_bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR; - video_vbase = ioremap((unsigned long)video_base, video_size); - printk(KERN_INFO "vesafb: framebuffer at 0x%p, mapped to 0x%p, size %dk\n", + if (!__request_region(&iomem_resource, video_base, video_size, + "vesafb")) { + printk(KERN_ERR + "vesafb: abort, cannot reserve video memory at 0x%lu\n", + video_base); + return -1; + } + + video_vbase = ioremap(video_base, video_size); + + printk(KERN_INFO "vesafb: framebuffer at 0x%lu, mapped to 0x%p, size %dk\n", video_base, video_vbase, video_size/1024); printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n", video_width, video_height, video_bpp, video_linelength, screen_info.pages); @@ -633,9 +642,13 @@ int __init vesafb_init(void) } video_cmap_len = 256; } - request_region(0x3c0, 32, "vga+"); + + /* request failure does not faze us, as vgacon probably has this + * region already (FIXME) */ + __request_region(&ioport_resource, 0x3c0, 32, "vesafb"); + if (mtrr) - mtrr_add((unsigned long)video_base, video_size, MTRR_TYPE_WRCOMB, 1); + mtrr_add(video_base, video_size, MTRR_TYPE_WRCOMB, 1); strcpy(fb_info.modename, "VESA VGA"); fb_info.changevar = NULL; diff --git a/drivers/video/vga.h b/drivers/video/vga.h index 8aaa1a5c1152..7c05ba331ee9 100644 --- a/drivers/video/vga.h +++ b/drivers/video/vga.h @@ -17,6 +17,7 @@ #ifndef __linux_video_vga_h__ #define __linux_video_vga_h__ +#include #include #include #ifndef CONFIG_AMIGA diff --git a/drivers/video/vga16fb.c b/drivers/video/vga16fb.c index 723bef47657f..9b014c45e675 100644 --- a/drivers/video/vga16fb.c +++ b/drivers/video/vga16fb.c @@ -32,6 +32,9 @@ #define dac_reg (0x3c8) #define dac_val (0x3c9) +#define VGA_FB_PHYS 0xA0000 +#define VGA_FB_PHYS_LEN 65535 + /* --------------------------------------------------------------------- */ /* @@ -101,6 +104,8 @@ static struct { u_short blue, green, red, pad; } palette[256]; static int currcon = 0; +static int release_io_ports = 0; + /* --------------------------------------------------------------------- */ /* @@ -158,8 +163,8 @@ static int vga16fb_get_fix(struct fb_fix_screeninfo *fix, int con, memset(fix, 0, sizeof(struct fb_fix_screeninfo)); strcpy(fix->id,"VGA16 VGA"); - fix->smem_start = 0xa0000; - fix->smem_len = 65536; + fix->smem_start = VGA_FB_PHYS; + fix->smem_len = VGA_FB_PHYS_LEN; fix->type = FB_TYPE_VGA_PLANES; fix->visual = FB_VISUAL_PSEUDOCOLOR; fix->xpanstep = 8; @@ -919,7 +924,13 @@ int __init vga16_init(void) printk(KERN_DEBUG "vga16fb: initializing\n"); - vga16fb.video_vbase = ioremap((unsigned long)0xa0000, 65536); + if (!__request_region(&iomem_resource, VGA_FB_PHYS, VGA_FB_PHYS_LEN, + "vga16fb")) { + printk (KERN_ERR "vga16fb: unable to reserve VGA memory, exiting\n"); + return -1; + } + + vga16fb.video_vbase = ioremap(VGA_FB_PHYS, VGA_FB_PHYS_LEN); printk(KERN_INFO "vga16fb: mapped to 0x%p\n", vga16fb.video_vbase); vga16fb.isVGA = ORIG_VIDEO_ISVGA; @@ -937,10 +948,11 @@ int __init vga16_init(void) palette[i].green = default_grn[j]; palette[i].blue = default_blu[j]; } - if (vga16fb.isVGA) - request_region(0x3c0, 32, "vga+"); - else - request_region(0x3C0, 32, "ega"); + + /* note - does not cause failure, b/c vgacon probably still owns this + * region (FIXME) */ + if (__request_region(&ioport_resource, 0x3C0, 32, "vga16fb")) + release_io_ports = 1; disp.var = vga16fb_defined; @@ -981,8 +993,10 @@ int init_module(void) void cleanup_module(void) { unregister_framebuffer(&vga16fb.fb_info); - release_region(0x3c0, 32); iounmap(vga16fb.video_vbase); + __release_region(&iomem_resource, VGA_FB_PHYS, VGA_FB_PHYS_LEN); + if (release_io_ports) + __release_region(&ioport_resource, 0x3c0, 32); } #endif diff --git a/fs/fifo.c b/fs/fifo.c index 3e641a6fe891..757b2c4f444f 100644 --- a/fs/fifo.c +++ b/fs/fifo.c @@ -12,38 +12,38 @@ #include #include -static int fifo_open(struct inode * inode,struct file * filp) +static int fifo_open(struct inode *inode, struct file *filp) { - int retval = 0; - unsigned long page = 0; - struct pipe_inode_info *info, *tmp = NULL; - - if (inode->i_pipe) - goto got_it; - tmp = kmalloc(sizeof(struct pipe_inode_info),GFP_KERNEL); - if (inode->i_pipe) - goto got_it; - if (!tmp) - goto oom; - page = __get_free_page(GFP_KERNEL); - if (inode->i_pipe) - goto got_it; - if (!page) - goto oom; - inode->i_pipe = tmp; - PIPE_LOCK(*inode) = 0; - PIPE_START(*inode) = PIPE_LEN(*inode) = 0; - PIPE_BASE(*inode) = (char *) page; - PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0; - PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0; - init_waitqueue_head(&PIPE_WAIT(*inode)); - tmp = NULL; /* no need to free it */ - page = 0; - -got_it: - - switch( filp->f_mode ) { + int ret; + ret = -ERESTARTSYS; + if (down_interruptible(PIPE_SEM(*inode))) + goto err_nolock_nocleanup; + + if (! inode->i_pipe) { + unsigned long page; + struct pipe_inode_info *info; + + info = kmalloc(sizeof(struct pipe_inode_info),GFP_KERNEL); + + ret = -ENOMEM; + if (!info) + goto err_nocleanup; + page = __get_free_page(GFP_KERNEL); + if (!page) { + kfree(info); + goto err_nocleanup; + } + + inode->i_pipe = info; + + init_waitqueue_head(PIPE_WAIT(*inode)); + PIPE_BASE(*inode) = (char *) page; + PIPE_START(*inode) = PIPE_LEN(*inode) = 0; + PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0; + } + + switch (filp->f_mode) { case 1: /* * O_RDONLY @@ -51,26 +51,26 @@ got_it: * opened, even when there is no process writing the FIFO. */ filp->f_op = &connecting_fifo_fops; - if (!PIPE_READERS(*inode)++) - wake_up_interruptible(&PIPE_WAIT(*inode)); - if (!(filp->f_flags & O_NONBLOCK) && !PIPE_WRITERS(*inode)) { - PIPE_RD_OPENERS(*inode)++; + if (PIPE_READERS(*inode)++ == 0) + wake_up_interruptible(PIPE_WAIT(*inode)); + + if (!(filp->f_flags & O_NONBLOCK)) { while (!PIPE_WRITERS(*inode)) { - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - interruptible_sleep_on(&PIPE_WAIT(*inode)); + if (signal_pending(current)) + goto err_rd; + up(PIPE_SEM(*inode)); + interruptible_sleep_on(PIPE_WAIT(*inode)); + + /* Note that using down_interruptible here + and similar places below is pointless, + since we have to acquire the lock to clean + up properly. */ + down(PIPE_SEM(*inode)); } - if (!--PIPE_RD_OPENERS(*inode)) - wake_up_interruptible(&PIPE_WAIT(*inode)); } - while (PIPE_WR_OPENERS(*inode)) - interruptible_sleep_on(&PIPE_WAIT(*inode)); + if (PIPE_WRITERS(*inode)) filp->f_op = &read_fifo_fops; - if (retval && !--PIPE_READERS(*inode)) - wake_up_interruptible(&PIPE_WAIT(*inode)); break; case 2: @@ -79,29 +79,21 @@ got_it: * POSIX.1 says that O_NONBLOCK means return -1 with * errno=ENXIO when there is no process reading the FIFO. */ - if ((filp->f_flags & O_NONBLOCK) && !PIPE_READERS(*inode)) { - retval = -ENXIO; - break; - } + ret = -ENXIO; + if ((filp->f_flags & O_NONBLOCK) && !PIPE_READERS(*inode)) + goto err; + filp->f_op = &write_fifo_fops; if (!PIPE_WRITERS(*inode)++) - wake_up_interruptible(&PIPE_WAIT(*inode)); - if (!PIPE_READERS(*inode)) { - PIPE_WR_OPENERS(*inode)++; - while (!PIPE_READERS(*inode)) { - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - interruptible_sleep_on(&PIPE_WAIT(*inode)); - } - if (!--PIPE_WR_OPENERS(*inode)) - wake_up_interruptible(&PIPE_WAIT(*inode)); + wake_up_interruptible(PIPE_WAIT(*inode)); + + while (!PIPE_READERS(*inode)) { + if (signal_pending(current)) + goto err_wr; + up(PIPE_SEM(*inode)); + interruptible_sleep_on(PIPE_WAIT(*inode)); + down(PIPE_SEM(*inode)); } - while (PIPE_RD_OPENERS(*inode)) - interruptible_sleep_on(&PIPE_WAIT(*inode)); - if (retval && !--PIPE_WRITERS(*inode)) - wake_up_interruptible(&PIPE_WAIT(*inode)); break; case 3: @@ -112,39 +104,47 @@ got_it: * the process can at least talk to itself. */ filp->f_op = &rdwr_fifo_fops; - if (!PIPE_READERS(*inode)++) - wake_up_interruptible(&PIPE_WAIT(*inode)); - while (PIPE_WR_OPENERS(*inode)) - interruptible_sleep_on(&PIPE_WAIT(*inode)); - if (!PIPE_WRITERS(*inode)++) - wake_up_interruptible(&PIPE_WAIT(*inode)); - while (PIPE_RD_OPENERS(*inode)) - interruptible_sleep_on(&PIPE_WAIT(*inode)); + + PIPE_READERS(*inode)++; + PIPE_WRITERS(*inode)++; + if (PIPE_READERS(*inode) == 1 || PIPE_WRITERS(*inode) == 1) + wake_up_interruptible(PIPE_WAIT(*inode)); break; default: - retval = -EINVAL; + ret = -EINVAL; + goto err; } - if (retval) - goto cleanup; -out: - if (tmp) - kfree(tmp); - if (page) - free_page(page); - return retval; - -cleanup: + + /* Ok! */ + up(PIPE_SEM(*inode)); + return 0; + +err_rd: + if (!--PIPE_READERS(*inode)) + wake_up_interruptible(PIPE_WAIT(*inode)); + ret = -ERESTARTSYS; + goto err; + +err_wr: + if (!--PIPE_WRITERS(*inode)) + wake_up_interruptible(PIPE_WAIT(*inode)); + ret = -ERESTARTSYS; + goto err; + +err: if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) { - info = inode->i_pipe; + struct pipe_inode_info *info = inode->i_pipe; inode->i_pipe = NULL; free_page((unsigned long)info->base); kfree(info); } - goto out; -oom: - retval = -ENOMEM; - goto out; + +err_nocleanup: + up(PIPE_SEM(*inode)); + +err_nolock_nocleanup: + return ret; } /* diff --git a/fs/pipe.c b/fs/pipe.c index 2303ca328498..89fdc96d76e2 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1,7 +1,7 @@ /* * linux/fs/pipe.c * - * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1991, 1992, 1999 Linus Torvalds */ #include @@ -22,187 +22,263 @@ #undef FIFO_SUNOS_BRAINDAMAGE #endif -/* We don't use the head/tail construction any more. Now we use the start/len*/ -/* construction providing full use of PIPE_BUF (multiple of PAGE_SIZE) */ -/* Florian Coosmann (FGC) ^ current = 1 */ -/* Additionally, we now use locking technique. This prevents race condition */ -/* in case of paging and multiple read/write on the same pipe. (FGC) */ -/* Reads with count = 0 should always return 0. Julian Bradfield 1999-06-07. */ +/* + * We use a start+len construction, which provides full use of the + * allocated memory. + * -- Florian Coosmann (FGC) + * + * Reads with count = 0 should always return 0. + * -- Julian Bradfield 1999-06-07. + */ + +/* Drop the inode semaphore and wait for a pipe event, atomically */ +static void pipe_wait(struct inode * inode) +{ + DECLARE_WAITQUEUE(wait, current); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue(PIPE_WAIT(*inode), &wait); + up(PIPE_SEM(*inode)); + schedule(); + remove_wait_queue(PIPE_WAIT(*inode), &wait); + current->state = TASK_RUNNING; +} -static ssize_t do_pipe_read(struct file * filp, char * buf, size_t count) +static ssize_t +pipe_read(struct file *filp, char *buf, size_t count, loff_t *ppos) { - struct inode * inode = filp->f_dentry->d_inode; - ssize_t chars = 0, size = 0, read = 0; - char *pipebuf; + struct inode *inode = filp->f_dentry->d_inode; + ssize_t size, read, ret; + /* Seeks are not allowed on pipes. */ + ret = -ESPIPE; + if (ppos != &filp->f_pos) + goto out_nolock; + + /* Always return 0 on null read. */ + ret = 0; + if (count == 0) + goto out_nolock; + + /* Grab, or try to grab, the pipe's semaphore with data present. */ if (filp->f_flags & O_NONBLOCK) { - if (PIPE_LOCK(*inode)) - return -EAGAIN; - if (PIPE_EMPTY(*inode)) { - if (PIPE_WRITERS(*inode)) - return -EAGAIN; - else - return 0; - } - } else while (PIPE_EMPTY(*inode) || PIPE_LOCK(*inode)) { + ret = -EAGAIN; + if (down_trylock(PIPE_SEM(*inode))) + goto out_nolock; + ret = PIPE_WRITERS(*inode) ? -EAGAIN : 0; + if (PIPE_EMPTY(*inode)) + goto out; + } else { + ret = -ERESTARTSYS; + if (down_interruptible(PIPE_SEM(*inode))) + goto out_nolock; + if (PIPE_EMPTY(*inode)) { - if (!PIPE_WRITERS(*inode) || !count) - return 0; + ret = 0; + if (!PIPE_WRITERS(*inode)) + goto out; + + for (;;) { + pipe_wait(inode); + ret = -ERESTARTSYS; + if (signal_pending(current)) + goto out_nolock; + if (down_interruptible(PIPE_SEM(*inode))) + goto out_nolock; + ret = 0; + if (!PIPE_EMPTY(*inode)) + break; + if (!PIPE_WRITERS(*inode)) + goto out; + } } - if (signal_pending(current)) - return -ERESTARTSYS; - interruptible_sleep_on(&PIPE_WAIT(*inode)); } - PIPE_LOCK(*inode)++; - while (count>0 && (size = PIPE_SIZE(*inode))) { - chars = PIPE_MAX_RCHUNK(*inode); + + /* Read what data is available. */ + ret = -EFAULT; + read = 0; + while (count > 0 && (size = PIPE_LEN(*inode))) { + char *pipebuf = PIPE_BASE(*inode) + PIPE_START(*inode); + ssize_t chars = PIPE_MAX_RCHUNK(*inode); + if (chars > count) chars = count; if (chars > size) chars = size; + + if (copy_to_user(buf, pipebuf, chars)) + goto out; + read += chars; - pipebuf = PIPE_BASE(*inode)+PIPE_START(*inode); PIPE_START(*inode) += chars; - PIPE_START(*inode) &= (PIPE_BUF-1); + PIPE_START(*inode) &= (PIPE_SIZE - 1); PIPE_LEN(*inode) -= chars; count -= chars; - copy_to_user(buf, pipebuf, chars ); buf += chars; } - PIPE_LOCK(*inode)--; - wake_up_interruptible(&PIPE_WAIT(*inode)); - if (read) { + + /* Cache behaviour optimization */ + if (!PIPE_LEN(*inode)) + PIPE_START(*inode) = 0; + + /* Signal writers there is more room. */ + wake_up_interruptible(PIPE_WAIT(*inode)); + + if (read) UPDATE_ATIME(inode); - return read; - } - if (PIPE_WRITERS(*inode)) - return -EAGAIN; - return 0; + ret = read; + +out: + up(PIPE_SEM(*inode)); +out_nolock: + return ret; } -static ssize_t do_pipe_write(struct file * filp, const char * buf, size_t count) +static ssize_t +pipe_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) { - struct inode * inode = filp->f_dentry->d_inode; - ssize_t chars = 0, free = 0, written = 0, err=0; - char *pipebuf; + struct inode *inode = filp->f_dentry->d_inode; + ssize_t free, written, ret; - if (!PIPE_READERS(*inode)) { /* no readers */ - send_sig(SIGPIPE,current,0); - return -EPIPE; - } - /* if count <= PIPE_BUF, we have to make it atomic */ - if (count <= PIPE_BUF) - free = count; - else - free = 1; /* can't do it atomically, wait for any free space */ - if (down_interruptible(&inode->i_sem)) { - return -ERESTARTSYS; - } - while (count>0) { - while ((PIPE_FREE(*inode) < free) || PIPE_LOCK(*inode)) { - if (!PIPE_READERS(*inode)) { /* no readers */ - send_sig(SIGPIPE,current,0); - err = -EPIPE; - goto errout; - } - if (signal_pending(current)) { - err = -ERESTARTSYS; - goto errout; - } - if (filp->f_flags & O_NONBLOCK) { - err = -EAGAIN; - goto errout; - } - interruptible_sleep_on(&PIPE_WAIT(*inode)); + /* Seeks are not allowed on pipes. */ + ret = -ESPIPE; + if (ppos != &filp->f_pos) + goto out_nolock; + + /* Null write succeeds. */ + ret = 0; + if (count == 0) + goto out_nolock; + + ret = -ERESTARTSYS; + if (down_interruptible(PIPE_SEM(*inode))) + goto out_nolock; + + /* No readers yields SIGPIPE. */ + if (!PIPE_READERS(*inode)) + goto sigpipe; + + /* If count <= PIPE_BUF, we have to make it atomic. */ + free = (count <= PIPE_BUF ? count : 1); + written = 0; + + /* Wait, or check for, available space. */ + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + if (PIPE_FREE(*inode) < free) + goto out; + } else { + while (PIPE_FREE(*inode) < free) { + pipe_wait(inode); + ret = -ERESTARTSYS; + if (signal_pending(current)) + goto out_nolock; + if (down_interruptible(PIPE_SEM(*inode))) + goto out_nolock; + + if (!PIPE_READERS(*inode)) + goto sigpipe; } - PIPE_LOCK(*inode)++; - while (count>0 && (free = PIPE_FREE(*inode))) { - chars = PIPE_MAX_WCHUNK(*inode); + } + + /* Copy into available space. */ + ret = -EFAULT; + while (count > 0) { + int space; + char *pipebuf = PIPE_BASE(*inode) + PIPE_END(*inode); + ssize_t chars = PIPE_MAX_WCHUNK(*inode); + + if ((space = PIPE_FREE(*inode)) != 0) { if (chars > count) chars = count; - if (chars > free) - chars = free; - pipebuf = PIPE_BASE(*inode)+PIPE_END(*inode); + if (chars > space) + chars = space; + + if (copy_from_user(pipebuf, buf, chars)) + goto out; + written += chars; PIPE_LEN(*inode) += chars; count -= chars; - copy_from_user(pipebuf, buf, chars ); buf += chars; + space = PIPE_FREE(*inode); + continue; } - PIPE_LOCK(*inode)--; - wake_up_interruptible(&PIPE_WAIT(*inode)); - free = 1; - } - inode->i_ctime = inode->i_mtime = CURRENT_TIME; - mark_inode_dirty(inode); -errout: - up(&inode->i_sem); - return written ? written : err; -} - -static ssize_t pipe_read(struct file * filp, char * buf, size_t count, loff_t *ppos) -{ - ssize_t retval; - - if (ppos != &filp->f_pos) - return -ESPIPE; - - if ( !count ) return 0; + ret = written; + if (filp->f_flags & O_NONBLOCK) + break; + + do { + /* This should be a synchronous wake-up: don't do idle reschedules! */ + wake_up_interruptible(PIPE_WAIT(*inode)); + pipe_wait(inode); + if (signal_pending(current)) + goto out; + if (down_interruptible(PIPE_SEM(*inode))) + goto out_nolock; + if (!PIPE_READERS(*inode)) + goto sigpipe; + } while (!PIPE_FREE(*inode)); + ret = -EFAULT; + } - lock_kernel(); - retval = do_pipe_read(filp, buf, count); - unlock_kernel(); - return retval; -} + /* Signal readers there is more data. */ + wake_up_interruptible(PIPE_WAIT(*inode)); -static ssize_t pipe_write(struct file * filp, const char * buf, size_t count, loff_t *ppos) -{ - ssize_t retval; + ret = (written ? written : -EAGAIN); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + mark_inode_dirty(inode); - if (ppos != &filp->f_pos) - return -ESPIPE; +out: + up(PIPE_SEM(*inode)); +out_nolock: + return ret; - lock_kernel(); - retval = do_pipe_write(filp, buf, count); - unlock_kernel(); - return retval; +sigpipe: + up(PIPE_SEM(*inode)); + send_sig(SIGPIPE, current, 0); + return -EPIPE; } -static long long pipe_lseek(struct file * file, long long offset, int orig) +static loff_t +pipe_lseek(struct file *file, loff_t offset, int orig) { return -ESPIPE; } -static ssize_t bad_pipe_r(struct file * filp, char * buf, - size_t count, loff_t *ppos) +static ssize_t +bad_pipe_r(struct file *filp, char *buf, size_t count, loff_t *ppos) { return -EBADF; } -static ssize_t bad_pipe_w(struct file * filp, const char * buf, - size_t count, loff_t *ppos) +static ssize_t +bad_pipe_w(struct file *filp, const char *buf, size_t count, loff_t *ppos) { return -EBADF; } -static int pipe_ioctl(struct inode *pino, struct file * filp, - unsigned int cmd, unsigned long arg) +static int +pipe_ioctl(struct inode *pino, struct file *filp, + unsigned int cmd, unsigned long arg) { switch (cmd) { case FIONREAD: - return put_user(PIPE_SIZE(*pino),(int *) arg); + return put_user(PIPE_LEN(*pino), (int *)arg); default: return -EINVAL; } } -static unsigned int pipe_poll(struct file * filp, poll_table * wait) +static unsigned int +pipe_poll(struct file *filp, poll_table *wait) { unsigned int mask; - struct inode * inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; - poll_wait(filp, &PIPE_WAIT(*inode), wait); + poll_wait(filp, PIPE_WAIT(*inode), wait); + + /* Reading only -- no need for aquiring the semaphore. */ mask = POLLIN | POLLRDNORM; if (PIPE_EMPTY(*inode)) mask = POLLOUT | POLLWRNORM; @@ -210,6 +286,7 @@ static unsigned int pipe_poll(struct file * filp, poll_table * wait) mask |= POLLHUP; if (!PIPE_READERS(*inode)) mask |= POLLERR; + return mask; } @@ -218,17 +295,21 @@ static unsigned int pipe_poll(struct file * filp, poll_table * wait) * Argh! Why does SunOS have to have different select() behaviour * for pipes and FIFOs? Hate, hate, hate! SunOS lacks POLLHUP. */ -static unsigned int fifo_poll(struct file * filp, poll_table * wait) +static unsigned int +fifo_poll(struct file *filp, poll_table *wait) { unsigned int mask; - struct inode * inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; + + poll_wait(filp, PIPE_WAIT(*inode), wait); - poll_wait(filp, &PIPE_WAIT(*inode), wait); + /* Reading only -- no need for aquiring the semaphore. */ mask = POLLIN | POLLRDNORM; if (PIPE_EMPTY(*inode)) mask = POLLOUT | POLLWRNORM; if (!PIPE_READERS(*inode)) mask |= POLLERR; + return mask; } #else @@ -242,82 +323,112 @@ static unsigned int fifo_poll(struct file * filp, poll_table * wait) * the open() code hasn't guaranteed a connection (O_NONBLOCK), * and we need to act differently until we do get a writer.. */ -static ssize_t connect_read(struct file * filp, char * buf, - size_t count, loff_t *ppos) +static ssize_t +connect_read(struct file *filp, char *buf, size_t count, loff_t *ppos) { - struct inode * inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; + + /* Reading only -- no need for aquiring the semaphore. */ if (PIPE_EMPTY(*inode) && !PIPE_WRITERS(*inode)) return 0; + filp->f_op = &read_fifo_fops; - return pipe_read(filp,buf,count,ppos); + return pipe_read(filp, buf, count, ppos); } -static unsigned int connect_poll(struct file * filp, poll_table * wait) +static unsigned int +connect_poll(struct file *filp, poll_table *wait) { - struct inode * inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; + unsigned int mask = 0; + + poll_wait(filp, PIPE_WAIT(*inode), wait); - poll_wait(filp, &PIPE_WAIT(*inode), wait); + /* Reading only -- no need for aquiring the semaphore. */ if (!PIPE_EMPTY(*inode)) { filp->f_op = &read_fifo_fops; - return POLLIN | POLLRDNORM; - } - if (PIPE_WRITERS(*inode)) + mask = POLLIN | POLLRDNORM; + } else if (PIPE_WRITERS(*inode)) { filp->f_op = &read_fifo_fops; - return POLLOUT | POLLWRNORM; + mask = POLLOUT | POLLWRNORM; + } + + return mask; } -static int pipe_release(struct inode * inode) +static int +pipe_release(struct inode *inode, int decr, int decw) { + down(PIPE_SEM(*inode)); + PIPE_READERS(*inode) -= decr; + PIPE_WRITERS(*inode) -= decw; if (!PIPE_READERS(*inode) && !PIPE_WRITERS(*inode)) { struct pipe_inode_info *info = inode->i_pipe; inode->i_pipe = NULL; free_page((unsigned long) info->base); kfree(info); - return 0; + } else { + wake_up_interruptible(PIPE_WAIT(*inode)); } - wake_up_interruptible(&PIPE_WAIT(*inode)); + up(PIPE_SEM(*inode)); + return 0; } -static int pipe_read_release(struct inode * inode, struct file * filp) +static int +pipe_read_release(struct inode *inode, struct file *filp) { - PIPE_READERS(*inode)--; - return pipe_release(inode); + return pipe_release(inode, 1, 0); } -static int pipe_write_release(struct inode * inode, struct file * filp) +static int +pipe_write_release(struct inode *inode, struct file *filp) { - PIPE_WRITERS(*inode)--; - return pipe_release(inode); + return pipe_release(inode, 0, 1); } -static int pipe_rdwr_release(struct inode * inode, struct file * filp) +static int +pipe_rdwr_release(struct inode *inode, struct file *filp) { - if (filp->f_mode & FMODE_READ) - PIPE_READERS(*inode)--; - if (filp->f_mode & FMODE_WRITE) - PIPE_WRITERS(*inode)--; - return pipe_release(inode); + int decr, decw; + + decr = (filp->f_mode & FMODE_READ) != 0; + decw = (filp->f_mode & FMODE_WRITE) != 0; + return pipe_release(inode, decr, decw); } -static int pipe_read_open(struct inode * inode, struct file * filp) +static int +pipe_read_open(struct inode *inode, struct file *filp) { + /* We could have perhaps used atomic_t, but this and friends + below are the only places. So it doesn't seem worthwhile. */ + down(PIPE_SEM(*inode)); PIPE_READERS(*inode)++; + up(PIPE_SEM(*inode)); + return 0; } -static int pipe_write_open(struct inode * inode, struct file * filp) +static int +pipe_write_open(struct inode *inode, struct file *filp) { + down(PIPE_SEM(*inode)); PIPE_WRITERS(*inode)++; + up(PIPE_SEM(*inode)); + return 0; } -static int pipe_rdwr_open(struct inode * inode, struct file * filp) +static int +pipe_rdwr_open(struct inode *inode, struct file *filp) { + down(PIPE_SEM(*inode)); if (filp->f_mode & FMODE_READ) PIPE_READERS(*inode)++; if (filp->f_mode & FMODE_WRITE) PIPE_WRITERS(*inode)++; + up(PIPE_SEM(*inode)); + return 0; } @@ -433,22 +544,20 @@ static struct inode * get_pipe_inode(void) goto fail_inode; page = __get_free_page(GFP_USER); - if (!page) goto fail_iput; - /* XXX */ inode->i_pipe = kmalloc(sizeof(struct pipe_inode_info), GFP_KERNEL); if (!inode->i_pipe) goto fail_page; - PIPE_BASE(*inode) = (char *) page; inode->i_op = &pipe_inode_operations; - init_waitqueue_head(&PIPE_WAIT(*inode)); + + init_waitqueue_head(PIPE_WAIT(*inode)); + PIPE_BASE(*inode) = (char *) page; PIPE_START(*inode) = PIPE_LEN(*inode) = 0; - PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0; PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1; - PIPE_LOCK(*inode) = 0; + /* * Mark the inode dirty from the very beginning, * that way it will never be moved to the dirty diff --git a/include/asm-i386/atomic.h b/include/asm-i386/atomic.h index 70bd39f695d5..6346f91d19de 100644 --- a/include/asm-i386/atomic.h +++ b/include/asm-i386/atomic.h @@ -73,15 +73,15 @@ static __inline__ int atomic_dec_and_test(volatile atomic_t *v) return c != 0; } -extern __inline__ int atomic_inc_and_test_greater_zero(volatile atomic_t *v) +extern __inline__ int atomic_add_negative(int i, volatile atomic_t *v) { unsigned char c; __asm__ __volatile__( - LOCK "incl %0; setg %1" + LOCK "addl %2,%0; sets %1" :"=m" (__atomic_fool_gcc(v)), "=qm" (c) - :"m" (__atomic_fool_gcc(v))); - return c; /* can be only 0 or 1 */ + :"ir" (i), "m" (__atomic_fool_gcc(v))); + return c; } /* These are x86-specific, used by some header files */ diff --git a/include/asm-i386/io.h b/include/asm-i386/io.h index 93fd0c1b52d3..2090dab84f8b 100644 --- a/include/asm-i386/io.h +++ b/include/asm-i386/io.h @@ -152,10 +152,16 @@ extern void iounmap(void *addr); #define readb(addr) (*(volatile unsigned char *) __io_virt(addr)) #define readw(addr) (*(volatile unsigned short *) __io_virt(addr)) #define readl(addr) (*(volatile unsigned int *) __io_virt(addr)) +#define __raw_readb readb +#define __raw_readw readw +#define __raw_readl readl #define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b)) #define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b)) #define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b)) +#define __raw_writeb writeb +#define __raw_writew writew +#define __raw_writel writel #define memset_io(a,b,c) memset(__io_virt(a),(b),(c)) #define memcpy_fromio(a,b,c) memcpy((a),__io_virt(b),(c)) diff --git a/include/asm-i386/semaphore-helper.h b/include/asm-i386/semaphore-helper.h deleted file mode 100644 index a80dfe566f40..000000000000 --- a/include/asm-i386/semaphore-helper.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef _I386_SEMAPHORE_HELPER_H -#define _I386_SEMAPHORE_HELPER_H - -/* - * SMP- and interrupt-safe semaphores helper functions. - * - * (C) Copyright 1996 Linus Torvalds - * (C) Copyright 1999 Andrea Arcangeli - */ - -/* - * These two _must_ execute atomically wrt each other. - * - * This is trivially done with load_locked/store_cond, - * but on the x86 we need an external synchronizer. - * - * NOTE: we can't look at the semaphore count here since it can be - * unreliable. Even if the count is minor than 1, the semaphore - * could be just owned by another process (this because not only up() increases - * the semaphore count, also the interruptible/trylock call can increment - * the semaphore count when they fails). - */ -static inline void wake_one_more(struct semaphore * sem) -{ - unsigned long flags; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - sem->waking++; - spin_unlock_irqrestore(&semaphore_wake_lock, flags); -} - -static inline int waking_non_zero(struct semaphore *sem) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_interruptible: - * 1 got the lock - * 0 go to sleep - * -EINTR interrupted - * - * If we give up we must undo our count-decrease we previously did in down(). - * Subtle: up() can continue to happens and increase the semaphore count - * even during our critical section protected by the spinlock. So - * we must remeber to undo the sem->waking that will be run from - * wake_one_more() some time soon, if the semaphore count become > 0. - */ -static inline int waking_non_zero_interruptible(struct semaphore *sem, - struct task_struct *tsk) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking > 0) { - sem->waking--; - ret = 1; - } else if (signal_pending(tsk)) { - if (atomic_inc_and_test_greater_zero(&sem->count)) - sem->waking--; - ret = -EINTR; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -/* - * waking_non_zero_trylock: - * 1 failed to lock - * 0 got the lock - * - * Implementation details are the same of the interruptible case. - */ -static inline int waking_non_zero_trylock(struct semaphore *sem) -{ - unsigned long flags; - int ret = 1; - - spin_lock_irqsave(&semaphore_wake_lock, flags); - if (sem->waking <= 0) - { - if (atomic_inc_and_test_greater_zero(&sem->count)) - sem->waking--; - } else { - sem->waking--; - ret = 0; - } - spin_unlock_irqrestore(&semaphore_wake_lock, flags); - return ret; -} - -#endif diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h index 56c72335860d..bd51aa8434bd 100644 --- a/include/asm-i386/semaphore.h +++ b/include/asm-i386/semaphore.h @@ -35,7 +35,7 @@ struct semaphore { atomic_t count; - int waking; + int sleepers; wait_queue_head_t wait; #if WAITQUEUE_DEBUG long __magic; @@ -71,7 +71,7 @@ extern inline void sema_init (struct semaphore *sem, int val) * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well. */ atomic_set(&sem->count, val); - sem->waking = 0; + sem->sleepers = 0; init_waitqueue_head(&sem->wait); #if WAITQUEUE_DEBUG sem->__magic = (int)&sem->__magic; diff --git a/include/linux/concap.h b/include/linux/concap.h index 7bece29f6321..a0743ec146b8 100644 --- a/include/linux/concap.h +++ b/include/linux/concap.h @@ -1,10 +1,11 @@ -/* $Id: concap.h,v 1.1 1998/02/01 00:15:11 keil Exp $ +/* $Id: concap.h,v 1.2 1999/08/23 15:54:21 keil Exp $ */ #ifndef _LINUX_CONCAP_H #define _LINUX_CONCAP_H #ifdef __KERNEL__ #include #include +#include /* Stuff to support encapsulation protocols genericly. The encapsulation protocol is processed at the uppermost layer of the network interface. @@ -25,11 +26,11 @@ struct concap_device_ops; /* this manages all data needed by the encapsulation protocol */ struct concap_proto{ - struct net_device *net_dev; /* net device using our service */ - struct concap_device_ops *dops; /* callbacks provided by device */ - struct concap_proto_ops *pops; /* callbacks provided by us */ + struct net_device *net_dev; /* net device using our service */ + struct concap_device_ops *dops; /* callbacks provided by device */ + struct concap_proto_ops *pops; /* callbacks provided by us */ int flags; - void *proto_data; /* protocol specific private data, to + void *proto_data; /* protocol specific private data, to be accessed via *pops methods only*/ /* : @@ -107,7 +108,3 @@ extern int concap_nop(struct concap_proto *cprot); extern int concap_drop_skb(struct concap_proto *cprot, struct sk_buff *skb); #endif #endif - - - - diff --git a/include/linux/i2c.h b/include/linux/i2c.h index a6c4a48f6f3b..feb877ed0d10 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -92,8 +92,6 @@ struct i2c_driver /* needed: unsigned long flags */ -#include - #if LINUX_VERSION_CODE >= 0x020100 # if 0 # define LOCK_FLAGS unsigned long flags; diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 99bb97fa253e..2e58af4edd81 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h @@ -75,6 +75,7 @@ #define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */ #define ETH_P_CONTROL 0x0016 /* Card specific control frames */ #define ETH_P_IRDA 0x0017 /* Linux/IR */ +#define ETH_P_ECONET 0x0018 /* Acorn Econet */ /* * This is an Ethernet frame header. diff --git a/include/linux/isdn.h b/include/linux/isdn.h index 152b11699522..d1d7350b1cc6 100644 --- a/include/linux/isdn.h +++ b/include/linux/isdn.h @@ -1,4 +1,4 @@ -/* $Id: isdn.h,v 1.70 1999/07/31 12:59:58 armin Exp $ +/* $Id: isdn.h,v 1.71 1999/08/23 15:54:22 keil Exp $ * * Main header for the Linux ISDN subsystem (linklevel). * @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdn.h,v $ + * Revision 1.71 1999/08/23 15:54:22 keil + * more backported changes from kernel 2.3.14 + * * Revision 1.70 1999/07/31 12:59:58 armin * Added tty fax capabilities. * @@ -577,13 +580,13 @@ typedef struct isdn_net_local_s { ulong sqfull_stamp; /* Start-Time of overload */ ulong slavedelay; /* Dynamic bundling delaytime */ int triggercps; /* BogoCPS needed for trigger slave */ - struct net_device *srobin; /* Ptr to Master device for slaves */ + struct net_device *srobin; /* Ptr to Master device for slaves */ isdn_net_phone *phone[2]; /* List of remote-phonenumbers */ /* phone[0] = Incoming Numbers */ /* phone[1] = Outgoing Numbers */ isdn_net_phone *dial; /* Pointer to dialed number */ - struct net_device *master; /* Ptr to Master device for slaves */ - struct net_device *slave; /* Ptr to Slave device for masters */ + struct net_device *master; /* Ptr to Master device for slaves */ + struct net_device *slave; /* Ptr to Slave device for masters */ struct isdn_net_local_s *next; /* Ptr to next link in bundle */ struct isdn_net_local_s *last; /* Ptr to last link in bundle */ struct isdn_net_dev_s *netdev; /* Ptr to netdev */ @@ -616,7 +619,7 @@ typedef struct isdn_net_dev_s { isdn_net_local *local; isdn_net_local *queue; void *next; /* Pointer to next isdn-interface */ - struct net_device dev; /* interface to upper levels */ + struct net_device dev; /* interface to upper levels */ #ifdef CONFIG_ISDN_PPP struct mpqueue *mp_last; struct ippp_bundle ib; diff --git a/include/linux/isdn_compat.h b/include/linux/isdn_compat.h index db002c415319..7750f63037ea 100644 --- a/include/linux/isdn_compat.h +++ b/include/linux/isdn_compat.h @@ -104,5 +104,13 @@ static inline unsigned long copy_to_user(void *to, const void *from, unsigned lo #define COMPAT_HAS_NEW_WAITQ #endif +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,12) +#define COMPAT_HAS_NEW_SETUP +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,14) +#define net_device device +#endif + #endif /* __KERNEL__ */ #endif /* _LINUX_ISDN_COMPAT_H */ diff --git a/include/linux/isdnif.h b/include/linux/isdnif.h index 35b66bba836d..06206eb916d6 100644 --- a/include/linux/isdnif.h +++ b/include/linux/isdnif.h @@ -1,4 +1,4 @@ -/* $Id: isdnif.h,v 1.29 1999/07/31 13:00:02 armin Exp $ +/* $Id: isdnif.h,v 1.30 1999/08/23 15:54:29 keil Exp $ * * Linux ISDN subsystem * @@ -22,6 +22,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Log: isdnif.h,v $ + * Revision 1.30 1999/08/23 15:54:29 keil + * more backported changes from kernel 2.3.14 + * * Revision 1.29 1999/07/31 13:00:02 armin * Added tty fax capabilities. * diff --git a/include/linux/msg.h b/include/linux/msg.h index 1ee1c434c4d2..78abcc24463e 100644 --- a/include/linux/msg.h +++ b/include/linux/msg.h @@ -11,8 +11,10 @@ #define MSG_NOERROR 010000 /* no error if message is too big */ #define MSG_EXCEPT 020000 /* recv any msg except of specified type.*/ +#ifdef __KERNEL__ + /* one msqid structure for each queue on the system */ -struct msqid_ds { +struct msqid_ds_kern { struct ipc_perm msg_perm; struct msg *msg_first; /* first message on queue */ struct msg *msg_last; /* last message in queue */ @@ -28,6 +30,24 @@ struct msqid_ds { __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ }; +#endif + +struct msqid_ds { + struct ipc_perm msg_perm; + struct msg *msg_first; /* first message on queue */ + struct msg *msg_last; /* last message in queue */ + __kernel_time_t msg_stime; /* last msgsnd time */ + __kernel_time_t msg_rtime; /* last msgrcv time */ + __kernel_time_t msg_ctime; /* last change time */ + unsigned long msg_cbytes; /* Reuse junk fields for 32 bit */ + unsigned long msg_qbytes; /* ditto */ + unsigned short msg_cbytes_old; /* current number of bytes on queue */ + unsigned short msg_qnum; /* number of messages in queue */ + unsigned short msg_qbytes_old; /* max number of bytes on queue */ + __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ +}; + /* message buffer for msgsnd and msgrcv calls */ struct msgbuf { long mtype; /* type of message */ diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index a96ede017808..7989f6b10113 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -169,9 +169,6 @@ extern void nf_invalidate_cache(int pf); * seconds to see why. - Linus */ -/* Use which one you mean explicitly. You have been warned. */ -#include - /* Two signed, return a signed. */ #define SMAX(a,b) ((ssize_t)(a)>(ssize_t)(b) ? (ssize_t)(a) : (ssize_t)(b)) #define SMIN(a,b) ((ssize_t)(a)<(ssize_t)(b) ? (ssize_t)(a) : (ssize_t)(b)) diff --git a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h index 01cf240ddd4e..6c0427b01df1 100644 --- a/include/linux/netfilter_ipv4.h +++ b/include/linux/netfilter_ipv4.h @@ -5,6 +5,7 @@ * (C)1998 Rusty Russell -- This code is GPL. */ +#include #include /* IP Cache bits. */ diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index c00d37845cdf..eb2d9105417e 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h @@ -3,32 +3,29 @@ struct pipe_inode_info { wait_queue_head_t wait; - char * base; + char *base; unsigned int start; - unsigned int lock; - unsigned int rd_openers; - unsigned int wr_openers; unsigned int readers; unsigned int writers; }; -#define PIPE_WAIT(inode) ((inode).i_pipe->wait) +/* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual + memory allocation, whereas PIPE_BUF makes atomicity guarantees. */ +#define PIPE_SIZE PAGE_SIZE + +#define PIPE_SEM(inode) (&(inode).i_sem) +#define PIPE_WAIT(inode) (&(inode).i_pipe->wait) #define PIPE_BASE(inode) ((inode).i_pipe->base) #define PIPE_START(inode) ((inode).i_pipe->start) #define PIPE_LEN(inode) ((inode).i_size) -#define PIPE_RD_OPENERS(inode) ((inode).i_pipe->rd_openers) -#define PIPE_WR_OPENERS(inode) ((inode).i_pipe->wr_openers) #define PIPE_READERS(inode) ((inode).i_pipe->readers) #define PIPE_WRITERS(inode) ((inode).i_pipe->writers) -#define PIPE_LOCK(inode) ((inode).i_pipe->lock) -#define PIPE_SIZE(inode) PIPE_LEN(inode) -#define PIPE_EMPTY(inode) (PIPE_SIZE(inode)==0) -#define PIPE_FULL(inode) (PIPE_SIZE(inode)==PIPE_BUF) -#define PIPE_FREE(inode) (PIPE_BUF - PIPE_LEN(inode)) -#define PIPE_END(inode) ((PIPE_START(inode)+PIPE_LEN(inode))&\ - (PIPE_BUF-1)) -#define PIPE_MAX_RCHUNK(inode) (PIPE_BUF - PIPE_START(inode)) -#define PIPE_MAX_WCHUNK(inode) (PIPE_BUF - PIPE_END(inode)) +#define PIPE_EMPTY(inode) (PIPE_LEN(inode) == 0) +#define PIPE_FULL(inode) (PIPE_LEN(inode) == PIPE_SIZE) +#define PIPE_FREE(inode) (PIPE_SIZE - PIPE_LEN(inode)) +#define PIPE_END(inode) ((PIPE_START(inode) + PIPE_LEN(inode)) & (PIPE_SIZE-1)) +#define PIPE_MAX_RCHUNK(inode) (PIPE_SIZE - PIPE_START(inode)) +#define PIPE_MAX_WCHUNK(inode) (PIPE_SIZE - PIPE_END(inode)) #endif diff --git a/include/linux/prctl.h b/include/linux/prctl.h index f08f3c36ed40..3382a6a5732f 100644 --- a/include/linux/prctl.h +++ b/include/linux/prctl.h @@ -1,9 +1,10 @@ #ifndef _LINUX_PRCTL_H #define _LINUX_PRCTL_H -/* Values to pass as first argument to prctl() */ +/* Values to pass as first argument to prctl() */ -#define PR_SET_PDEATHSIG 1 /* Second arg is a signal */ +#define PR_SET_PDEATHSIG 1 /* Second arg is a signal */ +#define PR_GET_PDEATHSIG 2 /* Second arg is a ptr to return the signal */ #endif /* _LINUX_PRCTL_H */ diff --git a/include/video/fbcon.h b/include/video/fbcon.h index 812a2ff9bc0e..7927a25a6dea 100644 --- a/include/video/fbcon.h +++ b/include/video/fbcon.h @@ -510,4 +510,25 @@ static __inline__ void fast_memmove(char *dst, const char *src, size_t size) #endif + +#if defined(__i386__) || defined(__alpha__) + +#define fb_readb __raw_readb +#define fb_readw __raw_readw +#define fb_readl __raw_readl +#define fb_writeb __raw_writeb +#define fb_writew __raw_writew +#define fb_writel __raw_writel + +#else + +#define fb_readb(addr) (*(volatile unsigned char *) __io_virt(addr)) +#define fb_readw(addr) (*(volatile unsigned short *) __io_virt(addr)) +#define fb_readl(addr) (*(volatile unsigned int *) __io_virt(addr)) +#define fb_writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b)) +#define fb_writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b)) +#define fb_writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b)) + +#endif + #endif /* _VIDEO_FBCON_H */ diff --git a/ipc/msg.c b/ipc/msg.c index 731a7a6b4deb..79ebbe4543b2 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -30,7 +30,7 @@ static int findkey (key_t key); static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data); #endif -static struct msqid_ds *msgque[MSGMNI]; +static struct msqid_ds_kern *msgque[MSGMNI]; static int msgbytes = 0; static int msghdrs = 0; static unsigned short msg_seq = 0; @@ -46,7 +46,7 @@ void __init msg_init (void) #endif for (id = 0; id < MSGMNI; id++) - msgque[id] = (struct msqid_ds *) IPC_UNUSED; + msgque[id] = (struct msqid_ds_kern *) IPC_UNUSED; msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0; init_waitqueue_head(&msg_lock); #ifdef CONFIG_PROC_FS @@ -59,7 +59,7 @@ void __init msg_init (void) static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg) { int id; - struct msqid_ds *msq; + struct msqid_ds_kern *msq; struct ipc_perm *ipcp; struct msg *msgh; long mtype; @@ -136,7 +136,7 @@ static int real_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg static int real_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg) { - struct msqid_ds *msq; + struct msqid_ds_kern *msq; struct ipc_perm *ipcp; struct msg *tmsg, *leastp = NULL; struct msg *nmsg = NULL; @@ -257,7 +257,7 @@ asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, static int findkey (key_t key) { int id; - struct msqid_ds *msq; + struct msqid_ds_kern *msq; for (id = 0; id <= max_msqid; id++) { while ((msq = msgque[id]) == IPC_NOID) @@ -273,20 +273,20 @@ static int findkey (key_t key) static int newque (key_t key, int msgflg) { int id; - struct msqid_ds *msq; + struct msqid_ds_kern *msq; struct ipc_perm *ipcp; for (id = 0; id < MSGMNI; id++) if (msgque[id] == IPC_UNUSED) { - msgque[id] = (struct msqid_ds *) IPC_NOID; + msgque[id] = (struct msqid_ds_kern *) IPC_NOID; goto found; } return -ENOSPC; found: - msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL); + msq = (struct msqid_ds_kern *) kmalloc (sizeof (*msq), GFP_KERNEL); if (!msq) { - msgque[id] = (struct msqid_ds *) IPC_UNUSED; + msgque[id] = (struct msqid_ds_kern *) IPC_UNUSED; wake_up (&msg_lock); return -ENOMEM; } @@ -315,7 +315,7 @@ found: asmlinkage long sys_msgget (key_t key, int msgflg) { int id, ret = -EPERM; - struct msqid_ds *msq; + struct msqid_ds_kern *msq; lock_kernel(); if (key == IPC_PRIVATE) @@ -342,7 +342,7 @@ asmlinkage long sys_msgget (key_t key, int msgflg) static void freeque (int id) { - struct msqid_ds *msq = msgque[id]; + struct msqid_ds_kern *msq = msgque[id]; struct msg *msgp, *msgh; msq->msg_perm.seq++; @@ -350,7 +350,7 @@ static void freeque (int id) msgbytes -= msq->msg_cbytes; if (id == max_msqid) while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED)); - msgque[id] = (struct msqid_ds *) IPC_UNUSED; + msgque[id] = (struct msqid_ds_kern *) IPC_UNUSED; used_queues--; while (waitqueue_active(&msq->rwait) || waitqueue_active(&msq->wwait)) { wake_up (&msq->rwait); @@ -368,7 +368,7 @@ static void freeque (int id) asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) { int id, err = -EINVAL; - struct msqid_ds *msq; + struct msqid_ds_kern *msq; struct msqid_ds tbuf; struct ipc_perm *ipcp; @@ -420,8 +420,10 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) tbuf.msg_stime = msq->msg_stime; tbuf.msg_rtime = msq->msg_rtime; tbuf.msg_ctime = msq->msg_ctime; + tbuf.msg_cbytes_old = msq->msg_cbytes; tbuf.msg_cbytes = msq->msg_cbytes; tbuf.msg_qnum = msq->msg_qnum; + tbuf.msg_qbytes_old = msq->msg_qbytes; tbuf.msg_qbytes = msq->msg_qbytes; tbuf.msg_lspid = msq->msg_lspid; tbuf.msg_lrpid = msq->msg_lrpid; @@ -462,8 +464,10 @@ asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) tbuf.msg_stime = msq->msg_stime; tbuf.msg_rtime = msq->msg_rtime; tbuf.msg_ctime = msq->msg_ctime; + tbuf.msg_cbytes_old = msq->msg_cbytes; tbuf.msg_cbytes = msq->msg_cbytes; tbuf.msg_qnum = msq->msg_qnum; + tbuf.msg_qbytes_old = msq->msg_qbytes; tbuf.msg_qbytes = msq->msg_qbytes; tbuf.msg_lspid = msq->msg_lspid; tbuf.msg_lrpid = msq->msg_lrpid; diff --git a/kernel/module.c b/kernel/module.c index 0701d7b3a023..6f4ad977d846 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -57,7 +57,7 @@ static void free_module(struct module *, int tag_freed); * Called at boot time */ -__initfunc(void init_modules(void)) +void __init init_modules(void) { kernel_module.nsyms = __stop___ksymtab - __start___ksymtab; diff --git a/kernel/sched.c b/kernel/sched.c index 26ddca2d9ec2..431d5c719bb0 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -36,7 +36,6 @@ #include #include #include -#include #include @@ -811,128 +810,6 @@ out: return; } -/* - * Semaphores are implemented using a two-way counter: - * The "count" variable is decremented for each process - * that tries to sleep, while the "waking" variable is - * incremented when the "up()" code goes to wake up waiting - * processes. - * - * Notably, the inline "up()" and "down()" functions can - * efficiently test if they need to do any extra work (up - * needs to do something only if count was negative before - * the increment operation. - * - * waking_non_zero() (from asm/semaphore.h) must execute - * atomically. - * - * When __up() is called, the count was negative before - * incrementing it, and we need to wake up somebody. - * - * This routine adds one to the count of processes that need to - * wake up and exit. ALL waiting processes actually wake up but - * only the one that gets to the "waking" field first will gate - * through and acquire the semaphore. The others will go back - * to sleep. - * - * Note that these functions are only called when there is - * contention on the lock, and as such all this is the - * "non-critical" part of the whole semaphore business. The - * critical part is the inline stuff in - * where we want to avoid any extra jumps and calls. - */ -void __up(struct semaphore *sem) -{ - wake_one_more(sem); - wake_up(&sem->wait); -} - -/* - * Perform the "down" function. Return zero for semaphore acquired, - * return negative for signalled out of the function. - * - * If called from __down, the return is ignored and the wait loop is - * not interruptible. This means that a task waiting on a semaphore - * using "down()" cannot be killed until someone does an "up()" on - * the semaphore. - * - * If called from __down_interruptible, the return value gets checked - * upon return. If the return value is negative then the task continues - * with the negative value in the return register (it can be tested by - * the caller). - * - * Either form may be used in conjunction with "up()". - * - */ - -#define DOWN_VAR \ - struct task_struct *tsk = current; \ - wait_queue_t wait; \ - init_waitqueue_entry(&wait, tsk); - -#define DOWN_HEAD(task_state) \ - \ - \ - tsk->state = (task_state); \ - add_wait_queue(&sem->wait, &wait); \ - \ - /* \ - * Ok, we're set up. sem->count is known to be less than zero \ - * so we must wait. \ - * \ - * We can let go the lock for purposes of waiting. \ - * We re-acquire it after awaking so as to protect \ - * all semaphore operations. \ - * \ - * If "up()" is called before we call waking_non_zero() then \ - * we will catch it right away. If it is called later then \ - * we will have to go through a wakeup cycle to catch it. \ - * \ - * Multiple waiters contend for the semaphore lock to see \ - * who gets to gate through and who has to wait some more. \ - */ \ - for (;;) { - -#define DOWN_TAIL(task_state) \ - tsk->state = (task_state); \ - } \ - tsk->state = TASK_RUNNING; \ - remove_wait_queue(&sem->wait, &wait); - -void __down(struct semaphore * sem) -{ - DOWN_VAR - DOWN_HEAD(TASK_UNINTERRUPTIBLE) - if (waking_non_zero(sem)) - break; - schedule(); - DOWN_TAIL(TASK_UNINTERRUPTIBLE) -} - -int __down_interruptible(struct semaphore * sem) -{ - int ret = 0; - DOWN_VAR - DOWN_HEAD(TASK_INTERRUPTIBLE) - - ret = waking_non_zero_interruptible(sem, tsk); - if (ret) - { - if (ret == 1) - /* ret != 0 only if we get interrupted -arca */ - ret = 0; - break; - } - schedule(); - DOWN_TAIL(TASK_INTERRUPTIBLE) - return ret; -} - -int __down_trylock(struct semaphore * sem) -{ - return waking_non_zero_trylock(sem); -} - #define SLEEP_ON_VAR \ unsigned long flags; \ wait_queue_t wait; \ diff --git a/kernel/sys.c b/kernel/sys.c index 3ec5bf54194b..1cb14631629e 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -998,6 +998,9 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, } current->pdeath_signal = sig; break; + case PR_GET_PDEATHSIG: + error = put_user(current->pdeath_signal, (int *)arg2); + break; default: error = -EINVAL; break; diff --git a/mm/memory.c b/mm/memory.c index c68c40f37428..e9da61a5ebee 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -821,7 +821,6 @@ static int do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma, if (PageReserved(page)) ++vma->vm_mm->rss; copy_cow_page(old_page,new_page); - flush_page_to_ram(old_page); flush_page_to_ram(new_page); flush_cache_page(vma, address); set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot)))); diff --git a/net/802/fc.c b/net/802/fc.c index 60996eb96cd1..723e7dae5986 100644 --- a/net/802/fc.c +++ b/net/802/fc.c @@ -12,7 +12,6 @@ #include #include -#include #include #include #include @@ -25,7 +24,6 @@ #include #include #include -#include #include #include #include diff --git a/net/802/llc_macinit.c b/net/802/llc_macinit.c index e00d565582df..792bfd5e8128 100644 --- a/net/802/llc_macinit.c +++ b/net/802/llc_macinit.c @@ -204,7 +204,7 @@ EXPORT_SYMBOL(llc_cancel_timers); #define ALL_TYPES_8022 0 -__initfunc(void llc_init(struct net_proto *proto)) +void __init llc_init(struct net_proto *proto) { printk(KERN_NOTICE "IEEE 802.2 LLC for Linux 2.1 (c) 1996 Tim Alpaerts\n"); return; diff --git a/net/802/p8022.c b/net/802/p8022.c index 06d4199c59f7..7d03668d225f 100644 --- a/net/802/p8022.c +++ b/net/802/p8022.c @@ -90,7 +90,7 @@ static struct packet_type p8022_packet_type = EXPORT_SYMBOL(register_8022_client); EXPORT_SYMBOL(unregister_8022_client); -__initfunc(void p8022_proto_init(struct net_proto *pro)) +void __init p8022_proto_init(struct net_proto *pro) { p8022_packet_type.type=htons(ETH_P_802_2); dev_add_pack(&p8022_packet_type); diff --git a/net/802/psnap.c b/net/802/psnap.c index 7184b938b108..7d8b120479b9 100644 --- a/net/802/psnap.c +++ b/net/802/psnap.c @@ -89,7 +89,7 @@ static void snap_datalink_header(struct datalink_proto *dl, struct sk_buff *skb, EXPORT_SYMBOL(register_snap_client); EXPORT_SYMBOL(unregister_snap_client); -__initfunc(void snap_proto_init(struct net_proto *pro)) +void __init snap_proto_init(struct net_proto *pro) { snap_dl=register_8022_client(0xAA, snap_rcv); if(snap_dl==NULL) diff --git a/net/802/tr.c b/net/802/tr.c index 28199f8893e7..f3fa70ac1248 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -538,7 +538,7 @@ static struct proc_dir_entry tr_rif_proc = { }; #endif -__initfunc(void rif_init(struct net_proto *unused)) +void __init rif_init(struct net_proto *unused) { rif_timer.expires = RIF_TIMEOUT; rif_timer.data = 0L; diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index 5410278f45d8..6aba2f14fdc5 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -1021,7 +1021,7 @@ static struct notifier_block aarp_notifier={ static char aarp_snap_id[]={0x00,0x00,0x00,0x80,0xF3}; -__initfunc(void aarp_proto_init(void)) +void __init aarp_proto_init(void) { if((aarp_dl=register_snap_client(aarp_snap_id, aarp_rcv))==NULL) printk(KERN_CRIT "Unable to register AARP with SNAP.\n"); diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 7338305001a6..b5aebbb06b61 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -2108,7 +2108,7 @@ static struct proc_dir_entry proc_atalk_iface= /* Called by proto.c on kernel start up */ -__initfunc(void atalk_proto_init(struct net_proto *pro)) +void __init atalk_proto_init(struct net_proto *pro) { (void) sock_register(&atalk_family_ops); if((ddp_dl = register_snap_client(ddp_snap_id, atalk_rcv)) == NULL) diff --git a/net/atm/atm_misc.c b/net/atm/atm_misc.c index 3f63b5ec9916..353321a93dd4 100644 --- a/net/atm/atm_misc.c +++ b/net/atm/atm_misc.c @@ -3,7 +3,6 @@ /* Written 1995-1999 by Werner Almesberger, EPFL ICA */ -#include #include #include #include diff --git a/net/atm/ipcommon.c b/net/atm/ipcommon.c index 44b6af5a66a6..4bf7a1918b9a 100644 --- a/net/atm/ipcommon.c +++ b/net/atm/ipcommon.c @@ -3,7 +3,6 @@ /* Written 1996,1997 by Werner Almesberger, EPFL LRC */ -#include #include #include #include diff --git a/net/atm/lec.c b/net/atm/lec.c index 3a94f7ec0993..ab640c4e666b 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -4,6 +4,7 @@ * */ +#include #include /* We are ethernet device */ @@ -34,7 +35,6 @@ #endif /* Modular too */ -#include #include #include "lec.h" diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 1a119dcab369..0035800659cd 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -1787,7 +1787,7 @@ static struct proc_dir_entry proc_ax25_calls = { }; #endif -__initfunc(void ax25_proto_init(struct net_proto *pro)) +void __init ax25_proto_init(struct net_proto *pro) { sock_register(&ax25_family_ops); ax25_packet_type.type = htons(ETH_P_AX25); diff --git a/net/core/dev.c b/net/core/dev.c index 35e18c6d315b..02a9f019bb48 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -1996,7 +1996,7 @@ static struct proc_dir_entry proc_net_wireless = { #endif /* CONFIG_PROC_FS */ #endif /* CONFIG_NET_RADIO */ -__initfunc(int net_dev_init(void)) +int __init net_dev_init(void) { struct net_device *dev, **dp; diff --git a/net/core/dev_mcast.c b/net/core/dev_mcast.c index 131b2e2a5c7c..c52df0507109 100644 --- a/net/core/dev_mcast.c +++ b/net/core/dev_mcast.c @@ -255,7 +255,7 @@ done: } #endif -__initfunc(void dev_mcast_init(void)) +void __init dev_mcast_init(void) { #ifdef CONFIG_PROC_FS struct proc_dir_entry *ent; diff --git a/net/core/dst.c b/net/core/dst.c index 03f1bfbe5aa8..f84896452d26 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -190,7 +190,7 @@ struct notifier_block dst_dev_notifier = { 0 }; -__initfunc(void dst_init(void)) +void __init dst_init(void) { register_netdevice_notifier(&dst_dev_notifier); } diff --git a/net/core/netfilter.c b/net/core/netfilter.c index 5f5862c24cb5..9bc77bc2e441 100644 --- a/net/core/netfilter.c +++ b/net/core/netfilter.c @@ -6,6 +6,7 @@ * * Rusty Russell (C)1998 -- This code is GPL. */ +#include #include #include #include @@ -149,7 +150,6 @@ void nf_unregister_sockopt(struct nf_setsockopt_ops *reg) #ifdef CONFIG_NETFILTER_DEBUG #include -#include #include #include #include @@ -554,7 +554,6 @@ void nf_invalidate_cache(int pf) } #ifdef CONFIG_NETFILTER_DEBUG -#include void debug_print_hooks_ip(unsigned int nf_debug) { diff --git a/net/core/profile.c b/net/core/profile.c index 491398864262..e43a3d6e1208 100644 --- a/net/core/profile.c +++ b/net/core/profile.c @@ -210,7 +210,7 @@ static struct net_device_stats *whitehole_get_stats(struct net_device *dev) return stats; } -__initfunc(int whitehole_init(struct net_device *dev)) +int __init whitehole_init(struct net_device *dev) { dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL); if (dev->priv == NULL) @@ -260,7 +260,7 @@ int net_profile_unregister(struct net_profile_slot *slot) } -__initfunc(int net_profile_init(void)) +int __init net_profile_init(void) { int i; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 07600081744c..b4d8582102e9 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -504,7 +504,7 @@ struct notifier_block rtnetlink_dev_notifier = { }; -__initfunc(void rtnetlink_init(void)) +void __init rtnetlink_init(void) { #ifdef RTNL_DEBUG printk("Initializing RT netlink socket\n"); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 9a116821dd0d..616e5fd0866f 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1005,7 +1005,7 @@ extern void tcp_v4_init(struct net_proto_family *); * Called by socket.c on kernel startup. */ -__initfunc(void inet_proto_init(struct net_proto *pro)) +void __init inet_proto_init(struct net_proto *pro) { struct sk_buff *dummy_skb; struct inet_protocol *p; diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 5b4a59affb3f..5e3421daf3d2 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -1125,7 +1125,7 @@ static struct proc_dir_entry proc_net_arp = { }; #endif -__initfunc(void arp_init (void)) +void __init arp_init (void) { neigh_table_init(&arp_tbl); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 68f1c9698ef6..f673a8125d58 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -20,6 +20,7 @@ * John McDonald : 0 length frag bug. */ +#include #include #include #include diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 01801c9b041f..5871f0c93898 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2145,7 +2145,7 @@ static int ip_rt_acct_read(char *buffer, char **start, off_t offset, #endif -__initfunc(void ip_rt_init(void)) +void __init ip_rt_init(void) { #ifdef CONFIG_PROC_FS #ifdef CONFIG_NET_CLS_ROUTE diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index da958ae17959..a23242eaa332 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -412,6 +412,7 @@ * (Updated by AK, but not complete yet.) **/ +#include #include #include #include diff --git a/net/khttpd/datasending.c b/net/khttpd/datasending.c index 8b292687cbb0..533195b3bd2b 100644 --- a/net/khttpd/datasending.c +++ b/net/khttpd/datasending.c @@ -34,6 +34,7 @@ Return value: The number of requests that changed status (ie: made some progress) */ +#include #include #include diff --git a/net/khttpd/main.c b/net/khttpd/main.c index 7a57076a5bb9..b1f67d9ae078 100644 --- a/net/khttpd/main.c +++ b/net/khttpd/main.c @@ -50,6 +50,7 @@ Userspace * ****************************************************************/ +#include #include #include #include diff --git a/net/khttpd/sysctl.c b/net/khttpd/sysctl.c index ada7b1fa1cad..244eb76db353 100644 --- a/net/khttpd/sysctl.c +++ b/net/khttpd/sysctl.c @@ -24,7 +24,6 @@ Sysctl interface #include -#include #include #include #include diff --git a/net/khttpd/userspace.c b/net/khttpd/userspace.c index 88521138bb8d..2acb27ff1856 100644 --- a/net/khttpd/userspace.c +++ b/net/khttpd/userspace.c @@ -199,6 +199,7 @@ static int AddSocketToAcceptQueue(struct socket *sock,const int Port) if (sk->state != TCP_LISTEN || sk->ack_backlog > sk->max_ack_backlog) /* To many pending requests */ { + release_sock(sk); sock_put(sk); return -1; } @@ -207,6 +208,7 @@ static int AddSocketToAcceptQueue(struct socket *sock,const int Port) if (req==NULL) { + release_sock(sk); sock_put(sk); return -1; } diff --git a/net/khttpd/waitheaders.c b/net/khttpd/waitheaders.c index d9c701e7b9c4..a7d4b82e0745 100644 --- a/net/khttpd/waitheaders.c +++ b/net/khttpd/waitheaders.c @@ -34,6 +34,7 @@ Return value: The number of requests that changed status */ +#include #include #include #include diff --git a/net/netsyms.c b/net/netsyms.c index 83e55951b656..882a63dff687 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -40,12 +40,10 @@ #include #include #include -#include #include #include #include #include -#include extern struct net_proto_family inet_family_ops; extern __u32 sysctl_wmem_max; diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 8a45e1b32cb4..e2d98e213100 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -1779,7 +1779,7 @@ extern void unix_sysctl_unregister(void); int init_module(void) #else -__initfunc(void unix_proto_init(struct net_proto *pro)) +void __init unix_proto_init(struct net_proto *pro) #endif { struct sk_buff *dummy_skb; -- 2.39.5