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
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/
-$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:
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.
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:
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
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.
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
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
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
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
--- /dev/null
+/*
+ * Generic semaphore code. Buyer beware. Do your own
+ * specific changes in <asm/semaphore-helper.h>
+ */
+
+#include <linux/sched.h>
+#include <asm/semaphore-helper.h>
+
+/*
+ * 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 <asm/semaphore.h>
+ * 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);
+}
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 :=
* Naturally it's not a 1:1 relation, but there are similarities.
*/
-#include <linux/config.h>
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/kernel_stat.h>
--- /dev/null
+/*
+ * i386 semaphore implementation.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ */
+#include <linux/sched.h>
+
+#include <asm/semaphore.h>
+
+/*
+ * 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 <asm/semaphore.h>
+ * 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"
+);
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);
$(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
+++ /dev/null
-/*
- * linux/arch/i386/lib/semaphore.S
- *
- * Copyright (C) 1996 Linus Torvalds
- */
-
-#include <linux/linkage.h>
-
-/*
- * 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
* 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;
#ifndef AMBASSADOR_H
#define AMBASSADOR_H
+#include <linux/config.h>
+
#ifdef CONFIG_ATM_AMBASSADOR_DEBUG
#define DEBUG_AMBASSADOR
#endif
*/
#include <linux/module.h>
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/pci.h>
#ifndef DRIVER_ATM_HORIZON_H
#define DRIVER_ATM_HORIZON_H
+#include <linux/config.h>
+
#ifdef CONFIG_ATM_HORIZON_DEBUG
#define DEBUG_HORIZON
#endif
/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
/* Written 1995-1998 by Werner Almesberger, EPFL LRC/ICA */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h> /* for jiffies */
#include <linux/mm.h>
/* Written 1995-1999 by Werner Almesberger, EPFL LRC/ICA */
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#ifndef DRIVER_ATM_ZATM_H
#define DRIVER_ATM_ZATM_H
+#include <linux/config.h>
#include <linux/skbuff.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
#include <linux/module.h>
#include <linux/version.h>
-#include <linux/config.h>
-#include <linux/module.h>
#include <linux/init.h>
#include "./ip2/ip2types.h"
#include <linux/ptrace.h>
#include <linux/ioport.h>
-#include <linux/wait.h>
#include <linux/cdk.h>
#include <linux/comstats.h>
-#include <linux/ioport.h>
#include <linux/delay.h>
#include <asm/system.h>
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
/*
- * $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.
*
#include "capicmd.h"
#include "capiutil.h"
-static char *revision = "$Revision: 1.7 $";
+static char *revision = "$Revision: 1.8 $";
/* ------------------------------------------------------------- */
/*
- * $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
*
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.3 $";
+static char *revision = "$Revision: 1.4 $";
/* ------------------------------------------------------------- */
/*
- * $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
*
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.3 $";
+static char *revision = "$Revision: 1.4 $";
/* ------------------------------------------------------------- */
/*
- * $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
*
#include "capilli.h"
#include "avmcard.h"
-static char *revision = "$Revision: 1.4 $";
+static char *revision = "$Revision: 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.
*
* 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
/*
- * $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.
*
* 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
*
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,
/*
- * $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.
*
* 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
*
-/* $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.
*
* 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.
#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
#define MAX_HEADER_LEN 10
+
/* Struct for adding new cards */
typedef struct eicon_cdef {
int membase;
#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
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 *);
-/* $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
* 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.
#undef EICON_FULL_SERVICE_OKTETT
-char *eicon_idi_revision = "$Revision: 1.11 $";
+char *eicon_idi_revision = "$Revision: 1.13 $";
eicon_manifbuf *manbuf;
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;
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:
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)
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;
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 */
/* 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 */
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
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:
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;
}
-
int
eicon_idi_manage_assign(eicon_card *card)
{
-/* $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
* 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.
-/* $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.
* 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.
/* 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);
}
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;
}
}
+/*
+ * 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
*/
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);
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)
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);
}
}
} 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);
}
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);
}
}
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)];
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 */
-/* $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.
* 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.
#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
-/* $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.
*
* 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.
*
*/
+#define DRIVERPATCH ""
+
#include <linux/config.h>
#include <linux/module.h>
#include <linux/init.h>
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;
#define MOD_USE_COUNT (GET_USE_COUNT (&__this_module))
#endif
-#define EICON_CTRL_VERSION 1
+#define EICON_CTRL_VERSION 2
ulong DebugVar;
}
}
+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)
{
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));
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)
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)
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;
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
printk(KERN_ERR
"eicon: if_readstatus called with invalid driverId!\n");
#endif
- return -ENODEV;
+ return 0;
}
static int
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 {
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
-/* $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.
* 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
*
#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 */
-/* $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
*
*
*
* $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
*
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);
}
-/* $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
* 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
*
extern const char *CardType[];
-const char *bkm_a4t_revision = "$Revision: 1.6 $";
+const char *bkm_a4t_revision = "$Revision: 1.7 $";
static inline u_char
-/* $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
* 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
*
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 {
-/* $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
* 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
*
#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;
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);
}
case (ISDN_PROTO_L2_HDLC):
case (ISDN_PROTO_L2_TRANS):
case (ISDN_PROTO_L2_MODEM):
+ case (ISDN_PROTO_L2_FAX):
releasestack_transl2(st);
break;
}
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))
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;
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);
}
/***************************************************************/
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)
{
struct Channel *chanp;
int i;
u_int num;
- u_long adr;
if (!csta) {
printk(KERN_ERR
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)
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;
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);
return(-EINVAL);
break;
default:
- break;
+ if (csta->auxcmd)
+ return(csta->auxcmd(csta, ic));
+ return(-EINVAL);
}
-
return (0);
}
-/* $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
*
#include <linux/stddef.h>
#include <linux/timer.h>
#include <linux/config.h>
+#include <linux/isdn_compat.h>
+#ifdef COMPAT_HAS_NEW_SETUP
+#include <linux/init.h>
+#endif
#include "hisax.h"
#include <linux/module.h>
#include <linux/kernel_stat.h>
#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)) {
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);
}
int
-ll_run(struct IsdnCardState *cs)
+ll_run(struct IsdnCardState *cs, int addfeatures)
{
long flags;
isdn_ctrl ic;
cli();
ic.driver = cs->myid;
ic.command = ISDN_STAT_RUN;
+ cs->iif.features |= addfeatures;
cs->iif.statcallb(&ic);
restore_flags(flags);
return 0;
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
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);
}
-/* $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
*
* 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
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",
#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 =
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)
cs->hw.elsa.counter++;
}
}
+#if ARCOFI_USE
if (cs->hw.elsa.MFlag) {
val = serial_inp(cs, UART_MCR);
val ^= 0x8;
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);
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) {
(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);
}
}
+#if ARCOFI_USE
+
static void
set_arcofi(struct IsdnCardState *cs, int bc) {
cs->dc.isac.arcofi_bc = bc;
static int
check_arcofi(struct IsdnCardState *cs)
{
-#if ARCOFI_USE
int arcofi_present = 0;
char tmp[40];
char *t;
interruptible_sleep_on(&cs->dc.isac.arcofi_wait);
return(1);
}
-#endif
return(0);
}
+#endif /* ARCOFI_USE */
static void
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) {
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;
modem_write_cmd(cs, msg, len);
}
break;
+#endif
}
if (cs->typ == ISDN_CTYPE_ELSA) {
int pwr = bytein(cs->hw.elsa.ale);
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);
-/* $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
*
* 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
*
#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
-/* $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
*
* 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
*
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},
};
/***********************/
/* 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);
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 */
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++;
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);
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,
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) {
reset_hfcpci(cs);
cs->cardmsg = &hfcpci_card_msg;
+ cs->auxcmd = &hfcpci_auxcmd;
return (1);
#else
printk(KERN_WARNING "HFC-PCI: NO_PCI_BIOS\n");
-/* $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
*
#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
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;
#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
#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
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;
#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
#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);
-/* $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
*
* ../../../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
*
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
-/* $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
*
*
*
* $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
*
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;
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 {
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;
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;
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);
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)
}
}
-static char debbuf[64];
+static char debbuf[128];
void
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)
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);
} 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",
} 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",
}
}
-void
+static void
setup_sart(struct BCState *bcs) {
struct IsdnCardState *cs = bcs->cs;
u_char dps = SET_DPS(bcs->hw.isar.dpath);
}
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);
}
}
-void
+static void
setup_iom2(struct BCState *bcs) {
struct IsdnCardState *cs = bcs->cs;
u_char dps = SET_DPS(bcs->hw.isar.dpath);
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:
}
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))
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;
}
}
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))
{
-/* $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
*
#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
#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
#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
#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);
-/* $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
*
*
* $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
*
*
*/
-const char *l1_revision = "$Revision: 2.34 $";
+const char *l1_revision = "$Revision: 2.36 $";
#define __NO_VERSION__
#include "hisax.h"
}
}
-static void
+void
BChannel_bh(struct BCState *bcs)
{
if (!bcs)
-/* $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
* 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
*
#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, ...);
}
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)
-/* $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
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)
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
cs->cardmsg = &ISurf_card_msg;
cs->irq_func = &isurf_interrupt;
+ cs->auxcmd = &isurf_auxcmd;
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
-/* $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
*
* 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
*
#include <linux/ctype.h>
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
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);
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);
} 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
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);
}
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},
{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),
# 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
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-----
-/* $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),
* 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
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+",
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;
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;
-/* $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.
*
* 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
*
#undef MAP_DEBUG
static char
-*revision = "$Revision: 1.57 $";
+*revision = "$Revision: 1.58 $";
static int icn_addcard(int, char *, char *);
#ifdef MODULE
#define icn_init init_module
#else
+#ifdef COMPAT_HAS_NEW_SETUP
+#include <linux/init.h>
+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)
icn_id2 = sid2;
}
}
+#ifdef COMPAT_HAS_NEW_SETUP
+ return(1);
+}
+__setup("icn=", icn_setup);
+#else
}
#endif
+#endif /* MODULES */
int
icn_init(void)
-/* $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).
*
* 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
#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.
* 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
-/* $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
*
-/* $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).
*
* 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
*
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
-/* $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).
*
* 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.
*
-/* $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).
*
* 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
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;
{
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);
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,
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);
}
-/* $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).
*
* 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
*
-/* $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).
*
* 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.
*
-/* $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)
* 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.
*
#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; }
-/* $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
* 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)
*
}
#else
-void pcbit_setup(char *str, int *ints)
+#ifdef COMPAT_HAS_NEW_SETUP
+#define MAX_PARA (MAX_PCBIT_CARDS * 2)
+#include <linux/init.h>
+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;
i++;
}
+#ifdef COMPAT_HAS_NEW_SETUP
+ return(1);
+}
+__setup("pcbit=", pcbit_setup);
+#else
}
#endif
+#endif
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;
static char version[] = "sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)\n";
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>
#include <linux/version.h>
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/errno.h>
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;
} 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: {
}
/* 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 */
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);
* use the PowerTweak utility (see http://linux.powertweak.com/).
*/
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#define MEGARAID_VERSION "v1.04 (August 16, 1999)"
-#include <linux/config.h>
#include <linux/version.h>
#ifdef MODULE
/*****************************************************************************/
-#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/string.h>
* This happens in pcm_copy_{in,out}().
*/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/stddef.h>
#include <asm/fixmap.h>
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
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
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)
endif
ifeq ($(CONFIG_USB_ACM),m)
M_OBJS += acm.o
- MIX_OBJS +=acm.o
+ MIX_OBJS += acm.o
endif
ifeq ($(CONFIG_USB_PRINTER),y)
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
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;i<NR_PORTS;i++) {
- if (!acm_state_table[i].present)
- return i;
- }
- return -1;
+ for (i=0;i<NR_PORTS;i++) {
+ if (!acm_state_table[i].present)
+ return i;
+ }
+ return -1;
}
static int acm_probe(struct usb_device *dev)
dev->descriptor.bDeviceProtocol != 0)
return -1;
- /*Now scan all configs for a ACM configuration*/
+ /* Now scan all configs for a ACM configuration */
for (cfgnum=0;cfgnum<dev->descriptor.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 ||
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 ||
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");
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;
}
{
usb_acm_cleanup();
}
-#endif
\ No newline at end of file
+#endif
struct usb_audio {
struct usb_device *dev;
struct list_head list;
+
+ void *irq_handle;
};
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; i<dev->config[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++;
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)
/*
* 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 <linux/kernel.h>
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;
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)
}
/* 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;
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;
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");
}
/* 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
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;
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;
usb_cpia_initstreamcap(cpia->dev, 0, 60);
- cpia_init_isoc(cpia);
+ err = cpia_init_isoc(cpia);
+ if (err)
+ goto open_err_on2;
return 0;
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)
#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 */
struct cpia_sbuf {
char *data;
int len;
+ struct usb_isoc_desc *isodesc;
+#if 0
void *isodesc;
+#endif
};
enum {
/*****************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/socket.h>
#include <asm/uaccess.h>
void *hcbuf[2];
void *hcisodesc[2];
unsigned char *buf;
-};
+};
-#define ISOFLG_ACTIVE (1<<0)
+#define ISOFLG_ACTIVE (1<<0)
/* --------------------------------------------------------------------- */
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;
{
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)
else
iso_schedsnd(isodesc);
spin_unlock_irqrestore(&isodesc->lock, flags);
- up(&ez->mutex);
+ up(&ez->mutex);
return 0;
}
return -ENOIOCTLCMD;
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 */
+
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);
}
/*
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;
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;
}
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;
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))
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;
}
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);
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;
/* 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;
}
}
- tmp = next;
}
+he_unlock:
spin_unlock_irqrestore(&hub_event_lock, flags);
}
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);
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;
#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 {
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;
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;
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))
unsigned long copy_size;
unsigned long bytes_written = 0;
unsigned long partial;
- int result;
+ int result = USB_ST_NOERROR;
int maxretry;
do {
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");
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;
}
return (len);
}
+/*
+ * proc entry for every device
+ * sailer@ife.ee.ethz.ch
+ */
+#include <linux/bitops.h>
+#include <asm/uaccess.h>
+#include <linux/mm.h>
+#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)
* 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 <linux/kernel.h>
#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;
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))
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");
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;
"interrupt128", "interrupt256", "control",
"bulk"};
-void show_queues(struct uhci *uhci)
+void uhci_show_queues(struct uhci *uhci)
{
int i;
struct uhci_qh *qh;
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);
}
}
}
*
* (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
#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
*
- * <status> is ((td->status >> 16) & 0xff) [a.k.a. uhci_status_bits(td->status)]
+ * <status> is (td->status & 0xFE0000) [a.k.a. uhci_status_bits(td->status)
* <dir_out> 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;
/*
* 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);
}
/*
:"=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) {
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)
:
:"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)
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)
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);
+ }
}
/*
}
/*
- * 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)
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);
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;
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;
} /* 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
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 */
uhci_qh_free(qh);
- return uhci_td_result(dev, last, NULL);
+ return uhci_td_result(dev, last, NULL, 1);
}
/*
* 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)
{
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 */
*/
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);
/*
* 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 */
/* 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);
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;
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);
uhci_qh_free(qh);
- return uhci_td_result(dev, last, rval);
+ return uhci_td_result(dev, last, rval, 1);
}
/*
}
/*
- *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
};
/*
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);
}
* 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;
} 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;
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);
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);
* 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;
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 */
/*
* Allocate the root_hub
*/
- usb = uhci_usb_alloc(NULL);
+ usb = usb_alloc_dev(NULL, bus);
if (!usb)
goto au_free_bus;
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 */
kfree(uhci);
}
-static int uhci_control_thread(void * __uhci)
+static int uhci_control_thread(void *__uhci)
{
struct uhci *uhci = (struct uhci *)__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",
* 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);
}
reset_hc(uhci);
- release_region(uhci->io_addr, 32);
+ release_region(uhci->io_addr, uhci->io_size);
release_uhci(uhci);
return retval;
/* 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;
}
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);
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)
/* 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);
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);
#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 */
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)));
* for TD <status>:
*/
#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 */
#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)
#define uhci_packetout(token) (uhci_packetid(token) != USB_PID_IN)
#define uhci_packetin(token) (uhci_packetid(token) == USB_PID_IN)
+/*
+ * for TD <info>: (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".
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 {
#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 */
struct uhci {
int irq;
unsigned int io_addr;
+ unsigned int io_size;
int control_pid;
int control_running;
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
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)
usb_show_config(dev->config + i);
}
-
/*
* Parse and show the different USB descriptors.
*/
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:
}
}
-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,
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,
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; i<desc->bNumDescriptors; 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");
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);
}
+
* 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
* 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 <linux/config.h>
#include <linux/string.h>
#include <linux/bitops.h>
*/
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);
}
}
-/* 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");
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");
}
* 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;
* 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;
}
/*
- * 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; i<hid->bNumDescriptors; 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);
}
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
static void usb_set_maxpacket(struct usb_device *dev)
{
int i, j;
- struct usb_interface *intf;
+ struct usb_interface *ifp;
for (i=0; i<dev->actconfig->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;
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;
}
}
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;
}
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)
/* 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;
}
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;
}
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;
}
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
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);
}
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
+
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)
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
#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
/*
#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
#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
/*
#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.
*/
#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
#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
* 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;
__u8 iProduct;
__u8 iSerialNumber;
__u8 bNumConfigurations;
-};
+} __attribute__ ((packed));
/* Endpoint descriptor */
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 {
__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.. */
__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;
};
*/
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);
};
/*
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; */
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
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 *);
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,
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
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);
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
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;
}
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;
/*****************************************************************************/
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/socket.h>
#include <linux/parport.h>
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 */
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
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)
#ifdef CONFIG_FB_OF
void atyfb_of_init(struct device_node *dp);
#endif
+#ifndef MODULE
int atyfb_setup(char*);
+#endif
static int currcon = 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;
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)
base = rp->start;
- io = (rp->flags & IORESOURCE_IOPORT);
+ io = (rp->flags & IORESOURCE_IO);
size = rp->end - base + 1;
#endif /* CONFIG_FB_OF */
+#ifndef MODULE
int __init atyfb_setup(char *options)
{
char *this_opt;
}
}
#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)
*
*/
-#define CLGEN_VERSION "1.9.4.2"
+#define CLGEN_VERSION "1.9.4.3"
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#ifdef CONFIG_ZORRO
int keyRAM; /* RAM, REG zorro board keys */
int keyREG;
+ unsigned long board_addr,
+ board_size;
#endif
#ifdef CONFIG_PCI
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;
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;
#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 {
+/* 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)
{
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
} 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");
+/* 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)
{
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);
#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);
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 */
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;
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
return 0;
+
+#endif /* defined(__sparc__) */
}
static int
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) {
}
return 0;
}
-#endif
+#endif /* !MODULE */
static int matroxfb_getmemory(WPMINFO unsigned int maxSize, unsigned int* realOffset, unsigned int *realSize){
vaddr_t vm;
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)
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 */
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;
}
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;
}
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
* 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){
*/
/* card */
-char *video_base;
+unsigned long video_base; /* physical addr */
int video_size;
char *video_vbase; /* mapped */
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;
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);
}
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;
#ifndef __linux_video_vga_h__
#define __linux_video_vga_h__
+#include <linux/config.h>
#include <linux/types.h>
#include <asm/io.h>
#ifndef CONFIG_AMIGA
#define dac_reg (0x3c8)
#define dac_val (0x3c9)
+#define VGA_FB_PHYS 0xA0000
+#define VGA_FB_PHYS_LEN 65535
+
/* --------------------------------------------------------------------- */
/*
static int currcon = 0;
+static int release_io_ports = 0;
+
/* --------------------------------------------------------------------- */
/*
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;
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;
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;
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
#include <linux/mm.h>
#include <linux/malloc.h>
-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
* 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:
* 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:
* 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;
}
/*
/*
* linux/fs/pipe.c
*
- * Copyright (C) 1991, 1992 Linus Torvalds
+ * Copyright (C) 1991, 1992, 1999 Linus Torvalds
*/
#include <linux/mm.h>
#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;
mask |= POLLHUP;
if (!PIPE_READERS(*inode))
mask |= POLLERR;
+
return mask;
}
* 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
* 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;
}
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
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 */
#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))
+++ /dev/null
-#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
struct semaphore {
atomic_t count;
- int waking;
+ int sleepers;
wait_queue_head_t wait;
#if WAITQUEUE_DEBUG
long __magic;
* 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;
-/* $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 <linux/skbuff.h>
#include <linux/netdevice.h>
+#include <linux/isdn_compat.h>
/* Stuff to support encapsulation protocols genericly. The encapsulation
protocol is processed at the uppermost layer of the network interface.
/* 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*/
/*
:
extern int concap_drop_skb(struct concap_proto *cprot, struct sk_buff *skb);
#endif
#endif
-
-
-
-
/* needed: unsigned long flags */
-#include <linux/version.h>
-
#if LINUX_VERSION_CODE >= 0x020100
# if 0
# define LOCK_FLAGS unsigned long flags;
#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.
-/* $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).
*
* 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.
*
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 */
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;
#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 */
-/* $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
*
* 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.
*
#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 */
__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 */
* seconds to see why. - Linus
*/
-/* Use which one you mean explicitly. You have been warned. */
-#include <linux/types.h>
-
/* 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))
* (C)1998 Rusty Russell -- This code is GPL.
*/
+#include <linux/config.h>
#include <linux/netfilter.h>
/* IP Cache bits. */
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
#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 */
#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 */
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;
#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
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;
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;
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)
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;
}
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)
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++;
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);
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;
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;
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;
* Called at boot time
*/
-__initfunc(void init_modules(void))
+void __init init_modules(void)
{
kernel_module.nsyms = __stop___ksymtab - __start___ksymtab;
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/mmu_context.h>
-#include <asm/semaphore-helper.h>
#include <linux/timex.h>
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 <asm/semaphore.h>
- * 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; \
}
current->pdeath_signal = sig;
break;
+ case PR_GET_PDEATHSIG:
+ error = put_user(current->pdeath_signal, (int *)arg2);
+ break;
default:
error = -EINVAL;
break;
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))));
#include <asm/uaccess.h>
#include <asm/system.h>
-#include <linux/config.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fcdevice.h>
#include <linux/skbuff.h>
#include <linux/errno.h>
-#include <linux/string.h>
#include <linux/timer.h>
#include <linux/net.h>
#include <linux/proc_fs.h>
#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;
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);
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)
};
#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;
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");
/* 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)
/* Written 1995-1999 by Werner Almesberger, EPFL ICA */
-#include <linux/config.h>
#include <linux/module.h>
#include <linux/atm.h>
#include <linux/atmdev.h>
/* Written 1996,1997 by Werner Almesberger, EPFL LRC */
-#include <linux/config.h>
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
*
*/
+#include <linux/config.h>
#include <linux/kernel.h>
/* We are ethernet device */
#endif
/* Modular too */
-#include <linux/config.h>
#include <linux/module.h>
#include "lec.h"
};
#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);
#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;
}
#endif
-__initfunc(void dev_mcast_init(void))
+void __init dev_mcast_init(void)
{
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *ent;
0
};
-__initfunc(void dst_init(void))
+void __init dst_init(void)
{
register_netdevice_notifier(&dst_dev_notifier);
}
*
* Rusty Russell (C)1998 -- This code is GPL.
*/
+#include <linux/config.h>
#include <linux/netfilter.h>
#include <net/protocol.h>
#include <linux/init.h>
#ifdef CONFIG_NETFILTER_DEBUG
#include <net/ip.h>
-#include <net/protocol.h>
#include <net/route.h>
#include <net/tcp.h>
#include <linux/netfilter_ipv4.h>
}
#ifdef CONFIG_NETFILTER_DEBUG
-#include <linux/netfilter_ipv4.h>
void debug_print_hooks_ip(unsigned int nf_debug)
{
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)
}
-__initfunc(int net_profile_init(void))
+int __init net_profile_init(void)
{
int i;
};
-__initfunc(void rtnetlink_init(void))
+void __init rtnetlink_init(void)
{
#ifdef RTNL_DEBUG
printk("Initializing RT netlink socket\n");
* 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;
};
#endif
-__initfunc(void arp_init (void))
+void __init arp_init (void)
{
neigh_table_init(&arp_tbl);
* John McDonald : 0 length frag bug.
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/sched.h>
#endif
-__initfunc(void ip_rt_init(void))
+void __init ip_rt_init(void)
{
#ifdef CONFIG_PROC_FS
#ifdef CONFIG_NET_CLS_ROUTE
* (Updated by AK, but not complete yet.)
**/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/poll.h>
The number of requests that changed status (ie: made some progress)
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
*
****************************************************************/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/malloc.h>
#include <linux/net.h>
if (sk->state != TCP_LISTEN ||
sk->ack_backlog > sk->max_ack_backlog) /* To many pending requests */
{
+ release_sock(sk);
sock_put(sk);
return -1;
}
if (req==NULL)
{
+ release_sock(sk);
sock_put(sk);
return -1;
}
The number of requests that changed status
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/skbuff.h>
#include <linux/smp_lock.h>
#include <net/udp.h>
#include <net/tcp.h>
#include <net/icmp.h>
-#include <net/route.h>
#include <net/inet_common.h>
#include <linux/inet.h>
#include <linux/mroute.h>
#include <linux/igmp.h>
-#include <linux/inetdevice.h>
extern struct net_proto_family inet_family_ops;
extern __u32 sysctl_wmem_max;
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;