diff options
| author | David S. Miller <davem@nuts.ninka.net> | 2002-07-22 06:34:05 -0700 |
|---|---|---|
| committer | David S. Miller <davem@nuts.ninka.net> | 2002-07-22 06:34:05 -0700 |
| commit | d0c91cb7127b4a086c04257ce827686cb7bbbdb3 (patch) | |
| tree | cbc1f210c13cf11cc6bece095c6ffcbcb9094cb5 | |
| parent | f153b55b58a10aa573bfa63f76d11e295d7294c4 (diff) | |
| parent | b43e708b4a1692618184cc1ee5edaedf81904df0 (diff) | |
Merge nuts.ninka.net:/home/davem/src/BK/BAK-net-2.5
into nuts.ninka.net:/home/davem/src/BK/net-2.5
455 files changed, 15184 insertions, 11603 deletions
diff --git a/Documentation/cli-sti-removal.txt b/Documentation/cli-sti-removal.txt new file mode 100644 index 000000000000..13c744dac866 --- /dev/null +++ b/Documentation/cli-sti-removal.txt @@ -0,0 +1,134 @@ + +#### cli()/sti() removal guide, started by Ingo Molnar <mingo@redhat.com> + + +as of 2.5.28, five popular macros have been removed on SMP, and +are being phased out on UP: + + cli(), sti(), save_flags(flags), save_flags_cli(flags), restore_flags(flags) + +until now it was possible to protect driver code against interrupt +handlers via a cli(), but from now on other, more lightweight methods +have to be used for synchronization, such as spinlocks or semaphores. + +for example, driver code that used to do something like: + + struct driver_data; + + irq_handler (...) + { + .... + driver_data.finish = 1; + driver_data.new_work = 0; + .... + } + + ... + + ioctl_func (...) + { + ... + cli(); + ... + driver_data.finish = 0; + driver_data.new_work = 2; + ... + sti(); + ... + } + +was SMP-correct because the cli() function ensured that no +interrupt handler (amongst them the above irq_handler()) function +would execute while the cli()-ed section is executing. + +but from now on a more direct method of locking has to be used: + + spinlock_t driver_lock = SPIN_LOCK_UNLOCKED; + struct driver_data; + + irq_handler (...) + { + unsigned long flags; + .... + spin_lock_irqsave(&driver_lock, flags); + .... + driver_data.finish = 1; + driver_data.new_work = 0; + .... + spin_unlock_irqrestore(&driver_lock, flags); + .... + } + + ... + + ioctl_func (...) + { + ... + spin_lock_irq(&driver_lock); + ... + driver_data.finish = 0; + driver_data.new_work = 2; + ... + spin_unlock_irq(&driver_lock); + ... + } + +the above code has a number of advantages: + +- the locking relation is easier to understand - actual lock usage + pinpoints the critical sections. cli() usage is too opaque. + Easier to understand means it's easier to debug. + +- it's faster, because spinlocks are faster to acquire than the + potentially heavily-used IRQ lock. Furthermore, your driver does + not have to wait eg. for a big heavy SCSI interrupt to finish, + because the driver_lock spinlock is only used by your driver. + cli() on the other hand was used by many drivers, and extended + the critical section to the whole IRQ handler function - creating + serious lock contention. + + +to make the transition easier, we've still kept the cli(), sti(), +save_flags(), save_flags_cli() and restore_flags() macros defined +on UP systems - but their usage will be phased out until 2.6 is +released. + +drivers that want to disable local interrupts (interrupts on the +current CPU), can use the following five macros: + + local_irq_disable(), local_irq_enable(), local_irq_save(flags), + local_irq_save_off(flags), local_irq_restore(flags) + +but beware, their meaning and semantics are much simpler, far from +that of the old cli(), sti(), save_flags(flags) and restore_flags(flags) +SMP meaning: + + local_irq_disable() => turn local IRQs off + + local_irq_enable() => turn local IRQs on + + local_irq_save(flags) => save the current IRQ state into flags. The + state can be on or off. (on some + architectures there's even more bits in it.) + + local_irq_save_off(flags) => save the current IRQ state into flags and + disable interrupts. + + local_irq_restore(flags) => restore the IRQ state from flags. + +(local_irq_save can save both irqs on and irqs off state, and +local_irq_restore can restore into both irqs on and irqs off state.) + +another related change is that synchronize_irq() now takes a parameter: +synchronize_irq(irq). This change too has the purpose of making SMP +to make the transition easier, we've still kept the cli(), sti(), +save_flags() and restore_flags() macros defined on UP systems - but +their usage will be phased out until the 2.6 kernel is released. + + +why were these changes done? The main reason was the architectural burden +of maintaining the cli()/sti() interface - it became a real problem. The +new interrupt system is much more streamlined, easier to understand, debug, +and it's also a bit faster - the same happened to it that will happen to +cli()/sti() using drivers once they convert to spinlocks :-) + diff --git a/Documentation/preempt-locking.txt b/Documentation/preempt-locking.txt index a9eac1c15718..08e6035a0e13 100644 --- a/Documentation/preempt-locking.txt +++ b/Documentation/preempt-locking.txt @@ -70,7 +70,8 @@ duration of the critical region. preempt_enable() decrement the preempt counter preempt_disable() increment the preempt counter preempt_enable_no_resched() decrement, but do not immediately preempt -preempt_get_count() return the preempt counter +preempt_check_resched() if needed, reschedule +preempt_count() return the preempt counter The functions are nestable. In other words, you can call preempt_disable n-times in a code path, and preemption will not be reenabled until the n-th @@ -81,6 +82,13 @@ Note that you do not need to explicitly prevent preemption if you are holding any locks or interrupts are disabled, since preemption is implicitly disabled in those cases. +But keep in mind that 'irqs disabled' is a fundamentally unsafe way of +disabling preemption - any spin_unlock() decreasing the preemption count +to 0 might trigger a reschedule. A simple printk() might trigger a reschedule. +So use this implicit preemption-disabling property only if you know that the +affected codepath does not do any of this. Best policy is to use this only for +small, atomic code that you wrote and which calls no complex functions. + Example: cpucache_t *cc; /* this is per-CPU */ diff --git a/Documentation/s390/cds.txt b/Documentation/s390/cds.txt index 82f37646bfbc..38aeab5b50df 100644 --- a/Documentation/s390/cds.txt +++ b/Documentation/s390/cds.txt @@ -885,8 +885,8 @@ Usage Notes : Prior to call do_IO() the device driver must assure disabled state, i.e. the I/O mask value in the PSW must be disabled. This can be accomplished by calling -__save_flags( flags). The current PSW flags are preserved and can be restored -by __restore_flags( flags) at a later time. +local_save_flags( flags). The current PSW flags are preserved and can be restored +by local_irq_restore( flags) at a later time. If the device driver violates this rule while running in a uni-processor environment an interrupt might be presented prior to the do_IO() routine diff --git a/Documentation/serial/driver b/Documentation/serial/driver new file mode 100644 index 000000000000..7396d0727927 --- /dev/null +++ b/Documentation/serial/driver @@ -0,0 +1,300 @@ + + Low Level Serial API + -------------------- + + + $Id: driver,v 1.9 2002/07/06 16:51:43 rmk Exp $ + + +This document is meant as a brief overview of some aspects of the new serial +driver. It is not complete, any questions you have should be directed to +<rmk@arm.linux.org.uk> + +The reference implementation is contained within serial_amba.c. + + + +Low Level Serial Hardware Driver +-------------------------------- + +The low level serial hardware driver is responsible for supplying port +information (defined by uart_port) and a set of control methods (defined +by uart_ops) to the core serial driver. The low level driver is also +responsible for handling interrupts for the port, and providing any +console support. + + +Console Support +--------------- + +The serial core provides a few helper functions. This includes identifing +the correct port structure (via uart_get_console) and decoding command line +arguments (uart_parse_options). + + +Locking +------- + +It is the responsibility of the low level hardware driver to perform the +necessary locking using port->lock. There are some exceptions (which +are described in the uart_ops listing below.) + +There are three locks. A per-port spinlock, a per-port tmpbuf semaphore, +and an overall semaphore. + +From the core driver perspective, the port->lock locks the following +data: + + port->mctrl + port->icount + info->xmit.head (circ->head) + info->xmit.tail (circ->tail) + +The low level driver is free to use this lock to provide any additional +locking. + +The core driver uses the info->tmpbuf_sem lock to prevent multi-threaded +access to the info->tmpbuf bouncebuffer used for port writes. + +The port_sem semaphore is used to protect against ports being added/ +removed or reconfigured at inappropriate times. + + +uart_ops +-------- + +The uart_ops structure is the main interface between serial_core and the +hardware specific driver. It contains all the methods to control the +hardware. + + tx_empty(port) + This function tests whether the transmitter fifo and shifter + for the port described by 'port' is empty. If it is empty, + this function should return TIOCSER_TEMT, otherwise return 0. + If the port does not support this operation, then it should + return TIOCSER_TEMT. + + Locking: none. + Interrupts: caller dependent. + This call must not sleep + + set_mctrl(port, mctrl) + This function sets the modem control lines for port described + by 'port' to the state described by mctrl. The relevant bits + of mctrl are: + - TIOCM_RTS RTS signal. + - TIOCM_DTR DTR signal. + - TIOCM_OUT1 OUT1 signal. + - TIOCM_OUT2 OUT2 signal. + If the appropriate bit is set, the signal should be driven + active. If the bit is clear, the signal should be driven + inactive. + + Locking: port->lock taken. + Interrupts: locally disabled. + This call must not sleep + + get_mctrl(port) + Returns the current state of modem control inputs. The state + of the outputs should not be returned, since the core keeps + track of their state. The state information should include: + - TIOCM_DCD state of DCD signal + - TIOCM_CTS state of CTS signal + - TIOCM_DSR state of DSR signal + - TIOCM_RI state of RI signal + The bit is set if the signal is currently driven active. If + the port does not support CTS, DCD or DSR, the driver should + indicate that the signal is permanently active. If RI is + not available, the signal should not be indicated as active. + + Locking: none. + Interrupts: caller dependent. + This call must not sleep + + stop_tx(port,tty_stop) + Stop transmitting characters. This might be due to the CTS + line becoming inactive or the tty layer indicating we want + to stop transmission. + + tty_stop: 1 if this call is due to the TTY layer issuing a + TTY stop to the driver (equiv to rs_stop). + + Locking: none. + Interrupts: caller dependent. + This call must not sleep + + start_tx(port,tty_start) + start transmitting characters. (incidentally, nonempty will + always be nonzero, and shouldn't be used - it will be dropped). + + tty_start: 1 if this call was due to the TTY layer issuing + a TTY start to the driver (equiv to rs_start) + + Locking: port->lock taken. + Interrupts: locally disabled. + This call must not sleep + + stop_rx(port) + Stop receiving characters; the port is in the process of + being closed. + + Locking: none. + Interrupts: caller dependent. + This call must not sleep + + enable_ms(port) + Enable the modem status interrupts. + + Locking: none. + Interrupts: caller dependent. + + break_ctl(port,ctl) + Control the transmission of a break signal. If ctl is + nonzero, the break signal should be transmitted. The signal + should be terminated when another call is made with a zero + ctl. + + Locking: none. + Interrupts: caller dependent. + This call must not sleep + + startup(port) + Grab any interrupt resources and initialise any low level driver + state. Enable the port for reception. It should not activate + RTS nor DTR; this will be done via a separate call to set_mctrl. + + Locking: port_sem taken. + Interrupts: globally disabled. + + shutdown(port) + Disable the port, disable any break condition that may be in + effect, and free any interrupt resources. It should not disable + RTS nor DTR; this will have already been done via a separate + call to set_mctrl. + + Locking: port_sem taken. + Interrupts: caller dependent. + + change_speed(port,cflag,iflag,quot) + Change the port parameters, including word length, parity, stop + bits. Update read_status_mask and ignore_status_mask to indicate + the types of events we are interested in receiving. Relevant + cflag bits are: + CSIZE - word size + CSTOPB - 2 stop bits + PARENB - parity enable + PARODD - odd parity (when PARENB is in force) + CREAD - enable reception of characters (if not set, + still receive characters from the port, but + throw them away. + CRTSCTS - if set, enable CTS status change reporting + CLOCAL - if not set, enable modem status change + reporting. + Relevant iflag bits are: + INPCK - enable frame and parity error events to be + passed to the TTY layer. + BRKINT + PARMRK - both of these enable break events to be + passed to the TTY layer. + + IGNPAR - ignore parity and framing errors + IGNBRK - ignore break errors, If IGNPAR is also + set, ignore overrun errors as well. + The interaction of the iflag bits is as follows (parity error + given as an example): + Parity error INPCK IGNPAR + None n/a n/a character received + Yes n/a 0 character discarded + Yes 0 1 character received, marked as + TTY_NORMAL + Yes 1 1 character received, marked as + TTY_PARITY + + Locking: none. + Interrupts: caller dependent. + This call must not sleep + + pm(port,state,oldstate) + perform any power management related activities on the specified + port. state indicates the new state (defined by ACPI D0-D3), + oldstate indicates the previous state. Essentially, D0 means + fully on, D3 means powered down. + + This function should not be used to grab any resources. + + Locking: none. + Interrupts: caller dependent. + + type(port) + Return a pointer to a string constant describing the specified + port, or return NULL, in which case the string 'unknown' is + substituted. + + Locking: none. + Interrupts: caller dependent. + + release_port(port) + Release any memory and IO region resources currently in use by + the port. + + Locking: none. + Interrupts: caller dependent. + + request_port(port) + Request any memory and IO region resources required by the port. + If any fail, no resources should be registered when this function + returns, and it should return -EBUSY on failure. + + Locking: none. + Interrupts: caller dependent. + + config_port(port,type) + Perform any autoconfiguration steps required for the port. `type` + contains a bit mask of the required configuration. UART_CONFIG_TYPE + indicates that the port requires detection and identification. + port->type should be set to the type found, or PORT_UNKNOWN if + no port was detected. + + UART_CONFIG_IRQ indicates autoconfiguration of the interrupt signal, + which should be probed using standard kernel autoprobing techniques. + This is not necessary on platforms where ports have interrupts + internally hard wired (eg, system on a chip implementations). + + Locking: none. + Interrupts: caller dependent. + + verify_port(port,serinfo) + Verify the new serial port information contained within serinfo is + suitable for this port type. + + Locking: none. + Interrupts: caller dependent. + + ioctl(port,cmd,arg) + Perform any port specific IOCTLs. IOCTL commands must be defined + using the standard numbering system found in <asm/ioctl.h> + + Locking: none. + Interrupts: caller dependent. + + +Other notes +----------- + +It is intended some day to drop the 'unused' entries from uart_port, and +allow low level drivers to register their own individual uart_port's with +the core. This will allow drivers to use uart_port as a pointer to a +structure containing both the uart_port entry with their own extensions, +thus: + + struct my_port { + struct uart_port port; + int my_stuff; + }; + +Todo +---- + +Please see the BUGS file in CVS at + + http://cvs.arm.linux.org.uk/cgi/viewcvs.cgi/serial/BUGS @@ -212,7 +212,7 @@ export MODLIB CPPFLAGS := -D__KERNEL__ -I$(HPATH) -CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \ +CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 -g \ -fomit-frame-pointer -fno-strict-aliasing -fno-common AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS) diff --git a/arch/alpha/kernel/core_apecs.c b/arch/alpha/kernel/core_apecs.c index a44d941c0e3f..37e84ec2eee6 100644 --- a/arch/alpha/kernel/core_apecs.c +++ b/arch/alpha/kernel/core_apecs.c @@ -131,7 +131,7 @@ conf_read(unsigned long addr, unsigned char type1) unsigned int stat0, value; unsigned int haxr2 = 0; - __save_and_cli(flags); /* avoid getting hit by machine check */ + local_irq_save(flags); /* avoid getting hit by machine check */ DBGC(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); @@ -201,7 +201,7 @@ conf_read(unsigned long addr, unsigned char type1) *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1; mb(); } - __restore_flags(flags); + local_irq_restore(flags); return value; } @@ -213,7 +213,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1) unsigned int stat0; unsigned int haxr2 = 0; - __save_and_cli(flags); /* avoid getting hit by machine check */ + local_irq_save(flags); /* avoid getting hit by machine check */ /* Reset status register to avoid losing errors. */ stat0 = *(vuip)APECS_IOC_DCSR; @@ -269,7 +269,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1) *(vuip)APECS_IOC_HAXR2 = haxr2 & ~1; mb(); } - __restore_flags(flags); + local_irq_restore(flags); } static int diff --git a/arch/alpha/kernel/core_cia.c b/arch/alpha/kernel/core_cia.c index 9990c2554fa0..e7f7abd7338f 100644 --- a/arch/alpha/kernel/core_cia.c +++ b/arch/alpha/kernel/core_cia.c @@ -113,7 +113,7 @@ conf_read(unsigned long addr, unsigned char type1) int cia_cfg = 0; DBGC(("conf_read(addr=0x%lx, type1=%d) ", addr, type1)); - __save_and_cli(flags); + local_irq_save(flags); /* Reset status register to avoid losing errors. */ stat0 = *(vip)CIA_IOC_CIA_ERR; @@ -154,7 +154,7 @@ conf_read(unsigned long addr, unsigned char type1) *(vip)CIA_IOC_CFG; } - __restore_flags(flags); + local_irq_restore(flags); DBGC(("done\n")); return value; @@ -167,7 +167,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1) int stat0, cia_cfg = 0; DBGC(("conf_write(addr=0x%lx, type1=%d) ", addr, type1)); - __save_and_cli(flags); + local_irq_save(flags); /* Reset status register to avoid losing errors. */ stat0 = *(vip)CIA_IOC_CIA_ERR; @@ -204,7 +204,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1) *(vip)CIA_IOC_CFG; } - __restore_flags(flags); + local_irq_restore(flags); DBGC(("done\n")); } diff --git a/arch/alpha/kernel/core_lca.c b/arch/alpha/kernel/core_lca.c index 28d743dd5bb6..e6c3928fe259 100644 --- a/arch/alpha/kernel/core_lca.c +++ b/arch/alpha/kernel/core_lca.c @@ -132,7 +132,7 @@ conf_read(unsigned long addr) unsigned long flags, code, stat0; unsigned int value; - __save_and_cli(flags); + local_irq_save(flags); /* Reset status register to avoid loosing errors. */ stat0 = *(vulp)LCA_IOC_STAT0; @@ -160,7 +160,7 @@ conf_read(unsigned long addr) value = 0xffffffff; } - __restore_flags(flags); + local_irq_restore(flags); return value; } @@ -169,7 +169,7 @@ conf_write(unsigned long addr, unsigned int value) { unsigned long flags, code, stat0; - __save_and_cli(flags); /* avoid getting hit by machine check */ + local_irq_save(flags); /* avoid getting hit by machine check */ /* Reset status register to avoid loosing errors. */ stat0 = *(vulp)LCA_IOC_STAT0; @@ -195,7 +195,7 @@ conf_write(unsigned long addr, unsigned int value) /* Reset machine check. */ wrmces(0x7); } - __restore_flags(flags); + local_irq_restore(flags); } static int diff --git a/arch/alpha/kernel/core_mcpcia.c b/arch/alpha/kernel/core_mcpcia.c index fec67208f1ff..655ed6757535 100644 --- a/arch/alpha/kernel/core_mcpcia.c +++ b/arch/alpha/kernel/core_mcpcia.c @@ -97,7 +97,7 @@ conf_read(unsigned long addr, unsigned char type1, cpu = smp_processor_id(); - __save_and_cli(flags); + local_irq_save(flags); DBG_CFG(("conf_read(addr=0x%lx, type1=%d, hose=%d)\n", addr, type1, mid)); @@ -131,7 +131,7 @@ conf_read(unsigned long addr, unsigned char type1, DBG_CFG(("conf_read(): finished\n")); - __restore_flags(flags); + local_irq_restore(flags); return value; } @@ -145,7 +145,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1, cpu = smp_processor_id(); - __save_and_cli(flags); /* avoid getting hit by machine check */ + local_irq_save(flags); /* avoid getting hit by machine check */ /* Reset status register to avoid losing errors. */ stat0 = *(vuip)MCPCIA_CAP_ERR(mid); @@ -167,7 +167,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1, mb(); DBG_CFG(("conf_write(): finished\n")); - __restore_flags(flags); + local_irq_restore(flags); } static int diff --git a/arch/alpha/kernel/core_t2.c b/arch/alpha/kernel/core_t2.c index 1fd7d126673e..04968c726b70 100644 --- a/arch/alpha/kernel/core_t2.c +++ b/arch/alpha/kernel/core_t2.c @@ -132,7 +132,7 @@ conf_read(unsigned long addr, unsigned char type1) cpu = smp_processor_id(); - __save_and_cli(flags); /* avoid getting hit by machine check */ + local_irq_save(flags); /* avoid getting hit by machine check */ DBG(("conf_read(addr=0x%lx, type1=%d)\n", addr, type1)); @@ -181,7 +181,7 @@ conf_read(unsigned long addr, unsigned char type1) } DBG(("conf_read(): finished\n")); - __restore_flags(flags); + local_irq_restore(flags); return value; } @@ -194,7 +194,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1) cpu = smp_processor_id(); - __save_and_cli(flags); /* avoid getting hit by machine check */ + local_irq_save(flags); /* avoid getting hit by machine check */ #if 0 { @@ -234,7 +234,7 @@ conf_write(unsigned long addr, unsigned int value, unsigned char type1) mb(); } DBG(("conf_write(): finished\n")); - __restore_flags(flags); + local_irq_restore(flags); } static int diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index a83d387a4c67..a1fa9a32544d 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -85,9 +85,9 @@ handle_IRQ_event(unsigned int irq, struct pt_regs *regs, do { if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); else - __cli(); + local_irq_disable(); status |= action->flags; action->handler(irq, action->dev_id, regs); @@ -95,7 +95,7 @@ handle_IRQ_event(unsigned int irq, struct pt_regs *regs, } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); irq_exit(cpu, irq); diff --git a/arch/alpha/kernel/irq_smp.c b/arch/alpha/kernel/irq_smp.c index 37f866966c5b..2828b34a599e 100644 --- a/arch/alpha/kernel/irq_smp.c +++ b/arch/alpha/kernel/irq_smp.c @@ -85,9 +85,9 @@ wait_on_irq(int cpu, void *where) show("wait_on_irq", where); count = MAXCOUNT; } - __sti(); + local_irq_enable(); udelay(1); /* make sure to run pending irqs */ - __cli(); + local_irq_disable(); if (irqs_running()) continue; @@ -153,7 +153,7 @@ __global_sti(void) if (!local_irq_count(cpu)) release_irqlock(cpu); - __sti(); + local_irq_enable(); } /* @@ -171,7 +171,7 @@ __global_save_flags(void) unsigned long flags; int cpu = smp_processor_id(); - __save_flags(flags); + local_save_flags(flags); local_enabled = (!(flags & 7)); /* default to local */ retval = 2 + local_enabled; @@ -197,10 +197,10 @@ __global_restore_flags(unsigned long flags) __global_sti(); break; case 2: - __cli(); + local_irq_disable(); break; case 3: - __sti(); + local_irq_enable(); break; default: printk(KERN_ERR "global_restore_flags: %08lx (%p)\n", diff --git a/arch/alpha/kernel/ns87312.c b/arch/alpha/kernel/ns87312.c index 8f690e43eacb..342b56d24c20 100644 --- a/arch/alpha/kernel/ns87312.c +++ b/arch/alpha/kernel/ns87312.c @@ -28,11 +28,11 @@ ns87312_enable_ide(long ide_base) int data; unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); outb(0, ide_base); /* set the index register for reg #0 */ data = inb(ide_base+1); /* read the current contents */ outb(0, ide_base); /* set the index register for reg #0 */ outb(data | 0x40, ide_base+1); /* turn on IDE */ outb(data | 0x40, ide_base+1); /* turn on IDE, really! */ - __restore_flags(flags); + local_irq_restore(flags); } diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index 8bc1ea59652f..ae466ff90696 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -88,7 +88,7 @@ common_shutdown_1(void *generic_ptr) int cpuid = smp_processor_id(); /* No point in taking interrupts anymore. */ - __cli(); + local_irq_disable(); cpup = (struct percpu_struct *) ((unsigned long)hwrpb + hwrpb->processor_offset diff --git a/arch/alpha/kernel/smc37c669.c b/arch/alpha/kernel/smc37c669.c index 8a817233a075..40bb0c1654d4 100644 --- a/arch/alpha/kernel/smc37c669.c +++ b/arch/alpha/kernel/smc37c669.c @@ -2486,7 +2486,7 @@ void __init SMC669_Init ( int index ) SMC37c669_CONFIG_REGS *SMC_base; unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); if ( ( SMC_base = SMC37c669_detect( index ) ) != NULL ) { #if SMC_DEBUG SMC37c669_config_mode( TRUE ); @@ -2541,12 +2541,12 @@ void __init SMC669_Init ( int index ) SMC37c669_config_mode( FALSE ); SMC37c669_display_device_info( ); #endif - __restore_flags(flags); + local_irq_restore(flags); printk( "SMC37c669 Super I/O Controller found @ 0x%lx\n", (unsigned long) SMC_base ); } else { - __restore_flags(flags); + local_irq_restore(flags); #if SMC_DEBUG printk( "No SMC37c669 Super I/O Controller found\n" ); #endif diff --git a/arch/alpha/kernel/smc37c93x.c b/arch/alpha/kernel/smc37c93x.c index b0e15d307562..421e51ea6bb7 100644 --- a/arch/alpha/kernel/smc37c93x.c +++ b/arch/alpha/kernel/smc37c93x.c @@ -243,7 +243,7 @@ int __init SMC93x_Init(void) unsigned long SMCUltraBase; unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); if ((SMCUltraBase = SMCDetectUltraIO()) != 0UL) { #if SMC_DEBUG SMCReportDeviceStatus(SMCUltraBase); @@ -264,13 +264,13 @@ int __init SMC93x_Init(void) SMCReportDeviceStatus(SMCUltraBase); #endif SMCRunState(SMCUltraBase); - __restore_flags(flags); + local_irq_restore(flags); printk("SMC FDC37C93X Ultra I/O Controller found @ 0x%lx\n", SMCUltraBase); return 1; } else { - __restore_flags(flags); + local_irq_restore(flags); DBG_DEVS(("No SMC FDC37C93X Ultra I/O Controller found\n")); return 0; } diff --git a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c index f20a8b08594a..41c904b7515d 100644 --- a/arch/alpha/kernel/smp.c +++ b/arch/alpha/kernel/smp.c @@ -175,7 +175,7 @@ smp_callin(void) current->active_mm = &init_mm; /* Must have completely accurate bogos. */ - __sti(); + local_irq_enable(); /* Wait boot CPU to stop with irq enabled before running calibrate_delay. */ diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index c99e1ecd8b40..79b647132c55 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -190,7 +190,7 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) spin_unlock(&irq_controller_lock); if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); status = 0; do { diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c index 5f2dda734984..9f4c92a2e906 100644 --- a/arch/cris/kernel/irq.c +++ b/arch/cris/kernel/irq.c @@ -266,7 +266,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) action = irq_action[irq]; if (action) { if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); action = irq_action[irq]; do_random = 0; do { @@ -276,7 +276,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) } while (action); if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); } irq_exit(cpu); diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c index c86358a1249f..19f45080e906 100644 --- a/arch/i386/kernel/apic.c +++ b/arch/i386/kernel/apic.c @@ -485,13 +485,13 @@ static void apic_pm_suspend(void *data) apic_pm_state.apic_tdcr = apic_read(APIC_TDCR); apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR); - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); disable_local_APIC(); rdmsr(MSR_IA32_APICBASE, l, h); l &= ~MSR_IA32_APICBASE_ENABLE; wrmsr(MSR_IA32_APICBASE, l, h); - __restore_flags(flags); + local_irq_restore(flags); } static void apic_pm_resume(void *data) @@ -499,8 +499,8 @@ static void apic_pm_resume(void *data) unsigned int l, h; unsigned long flags; - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); rdmsr(MSR_IA32_APICBASE, l, h); l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; @@ -523,7 +523,7 @@ static void apic_pm_resume(void *data) apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); - __restore_flags(flags); + local_irq_restore(flags); if (apic_pm_state.perfctr_pmdev) pm_send(apic_pm_state.perfctr_pmdev, PM_RESUME, data); } @@ -804,8 +804,8 @@ void setup_APIC_timer(void * data) unsigned long flags; int delta; - __save_flags(flags); - __sti(); + local_save_flags(flags); + local_irq_enable(); /* * ok, Intel has some smart code in their APIC that knows * if a CPU was in 'hlt' lowpower mode, and this increases @@ -842,7 +842,7 @@ void setup_APIC_timer(void * data) printk("CPU%d<T0:%d,T1:%d,D:%d,S:%d,C:%d>\n", smp_processor_id(), t0, t1, delta, slice, clocks); - __restore_flags(flags); + local_irq_restore(flags); } /* @@ -935,7 +935,7 @@ void __init setup_APIC_clocks (void) printk("Using local APIC timer interrupts.\n"); using_apic_timer = 1; - __cli(); + local_irq_disable(); calibration_result = calibrate_APIC_clock(); /* @@ -943,7 +943,7 @@ void __init setup_APIC_clocks (void) */ setup_APIC_timer((void *)calibration_result); - __sti(); + local_irq_enable(); /* and update all other cpus */ smp_call_function(setup_APIC_timer, (void *)calibration_result, 1, 1); @@ -1084,9 +1084,9 @@ void smp_apic_timer_interrupt(struct pt_regs regs) * Besides, if we don't timer interrupts ignore the global * interrupt lock, which is the WrongThing (tm) to do. */ - irq_enter(cpu, 0); + irq_enter(); smp_local_timer_interrupt(®s); - irq_exit(cpu, 0); + irq_exit(); if (softirq_pending(cpu)) do_softirq(); @@ -1099,6 +1099,7 @@ asmlinkage void smp_spurious_interrupt(void) { unsigned long v; + irq_enter(); /* * Check if this really is a spurious interrupt and ACK it * if it is a vectored one. Just in case... @@ -1111,6 +1112,7 @@ asmlinkage void smp_spurious_interrupt(void) /* see sw-dev-man vol 3, chapter 7.4.13.5 */ printk(KERN_INFO "spurious APIC interrupt on CPU#%d, should never happen.\n", smp_processor_id()); + irq_exit(); } /* @@ -1121,6 +1123,7 @@ asmlinkage void smp_error_interrupt(void) { unsigned long v, v1; + irq_enter(); /* First tickle the hardware, only then report what went on. -- REW */ v = apic_read(APIC_ESR); apic_write(APIC_ESR, 0); @@ -1140,6 +1143,7 @@ asmlinkage void smp_error_interrupt(void) */ printk (KERN_ERR "APIC error on CPU%d: %02lx(%02lx)\n", smp_processor_id(), v , v1); + irq_exit(); } /* diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 11c3c42185cd..1dfd424a2eb9 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -222,6 +222,8 @@ #include <linux/sysrq.h> +extern rwlock_t xtime_lock; +extern spinlock_t i8253_lock; extern unsigned long get_cmos_time(void); extern void machine_real_restart(unsigned char *, int); @@ -512,9 +514,9 @@ static void apm_error(char *str, int err) */ #define APM_DO_CLI \ if (apm_info.allow_ints) \ - __sti(); \ + local_irq_enable(); \ else \ - __cli(); + local_irq_disable(); #ifdef APM_ZERO_SEGS # define APM_DECL_SEGS \ @@ -568,7 +570,7 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in, APM_DECL_SEGS unsigned long flags; - __save_flags(flags); + local_save_flags(flags); APM_DO_CLI; APM_DO_SAVE_SEGS; /* @@ -588,7 +590,7 @@ static u8 apm_bios_call(u32 func, u32 ebx_in, u32 ecx_in, : "a" (func), "b" (ebx_in), "c" (ecx_in) : "memory", "cc"); APM_DO_RESTORE_SEGS; - __restore_flags(flags); + local_irq_restore(flags); return *eax & 0xff; } @@ -612,7 +614,7 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax) APM_DECL_SEGS unsigned long flags; - __save_flags(flags); + local_save_flags(flags); APM_DO_CLI; APM_DO_SAVE_SEGS; { @@ -636,7 +638,7 @@ static u8 apm_bios_call_simple(u32 func, u32 ebx_in, u32 ecx_in, u32 *eax) : "memory", "cc"); } APM_DO_RESTORE_SEGS; - __restore_flags(flags); + local_irq_restore(flags); return error; } @@ -1141,40 +1143,25 @@ out: static void set_time(void) { - unsigned long flags; - - if (got_clock_diff) { /* Must know time zone in order to set clock */ - save_flags(flags); - cli(); + if (got_clock_diff) /* Must know time zone in order to set clock */ CURRENT_TIME = get_cmos_time() + clock_cmos_diff; - restore_flags(flags); - } } static void get_time_diff(void) { #ifndef CONFIG_APM_RTC_IS_GMT - unsigned long flags; - /* * Estimate time zone so that set_time can update the clock */ - save_flags(flags); clock_cmos_diff = -get_cmos_time(); - cli(); clock_cmos_diff += CURRENT_TIME; got_clock_diff = 1; - restore_flags(flags); #endif } -static void reinit_timer(void) +static inline void reinit_timer(void) { #ifdef INIT_TIMER_AFTER_SUSPEND - unsigned long flags; - - save_flags(flags); - cli(); /* set the clock to 100 Hz */ outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ udelay(10); @@ -1182,7 +1169,6 @@ static void reinit_timer(void) udelay(10); outb(LATCH >> 8 , 0x40); /* MSB */ udelay(10); - restore_flags(flags); #endif } @@ -1203,13 +1189,21 @@ static int suspend(int vetoable) } printk(KERN_CRIT "apm: suspend was vetoed, but suspending anyway.\n"); } + /* serialize with the timer interrupt */ + write_lock_irq(&xtime_lock); + + /* protect against access to timer chip registers */ + spin_lock(&i8253_lock); + get_time_diff(); - cli(); err = set_system_power_state(APM_STATE_SUSPEND); reinit_timer(); set_time(); ignore_normal_resume = 1; - sti(); + + spin_unlock(&i8253_lock); + write_unlock_irq(&xtime_lock); + if (err == APM_NO_ERROR) err = APM_SUCCESS; if (err != APM_SUCCESS) @@ -1232,8 +1226,12 @@ static void standby(void) { int err; + /* serialize with the timer interrupt */ + write_lock_irq(&xtime_lock); /* If needed, notify drivers here */ get_time_diff(); + write_unlock_irq(&xtime_lock); + err = set_system_power_state(APM_STATE_STANDBY); if ((err != APM_SUCCESS) && (err != APM_NO_ERROR)) apm_error("standby", err); @@ -1321,7 +1319,9 @@ static void check_events(void) ignore_bounce = 1; if ((event != APM_NORMAL_RESUME) || (ignore_normal_resume == 0)) { + write_lock_irq(&xtime_lock); set_time(); + write_unlock_irq(&xtime_lock); pm_send_all(PM_RESUME, (void *)0); queue_event(event, NULL); } @@ -1336,7 +1336,9 @@ static void check_events(void) break; case APM_UPDATE_TIME: + write_lock_irq(&xtime_lock); set_time(); + write_unlock_irq(&xtime_lock); break; case APM_CRITICAL_SUSPEND: diff --git a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c index 9a1c05eddf55..f2a9920996a8 100644 --- a/arch/i386/kernel/bluesmoke.c +++ b/arch/i386/kernel/bluesmoke.c @@ -10,12 +10,14 @@ #include <linux/config.h> #include <linux/irq.h> #include <linux/tqueue.h> + #include <asm/processor.h> #include <asm/system.h> #include <asm/msr.h> #include <asm/apic.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> +#include <asm/hardirq.h> #ifdef CONFIG_X86_MCE @@ -74,7 +76,9 @@ static void (*vendor_thermal_interrupt)(struct pt_regs *regs) = unexpected_therm asmlinkage void smp_thermal_interrupt(struct pt_regs regs) { + irq_enter(); vendor_thermal_interrupt(®s); + irq_exit(); } /* P4/Xeon Thermal regulation detect and init */ diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c index 8b30e6628f3b..8a8305d024f3 100644 --- a/arch/i386/kernel/cpu/common.c +++ b/arch/i386/kernel/cpu/common.c @@ -426,7 +426,7 @@ void __init cpu_init (void) if (test_and_set_bit(nr, &cpu_initialized)) { printk(KERN_WARNING "CPU#%d already initialized!\n", nr); - for (;;) __sti(); + for (;;) local_irq_enable(); } printk(KERN_INFO "Initializing CPU#%d\n", nr); diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index c068803128c8..641062bbcbf2 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S @@ -72,12 +72,8 @@ VM_MASK = 0x00020000 #ifdef CONFIG_PREEMPT #define preempt_stop cli -#define INC_PRE_COUNT(reg) incl TI_PRE_COUNT(reg); -#define DEC_PRE_COUNT(reg) decl TI_PRE_COUNT(reg); #else #define preempt_stop -#define INC_PRE_COUNT(reg) -#define DEC_PRE_COUNT(reg) #define resume_kernel restore_all #endif @@ -190,8 +186,6 @@ ENTRY(ret_from_fork) # userspace resumption stub bypassing syscall exit tracing ALIGN ret_from_intr: - preempt_stop - DEC_PRE_COUNT(%ebx) ret_from_exception: movl EFLAGS(%esp), %eax # mix EFLAGS and CS movb CS(%esp), %al @@ -338,9 +332,8 @@ vector=vector+1 ALIGN common_interrupt: SAVE_ALL - GET_THREAD_INFO(%ebx) - INC_PRE_COUNT(%ebx) call do_IRQ + GET_THREAD_INFO(%ebx) jmp ret_from_intr #define BUILD_INTERRUPT(name, nr) \ @@ -348,7 +341,6 @@ ENTRY(name) \ pushl $nr-256; \ SAVE_ALL \ GET_THREAD_INFO(%ebx); \ - INC_PRE_COUNT(%ebx) \ call smp_/**/name; \ jmp ret_from_intr; diff --git a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c index 86ce6170a11d..04bbafb264ec 100644 --- a/arch/i386/kernel/i386_ksyms.c +++ b/arch/i386/kernel/i386_ksyms.c @@ -132,13 +132,7 @@ EXPORT_SYMBOL(cpu_online_map); EXPORT_SYMBOL_NOVERS(__write_lock_failed); EXPORT_SYMBOL_NOVERS(__read_lock_failed); -/* Global SMP irq stuff */ -EXPORT_SYMBOL(synchronize_irq); -EXPORT_SYMBOL(global_irq_holder); -EXPORT_SYMBOL(__global_cli); -EXPORT_SYMBOL(__global_sti); -EXPORT_SYMBOL(__global_save_flags); -EXPORT_SYMBOL(__global_restore_flags); +/* Global SMP stuff */ EXPORT_SYMBOL(smp_call_function); /* TLB flushing */ diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index d09e00d867da..a2ca84337699 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -1219,7 +1219,7 @@ static int __init timer_irq_works(void) { unsigned int t1 = jiffies; - sti(); + local_irq_enable(); /* Let ten ticks pass... */ mdelay((10 * 1000) / HZ); diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 4265cb038a5a..7acd3f1417b9 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -184,250 +184,12 @@ int show_interrupts(struct seq_file *p, void *v) return 0; } -/* - * Global interrupt locks for SMP. Allow interrupts to come in on any - * CPU, yet make cli/sti act globally to protect critical regions.. - */ - -#ifdef CONFIG_SMP -unsigned char global_irq_holder = NO_PROC_ID; -unsigned volatile long global_irq_lock; /* pendantic: long for set_bit --RR */ - -extern void show_stack(unsigned long* esp); - -static void show(char * str) -{ - int i; - int cpu = smp_processor_id(); - - printk("\n%s, CPU %d:\n", str, cpu); - printk("irq: %d [",irqs_running()); - for(i=0;i < NR_CPUS;i++) - printk(" %d",local_irq_count(i)); - printk(" ]\nbh: %d [",spin_is_locked(&global_bh_lock) ? 1 : 0); - for(i=0;i < NR_CPUS;i++) - printk(" %d",local_bh_count(i)); - - printk(" ]\nStack dumps:"); - for(i = 0; i < NR_CPUS; i++) { - unsigned long esp; - if (i == cpu) - continue; - printk("\nCPU %d:",i); - esp = init_tss[i].esp0; - if (!esp) { - /* tss->esp0 is set to NULL in cpu_init(), - * it's initialized when the cpu returns to user - * space. -- manfreds - */ - printk(" <unknown> "); - continue; - } - esp &= ~(THREAD_SIZE-1); - esp += sizeof(struct thread_info); - show_stack((void*)esp); - } - printk("\nCPU %d:",cpu); - show_stack(NULL); - printk("\n"); -} - -#define MAXCOUNT 100000000 - -/* - * I had a lockup scenario where a tight loop doing - * spin_unlock()/spin_lock() on CPU#1 was racing with - * spin_lock() on CPU#0. CPU#0 should have noticed spin_unlock(), but - * apparently the spin_unlock() information did not make it - * through to CPU#0 ... nasty, is this by design, do we have to limit - * 'memory update oscillation frequency' artificially like here? - * - * Such 'high frequency update' races can be avoided by careful design, but - * some of our major constructs like spinlocks use similar techniques, - * it would be nice to clarify this issue. Set this define to 0 if you - * want to check whether your system freezes. I suspect the delay done - * by SYNC_OTHER_CORES() is in correlation with 'snooping latency', but - * i thought that such things are guaranteed by design, since we use - * the 'LOCK' prefix. - */ -#define SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND 0 - -#if SUSPECTED_CPU_OR_CHIPSET_BUG_WORKAROUND -# define SYNC_OTHER_CORES(x) udelay(x+1) -#else -/* - * We have to allow irqs to arrive between __sti and __cli - */ -# define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") -#endif - -static inline void wait_on_irq(int cpu) -{ - int count = MAXCOUNT; - - for (;;) { - - /* - * Wait until all interrupts are gone. Wait - * for bottom half handlers unless we're - * already executing in one.. - */ - if (!irqs_running()) - if (local_bh_count(cpu) || !spin_is_locked(&global_bh_lock)) - break; - - /* Duh, we have to loop. Release the lock to avoid deadlocks */ - clear_bit(0,&global_irq_lock); - - for (;;) { - if (!--count) { - show("wait_on_irq"); - count = ~0; - } - __sti(); - SYNC_OTHER_CORES(cpu); - __cli(); - if (irqs_running()) - continue; - if (global_irq_lock) - continue; - if (!local_bh_count(cpu) && spin_is_locked(&global_bh_lock)) - continue; - if (!test_and_set_bit(0,&global_irq_lock)) - break; - } - } -} - -/* - * This is called when we want to synchronize with - * interrupts. We may for example tell a device to - * stop sending interrupts: but to make sure there - * are no interrupts that are executing on another - * CPU we need to call this function. - */ -void synchronize_irq(void) -{ - if (irqs_running()) { - /* Stupid approach */ - cli(); - sti(); - } -} - -static inline void get_irqlock(int cpu) -{ - if (test_and_set_bit(0,&global_irq_lock)) { - /* do we already hold the lock? */ - if ((unsigned char) cpu == global_irq_holder) - return; - /* Uhhuh.. Somebody else got it. Wait.. */ - do { - do { - rep_nop(); - } while (test_bit(0,&global_irq_lock)); - } while (test_and_set_bit(0,&global_irq_lock)); - } - /* - * We also to make sure that nobody else is running - * in an interrupt context. - */ - wait_on_irq(cpu); - - /* - * Ok, finally.. - */ - global_irq_holder = cpu; -} - -#define EFLAGS_IF_SHIFT 9 - -/* - * A global "cli()" while in an interrupt context - * turns into just a local cli(). Interrupts - * should use spinlocks for the (very unlikely) - * case that they ever want to protect against - * each other. - * - * If we already have local interrupts disabled, - * this will not turn a local disable into a - * global one (problems with spinlocks: this makes - * save_flags+cli+sti usable inside a spinlock). - */ -void __global_cli(void) -{ - unsigned int flags; - - __save_flags(flags); - if (flags & (1 << EFLAGS_IF_SHIFT)) { - int cpu; - __cli(); - cpu = smp_processor_id(); - if (!local_irq_count(cpu)) - get_irqlock(cpu); - } -} - -void __global_sti(void) -{ - int cpu = get_cpu(); - - if (!local_irq_count(cpu)) - release_irqlock(cpu); - __sti(); - put_cpu(); -} - -/* - * SMP flags value to restore to: - * 0 - global cli - * 1 - global sti - * 2 - local cli - * 3 - local sti - */ -unsigned long __global_save_flags(void) -{ - int retval; - int local_enabled; - unsigned long flags; - int cpu = smp_processor_id(); - - __save_flags(flags); - local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1; - /* default to local */ - retval = 2 + local_enabled; - - /* check for global flags if we're not in an interrupt */ - if (!local_irq_count(cpu)) { - if (local_enabled) - retval = 1; - if (global_irq_holder == cpu) - retval = 0; - } - return retval; -} - -void __global_restore_flags(unsigned long flags) +#if CONFIG_SMP +inline void synchronize_irq(unsigned int irq) { - switch (flags) { - case 0: - __global_cli(); - break; - case 1: - __global_sti(); - break; - case 2: - __cli(); - break; - case 3: - __sti(); - break; - default: - printk("global_restore_flags: %08lx (%08lx)\n", - flags, (&flags)[-1]); - } + while (irq_desc[irq].status & IRQ_INPROGRESS) + cpu_relax(); } - #endif /* @@ -439,15 +201,10 @@ void __global_restore_flags(unsigned long flags) */ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action) { - int status; - int cpu = smp_processor_id(); - - irq_enter(cpu, irq); - - status = 1; /* Force the "do bottom halves" bit */ + int status = 1; /* Force the "do bottom halves" bit */ if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); do { status |= action->flags; @@ -456,9 +213,7 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); - - irq_exit(cpu, irq); + local_irq_disable(); return status; } @@ -511,13 +266,7 @@ inline void disable_irq_nosync(unsigned int irq) void disable_irq(unsigned int irq) { disable_irq_nosync(irq); - - if (!local_irq_count(smp_processor_id())) { - do { - barrier(); - cpu_relax(); - } while (irq_desc[irq].status & IRQ_INPROGRESS); - } + synchronize_irq(irq); } /** @@ -581,6 +330,7 @@ asmlinkage unsigned int do_IRQ(struct pt_regs regs) struct irqaction * action; unsigned int status; + irq_enter(); kstat.irqs[cpu][irq]++; spin_lock(&desc->lock); desc->handler->ack(irq); @@ -640,6 +390,8 @@ out: desc->handler->end(irq); spin_unlock(&desc->lock); + irq_exit(); + if (softirq_pending(cpu)) do_softirq(); return 1; @@ -768,13 +520,8 @@ void free_irq(unsigned int irq, void *dev_id) } spin_unlock_irqrestore(&desc->lock,flags); -#ifdef CONFIG_SMP /* Wait to make sure it's not being used on another CPU */ - while (desc->status & IRQ_INPROGRESS) { - barrier(); - cpu_relax(); - } -#endif + synchronize_irq(irq); kfree(action); return; } @@ -826,7 +573,7 @@ unsigned long probe_irq_on(void) /* Wait for longstanding interrupts to trigger. */ for (delay = jiffies + HZ/50; time_after(delay, jiffies); ) - /* about 20ms delay */ synchronize_irq(); + /* about 20ms delay */ barrier(); /* * enable any unassigned irqs @@ -849,7 +596,7 @@ unsigned long probe_irq_on(void) * Wait for spurious interrupts to trigger */ for (delay = jiffies + HZ/10; time_after(delay, jiffies); ) - /* about 100ms delay */ synchronize_irq(); + /* about 100ms delay */ barrier(); /* * Now filter out any obviously spurious interrupts diff --git a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c index 1d6877dc2a91..01adbef69e2d 100644 --- a/arch/i386/kernel/ldt.c +++ b/arch/i386/kernel/ldt.c @@ -107,7 +107,8 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) void release_segments(struct mm_struct *mm) { if (mm->context.size) { - clear_LDT(); + if (mm == current->active_mm) + clear_LDT(); if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE) vfree(mm->context.ldt); else diff --git a/arch/i386/kernel/mca.c b/arch/i386/kernel/mca.c index dc7db1cdce4c..067dafca3a6c 100644 --- a/arch/i386/kernel/mca.c +++ b/arch/i386/kernel/mca.c @@ -102,6 +102,12 @@ struct MCA_info { static struct MCA_info* mca_info = NULL; +/* + * Motherboard register spinlock. Untested on SMP at the moment, but + * are there any MCA SMP boxes? + */ +static spinlock_t mca_lock = SPIN_LOCK_UNLOCKED; + /* MCA registers */ #define MCA_MOTHERBOARD_SETUP_REG 0x94 @@ -213,8 +219,11 @@ void __init mca_init(void) } memset(mca_info, 0, sizeof(struct MCA_info)); - save_flags(flags); - cli(); + /* + * We do not expect many MCA interrupts during initialization, + * but let us be safe: + */ + spin_lock_irq(&mca_lock); /* Make sure adapter setup is off */ @@ -300,8 +309,7 @@ void __init mca_init(void) outb_p(0, MCA_ADAPTER_SETUP_REG); /* Enable interrupts and return memory start */ - - restore_flags(flags); + spin_unlock_irq(&mca_lock); for (i = 0; i < MCA_STANDARD_RESOURCES; i++) request_resource(&ioport_resource, mca_standard_resources + i); @@ -514,8 +522,7 @@ unsigned char mca_read_pos(int slot, int reg) if(slot < 0 || slot >= MCA_NUMADAPTERS || mca_info == NULL) return 0; if(reg < 0 || reg >= 8) return 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&mca_lock, flags); /* Make sure motherboard setup is off */ @@ -566,7 +573,7 @@ unsigned char mca_read_pos(int slot, int reg) mca_info->slot[slot].pos[reg] = byte; - restore_flags(flags); + spin_unlock_irqrestore(&mca_lock, flags); return byte; } /* mca_read_pos() */ @@ -610,8 +617,7 @@ void mca_write_pos(int slot, int reg, unsigned char byte) if(mca_info == NULL) return; - save_flags(flags); - cli(); + spin_lock_irqsave(&mca_lock, flags); /* Make sure motherboard setup is off */ @@ -623,7 +629,7 @@ void mca_write_pos(int slot, int reg, unsigned char byte) outb_p(byte, MCA_POS_REG(reg)); outb_p(0, MCA_ADAPTER_SETUP_REG); - restore_flags(flags); + spin_unlock_irqrestore(&mca_lock, flags); /* Update the global register list, while we have the byte */ diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c index c778b49b4257..1ce749174636 100644 --- a/arch/i386/kernel/mtrr.c +++ b/arch/i386/kernel/mtrr.c @@ -381,7 +381,7 @@ static int arr3_protected; static void set_mtrr_prepare_save (struct set_mtrr_context *ctxt) { /* Disable interrupts locally */ - __save_flags (ctxt->flags); __cli (); + local_save_flags (ctxt->flags); local_irq_disable (); if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) return; @@ -428,7 +428,7 @@ static void set_mtrr_cache_disable (struct set_mtrr_context *ctxt) static void set_mtrr_done (struct set_mtrr_context *ctxt) { if ( mtrr_if != MTRR_IF_INTEL && mtrr_if != MTRR_IF_CYRIX_ARR ) { - __restore_flags (ctxt->flags); + local_irq_restore (ctxt->flags); return; } @@ -452,7 +452,7 @@ static void set_mtrr_done (struct set_mtrr_context *ctxt) write_cr4(ctxt->cr4val); /* Re-enable interrupts locally (if enabled previously) */ - __restore_flags (ctxt->flags); + local_irq_restore (ctxt->flags); } /* End Function set_mtrr_done */ /* This function returns the number of variable MTRRs */ @@ -546,7 +546,7 @@ static void cyrix_get_arr (unsigned int reg, unsigned long *base, arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */ /* Save flags and disable interrupts */ - __save_flags (flags); __cli (); + local_save_flags (flags); local_irq_disable (); ccr3 = getCx86 (CX86_CCR3); setCx86 (CX86_CCR3, (ccr3 & 0x0f) | 0x10); /* enable MAPEN */ @@ -557,7 +557,7 @@ static void cyrix_get_arr (unsigned int reg, unsigned long *base, setCx86 (CX86_CCR3, ccr3); /* disable MAPEN */ /* Enable interrupts if it was enabled previously */ - __restore_flags (flags); + local_irq_restore (flags); shift = ((unsigned char *) base)[1] & 0x0f; *base >>= PAGE_SHIFT; diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index a2447287092d..18c2edecde43 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c @@ -78,7 +78,7 @@ int __init check_nmi_watchdog (void) printk(KERN_INFO "testing NMI watchdog ... "); memcpy(tmp, irq_stat, sizeof(tmp)); - sti(); + local_irq_enable(); mdelay((10*1000)/nmi_hz); // wait 10 ticks for (cpu = 0; cpu < NR_CPUS; cpu++) { diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 57bc712dbc66..1a7a569827d6 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -89,11 +89,11 @@ void enable_hlt(void) void default_idle(void) { if (current_cpu_data.hlt_works_ok && !hlt_counter) { - __cli(); + local_irq_disable(); if (!need_resched()) safe_halt(); else - __sti(); + local_irq_enable(); } } @@ -106,7 +106,7 @@ static void poll_idle (void) { int oldval; - __sti(); + local_irq_enable(); /* * Deal with another CPU just having chosen a thread to @@ -290,7 +290,7 @@ void machine_real_restart(unsigned char *code, int length) { unsigned long flags; - cli(); + local_irq_disable(); /* Write zero to CMOS register number 0x0f, which the BIOS POST routine will recognize as telling it to do a proper reboot. (Well diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c index 2098fcf2679a..d762d602a0b1 100644 --- a/arch/i386/kernel/smp.c +++ b/arch/i386/kernel/smp.c @@ -161,8 +161,8 @@ static inline void send_IPI_mask_bitmask(int mask, int vector) unsigned long cfg; unsigned long flags; - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); /* @@ -186,7 +186,7 @@ static inline void send_IPI_mask_bitmask(int mask, int vector) */ apic_write_around(APIC_ICR, cfg); - __restore_flags(flags); + local_irq_restore(flags); } static inline void send_IPI_mask_sequence(int mask, int vector) @@ -200,8 +200,8 @@ static inline void send_IPI_mask_sequence(int mask, int vector) * should be modified to do 1 message per cluster ID - mbligh */ - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); for (query_cpu = 0; query_cpu < NR_CPUS; ++query_cpu) { query_mask = 1 << query_cpu; @@ -229,7 +229,7 @@ static inline void send_IPI_mask_sequence(int mask, int vector) apic_write_around(APIC_ICR, cfg); } } - __restore_flags(flags); + local_irq_restore(flags); } static inline void send_IPI_mask(int mask, int vector) @@ -387,7 +387,7 @@ asmlinkage void smp_invalidate_interrupt (void) clear_bit(cpu, &flush_cpumask); out: - put_cpu(); + put_cpu_no_resched(); } static void flush_tlb_others (unsigned long cpumask, struct mm_struct *mm, @@ -603,7 +603,7 @@ static void stop_this_cpu (void * dummy) * Remove this CPU: */ clear_bit(smp_processor_id(), &cpu_online_map); - __cli(); + local_irq_disable(); disable_local_APIC(); if (cpu_data[smp_processor_id()].hlt_works_ok) for(;;) __asm__("hlt"); @@ -618,9 +618,9 @@ void smp_send_stop(void) { smp_call_function(stop_this_cpu, NULL, 1, 0); - __cli(); + local_irq_disable(); disable_local_APIC(); - __sti(); + local_irq_enable(); } /* diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c index d77a1fb38d0f..cdd964721ab4 100644 --- a/arch/i386/kernel/smpboot.c +++ b/arch/i386/kernel/smpboot.c @@ -453,7 +453,7 @@ void __init smp_callin(void) clear_local_APIC(); setup_local_APIC(); - __sti(); + local_irq_enable(); #ifdef CONFIG_MTRR /* @@ -1060,7 +1060,6 @@ void __init smp_boot_cpus(void) boot_cpu_logical_apicid = logical_smp_processor_id(); map_cpu_to_boot_apicid(0, boot_cpu_apicid); - global_irq_holder = NO_PROC_ID; current_thread_info()->cpu = 0; smp_tune_scheduling(); diff --git a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c index 195a2b943908..7c60b661f713 100644 --- a/arch/i386/kernel/vm86.c +++ b/arch/i386/kernel/vm86.c @@ -571,6 +571,8 @@ static struct vm86_irqs { struct task_struct *tsk; int sig; } vm86_irqs[16]; + +static spinlock_t irqbits_lock = SPIN_LOCK_UNLOCKED; static int irqbits; #define ALLOWED_SIGS ( 1 /* 0 = don't send a signal */ \ @@ -580,9 +582,8 @@ static int irqbits; static void irq_handler(int intno, void *dev_id, struct pt_regs * regs) { int irq_bit; unsigned long flags; - - save_flags(flags); - cli(); + + spin_lock_irqsave(&irqbits_lock, flags); irq_bit = 1 << intno; if ((irqbits & irq_bit) || ! vm86_irqs[intno].tsk) goto out; @@ -591,14 +592,19 @@ static void irq_handler(int intno, void *dev_id, struct pt_regs * regs) { send_sig(vm86_irqs[intno].sig, vm86_irqs[intno].tsk, 1); /* else user will poll for IRQs */ out: - restore_flags(flags); + spin_unlock_irqrestore(&irqbits_lock, flags); } static inline void free_vm86_irq(int irqnumber) { + unsigned long flags; + free_irq(irqnumber,0); vm86_irqs[irqnumber].tsk = 0; + + spin_lock_irqsave(&irqbits_lock, flags); irqbits &= ~(1 << irqnumber); + spin_unlock_irqrestore(&irqbits_lock, flags); } static inline int task_valid(struct task_struct *tsk) @@ -635,11 +641,10 @@ static inline int get_and_reset_irq(int irqnumber) if ( (irqnumber<3) || (irqnumber>15) ) return 0; if (vm86_irqs[irqnumber].tsk != current) return 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&irqbits_lock, flags); bit = irqbits & (1 << irqnumber); irqbits &= ~bit; - restore_flags(flags); + spin_unlock_irqrestore(&irqbits_lock, flags); return bit; } diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index 474009886b35..8c4328690ebe 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -107,27 +107,25 @@ extern spinlock_t timerlist_lock; */ void bust_spinlocks(int yes) { + int loglevel_save = console_loglevel; + spin_lock_init(&timerlist_lock); if (yes) { oops_in_progress = 1; -#ifdef CONFIG_SMP - global_irq_lock = 0; /* Many serial drivers do __global_cli() */ -#endif - } else { - int loglevel_save = console_loglevel; + return; + } #ifdef CONFIG_VT - unblank_screen(); + unblank_screen(); #endif - oops_in_progress = 0; - /* - * OK, the message is on the console. Now we call printk() - * without oops_in_progress set so that printk will give klogd - * a poke. Hold onto your hats... - */ - console_loglevel = 15; /* NMI oopser may have shut the console up */ - printk(" "); - console_loglevel = loglevel_save; - } + oops_in_progress = 0; + /* + * OK, the message is on the console. Now we call printk() + * without oops_in_progress set so that printk will give klogd + * a poke. Hold onto your hats... + */ + console_loglevel = 15; /* NMI oopser may have shut the console up */ + printk(" "); + console_loglevel = loglevel_save; } asmlinkage void do_invalid_op(struct pt_regs *, unsigned long); diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c index 3b809127667e..9f7b7dc037b0 100644 --- a/arch/i386/mm/ioremap.c +++ b/arch/i386/mm/ioremap.c @@ -215,7 +215,7 @@ void iounmap(void *addr) struct vm_struct *p; if (addr <= high_memory) return; - p = remove_kernel_area(PAGE_MASK & (unsigned long) addr); + p = remove_kernel_area((void *) (PAGE_MASK & (unsigned long) addr)); if (!p) { printk("__iounmap: bad address %p\n", addr); return; diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c index aff679e20aaa..ea4f3c51f377 100644 --- a/arch/i386/pci/direct.c +++ b/arch/i386/pci/direct.c @@ -306,7 +306,7 @@ static struct pci_ops * __devinit pci_check_direct(void) unsigned int tmp; unsigned long flags; - __save_flags(flags); __cli(); + local_save_flags(flags); local_irq_disable(); /* * Check if configuration type 1 works. @@ -318,7 +318,7 @@ static struct pci_ops * __devinit pci_check_direct(void) if (inl (0xCF8) == 0x80000000 && pci_sanity_check(&pci_direct_conf1)) { outl (tmp, 0xCF8); - __restore_flags(flags); + local_irq_restore(flags); printk(KERN_INFO "PCI: Using configuration type 1\n"); if (!request_region(0xCF8, 8, "PCI conf1")) return NULL; @@ -336,7 +336,7 @@ static struct pci_ops * __devinit pci_check_direct(void) outb (0x00, 0xCFA); if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00 && pci_sanity_check(&pci_direct_conf2)) { - __restore_flags(flags); + local_irq_restore(flags); printk(KERN_INFO "PCI: Using configuration type 2\n"); if (!request_region(0xCF8, 4, "PCI conf2")) return NULL; @@ -344,7 +344,7 @@ static struct pci_ops * __devinit pci_check_direct(void) } } - __restore_flags(flags); + local_irq_restore(flags); return NULL; } diff --git a/arch/i386/pci/pcbios.c b/arch/i386/pci/pcbios.c index 8d3b0cb57ccb..ccf3c2b090da 100644 --- a/arch/i386/pci/pcbios.c +++ b/arch/i386/pci/pcbios.c @@ -82,7 +82,7 @@ static unsigned long bios32_service(unsigned long service) unsigned long entry; /* %edx */ unsigned long flags; - __save_flags(flags); __cli(); + local_save_flags(flags); local_irq_disable(); __asm__("lcall *(%%edi); cld" : "=a" (return_code), "=b" (address), @@ -91,7 +91,7 @@ static unsigned long bios32_service(unsigned long service) : "0" (service), "1" (0), "D" (&bios32_indirect)); - __restore_flags(flags); + local_irq_restore(flags); switch (return_code) { case 0: @@ -122,7 +122,7 @@ static int __devinit check_pcibios(void) if ((pcibios_entry = bios32_service(PCI_SERVICE))) { pci_indirect.address = pcibios_entry + PAGE_OFFSET; - __save_flags(flags); __cli(); + local_save_flags(flags); local_irq_disable(); __asm__( "lcall *(%%edi); cld\n\t" "jc 1f\n\t" @@ -135,7 +135,7 @@ static int __devinit check_pcibios(void) : "1" (PCIBIOS_PCI_BIOS_PRESENT), "D" (&pci_indirect) : "memory"); - __restore_flags(flags); + local_irq_restore(flags); status = (eax >> 8) & 0xff; hw_mech = eax & 0xff; diff --git a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c index e387c19daefe..e44fa800457b 100644 --- a/arch/ia64/hp/sim/simscsi.c +++ b/arch/ia64/hp/sim/simscsi.c @@ -144,7 +144,7 @@ simscsi_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) } int -simscsi_biosparam (Disk *disk, kdev_t n, int ip[]) +simscsi_biosparam (Disk *disk, struct block_device *n, int ip[]) { int size = disk->capacity; diff --git a/arch/ia64/hp/sim/simscsi.h b/arch/ia64/hp/sim/simscsi.h index 41045408a5da..42e584563ab3 100644 --- a/arch/ia64/hp/sim/simscsi.h +++ b/arch/ia64/hp/sim/simscsi.h @@ -17,7 +17,7 @@ extern const char *simscsi_info (struct Scsi_Host *); extern int simscsi_queuecommand (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); extern int simscsi_abort (Scsi_Cmnd *); extern int simscsi_reset (Scsi_Cmnd *, unsigned int); -extern int simscsi_biosparam (Disk *, kdev_t, int[]); +extern int simscsi_biosparam (Disk *, struct block_device *, int[]); #define SIMSCSI { \ detect: simscsi_detect, \ diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index f4a8b88f45c3..5772707363b2 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -284,7 +284,7 @@ static void show(char * str) # define SYNC_OTHER_CORES(x) udelay(x+1) #else /* - * We have to allow irqs to arrive between __sti and __cli + * We have to allow irqs to arrive between local_irq_enable and local_irq_disable */ # ifdef CONFIG_IA64 # define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop 0") @@ -317,9 +317,9 @@ static inline void wait_on_irq(void) show("wait_on_irq"); count = ~0; } - __sti(); + local_irq_enable(); SYNC_OTHER_CORES(smp_processor_id()); - __cli(); + local_irq_disable(); if (irqs_running()) continue; if (global_irq_lock) @@ -394,16 +394,16 @@ void __global_cli(void) unsigned int flags; #ifdef CONFIG_IA64 - __save_flags(flags); + local_save_flags(flags); if (flags & IA64_PSR_I) { - __cli(); + local_irq_disable(); if (!really_local_irq_count()) get_irqlock(); } #else - __save_flags(flags); + local_save_flags(flags); if (flags & (1 << EFLAGS_IF_SHIFT)) { - __cli(); + local_irq_disable(); if (!really_local_irq_count()) get_irqlock(); } @@ -414,7 +414,7 @@ void __global_sti(void) { if (!really_local_irq_count()) release_irqlock(smp_processor_id()); - __sti(); + local_irq_enable(); } /* @@ -431,7 +431,7 @@ unsigned long __global_save_flags(void) unsigned long flags; int cpu = smp_processor_id(); - __save_flags(flags); + local_save_flags(flags); #ifdef CONFIG_IA64 local_enabled = (flags & IA64_PSR_I) != 0; #else @@ -460,10 +460,10 @@ void __global_restore_flags(unsigned long flags) __global_sti(); break; case 2: - __cli(); + local_irq_disable(); break; case 3: - __sti(); + local_irq_enable(); break; default: printk("global_restore_flags: %08lx (%08lx)\n", @@ -489,7 +489,7 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * status = 1; /* Force the "do bottom halves" bit */ if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); do { status |= action->flags; @@ -498,7 +498,7 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); local_irq_exit(irq); diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c index ee5cd1d25e67..5dd0a97cd4ac 100644 --- a/arch/ia64/kernel/smp.c +++ b/arch/ia64/kernel/smp.c @@ -91,7 +91,7 @@ stop_this_cpu (void) */ clear_bit(smp_processor_id(), &cpu_online_map); max_xtp(); - __cli(); + local_irq_disable(); cpu_halt(); } diff --git a/arch/ia64/sn/kernel/llsc4.c b/arch/ia64/sn/kernel/llsc4.c index 534e72a9502e..b8d6113f7785 100644 --- a/arch/ia64/sn/kernel/llsc4.c +++ b/arch/ia64/sn/kernel/llsc4.c @@ -1025,7 +1025,7 @@ int_test() { if (mycpu == NR_CPUS-1) { printk("\nTight loop of cpu %d sending ints to cpu 0 (every 100 us)\n", mycpu); udelay(IS_RUNNING_ON_SIMULATOR ? 1000 : 1000000); - __cli(); + local_irq_disable(); while (1) { smp_send_reschedule(0); udelay(100); diff --git a/arch/ia64/sn/kernel/sv.c b/arch/ia64/sn/kernel/sv.c index 2f9e86568267..39ad4cfa0e0c 100644 --- a/arch/ia64/sn/kernel/sv.c +++ b/arch/ia64/sn/kernel/sv.c @@ -183,7 +183,7 @@ signed long sv_wait(sv_t *sv, int sv_wait_flags, unsigned long timeout) #ifdef SV_DEBUG_INTERRUPT_STATE { unsigned long flags; - __save_flags(flags); + local_save_flags(flags); if(sv->sv_flags & SV_INTS) { if(SV_TEST_INTERRUPTS_ENABLED(flags)) { @@ -279,7 +279,7 @@ void sv_signal(sv_t *sv) #ifdef SV_DEBUG_INTERRUPT_STATE if(sv->sv_flags & SV_INTS) { unsigned long flags; - __save_flags(flags); + local_save_flags(flags); if(SV_TEST_INTERRUPTS_ENABLED(flags)) printk(KERN_ERR "sv_signal: SV_INTS and " "interrupts enabled! (flags: 0x%lx)\n", flags); @@ -296,7 +296,7 @@ void sv_broadcast(sv_t *sv) #ifdef SV_DEBUG_INTERRUPT_STATE if(sv->sv_flags & SV_INTS) { unsigned long flags; - __save_flags(flags); + local_save_flags(flags); if(SV_TEST_INTERRUPTS_ENABLED(flags)) printk(KERN_ERR "sv_broadcast: SV_INTS and " "interrupts enabled! (flags: 0x%lx)\n", flags); @@ -475,7 +475,7 @@ static int interrupt_test_worker(void *unused) printk("ITW: thread %d started.\n", id); while(1) { - __save_flags(flags2); + local_save_flags(flags2); if(jiffies % 3) { printk("ITW %2d %5d: irqsaving (%lx)\n", id, it, flags2); spin_lock_irqsave(&int_test_spin, flags); @@ -484,11 +484,11 @@ static int interrupt_test_worker(void *unused) spin_lock_irq(&int_test_spin); } - __save_flags(flags2); + local_save_flags(flags2); printk("ITW %2d %5d: locked, sv_waiting (%lx).\n", id, it, flags2); sv_wait(&int_test_sv, 0, 0); - __save_flags(flags2); + local_save_flags(flags2); printk("ITW %2d %5d: wait finished (%lx), pausing\n", id, it, flags2); set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(jiffies & 0xf); diff --git a/arch/m68k/bvme6000/config.c b/arch/m68k/bvme6000/config.c index 2a15d06f27f7..a5f5f76ba75d 100644 --- a/arch/m68k/bvme6000/config.c +++ b/arch/m68k/bvme6000/config.c @@ -49,7 +49,6 @@ extern int bvme6000_kbdrate (struct kbd_repeat *); extern unsigned long bvme6000_gettimeoffset (void); extern int bvme6000_hwclk (int, struct rtc_time *); extern int bvme6000_set_clock_mmss (unsigned long); -extern void bvme6000_check_partition (struct gendisk *hd, unsigned int dev); extern void bvme6000_mksound( unsigned int count, unsigned int ticks ); extern void bvme6000_reset (void); extern void bvme6000_waitbut(void); diff --git a/arch/m68k/mvme147/config.c b/arch/m68k/mvme147/config.c index 211c1e2a00ea..7e5c1cdd5c1b 100644 --- a/arch/m68k/mvme147/config.c +++ b/arch/m68k/mvme147/config.c @@ -48,7 +48,6 @@ extern int mvme147_kbdrate (struct kbd_repeat *); extern unsigned long mvme147_gettimeoffset (void); extern int mvme147_hwclk (int, struct rtc_time *); extern int mvme147_set_clock_mmss (unsigned long); -extern void mvme147_check_partition (struct gendisk *hd, unsigned int dev); extern void mvme147_reset (void); extern void mvme147_waitbut(void); diff --git a/arch/m68k/mvme16x/config.c b/arch/m68k/mvme16x/config.c index 528c24a5d474..97f22c630bd4 100644 --- a/arch/m68k/mvme16x/config.c +++ b/arch/m68k/mvme16x/config.c @@ -52,7 +52,6 @@ extern int mvme16x_kbdrate (struct kbd_repeat *); extern unsigned long mvme16x_gettimeoffset (void); extern int mvme16x_hwclk (int, struct rtc_time *); extern int mvme16x_set_clock_mmss (unsigned long); -extern void mvme16x_check_partition (struct gendisk *hd, unsigned int dev); extern void mvme16x_mksound( unsigned int count, unsigned int ticks ); extern void mvme16x_reset (void); extern void mvme16x_waitbut(void); diff --git a/arch/mips/baget/irq.c b/arch/mips/baget/irq.c index d346ec8714ef..551985d5a9c2 100644 --- a/arch/mips/baget/irq.c +++ b/arch/mips/baget/irq.c @@ -186,7 +186,7 @@ static void do_IRQ(int irq, struct pt_regs * regs) action = *(irq + irq_action); if (action) { if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); action = *(irq + irq_action); do_random = 0; do { @@ -196,7 +196,7 @@ static void do_IRQ(int irq, struct pt_regs * regs) } while (action); if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); } else { printk("do_IRQ: Unregistered IRQ (0x%X) occurred\n", irq); } diff --git a/arch/mips/dec/irq.c b/arch/mips/dec/irq.c index d460583f3cc4..d34890f29dde 100644 --- a/arch/mips/dec/irq.c +++ b/arch/mips/dec/irq.c @@ -136,7 +136,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs) action = *(irq + irq_action); if (action) { if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); action = *(irq + irq_action); do_random = 0; do { @@ -146,7 +146,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs) } while (action); if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); unmask_irq(irq); } irq_exit(cpu, irq); diff --git a/arch/mips/gt64120/momenco_ocelot/irq.c b/arch/mips/gt64120/momenco_ocelot/irq.c index e28be4037bad..81216fcba79d 100644 --- a/arch/mips/gt64120/momenco_ocelot/irq.c +++ b/arch/mips/gt64120/momenco_ocelot/irq.c @@ -147,7 +147,7 @@ void __init init_IRQ(void) * int-handler is not on bootstrap */ clear_cp0_status(ST0_IM | ST0_BEV); - __cli(); + local_irq_disable(); /* Sets the first-level interrupt dispatcher. */ set_except_vector(0, ocelot_handle_int); diff --git a/arch/mips/ite-boards/generic/irq.c b/arch/mips/ite-boards/generic/irq.c index 53585e39f793..88003824768a 100644 --- a/arch/mips/ite-boards/generic/irq.c +++ b/arch/mips/ite-boards/generic/irq.c @@ -271,12 +271,12 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs) //mask_irq(1<<irq); //printk("action->handler %x\n", action->handler); disable_it8172_irq(irq); - //if (!(action->flags & SA_INTERRUPT)) __sti(); /* reenable ints */ + //if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); /* reenable ints */ do { action->handler(irq, action->dev_id, regs); action = action->next; } while ( action ); - //__cli(); /* disable ints */ + //local_irq_disable(); /* disable ints */ if (irq_desc[irq].handler) { } diff --git a/arch/mips/ite-boards/generic/time.c b/arch/mips/ite-boards/generic/time.c index fc294490b2aa..600b4cef1afa 100644 --- a/arch/mips/ite-boards/generic/time.c +++ b/arch/mips/ite-boards/generic/time.c @@ -168,7 +168,7 @@ static unsigned long __init cal_r4koff(void) unsigned long count; unsigned int flags; - __save_and_cli(flags); + local_irq_save(flags); /* Start counter exactly on falling edge of update flag */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); @@ -184,7 +184,7 @@ static unsigned long __init cal_r4koff(void) count = read_32bit_cp0_register(CP0_COUNT); /* restore interrupts */ - __restore_flags(flags); + local_irq_restore(flags); return (count / HZ); } diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index 77e00450a800..baa7000d9baf 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -114,7 +114,7 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * status = 1; /* Force the "do bottom halves" bit */ if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); do { status |= action->flags; @@ -123,7 +123,7 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); irq_exit(cpu, irq); diff --git a/arch/mips/kernel/old-irq.c b/arch/mips/kernel/old-irq.c index 50f0807a77e1..664be080f40e 100644 --- a/arch/mips/kernel/old-irq.c +++ b/arch/mips/kernel/old-irq.c @@ -183,7 +183,7 @@ asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs) goto out; if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); action = *(irq + irq_action); do_random = 0; do { @@ -193,7 +193,7 @@ asmlinkage void i8259_do_irq(int irq, struct pt_regs *regs) } while (action); if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); unmask_irq (irq); out: @@ -219,7 +219,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) action = *(irq + irq_action); if (action) { if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); action = *(irq + irq_action); do_random = 0; do { @@ -229,7 +229,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) } while (action); if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); } irq_exit(cpu, irq); diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index 7f9f3aacf42d..511ef439f4d2 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -174,10 +174,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) case FPC_EIR: { /* implementation / version register */ unsigned int flags; - __save_flags(flags); + local_save_flags(flags); enable_cp1(); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); - __restore_flags(flags); + local_irq_restore(flags); break; } default: diff --git a/arch/mips/kernel/smp.c b/arch/mips/kernel/smp.c index 96276f71ebb2..45bff0a5ae82 100644 --- a/arch/mips/kernel/smp.c +++ b/arch/mips/kernel/smp.c @@ -281,9 +281,9 @@ static inline void wait_on_irq(int cpu) printk("Count spun out. Huh?\n"); count = ~0; } - __sti(); + local_irq_enable(); SYNC_OTHER_CORES(cpu); - __cli(); + local_irq_disable(); if (irqs_running()) continue; if (spin_is_locked(&global_irq_lock)) @@ -335,10 +335,10 @@ void __global_cli(void) { unsigned int flags; - __save_flags(flags); + local_save_flags(flags); if (flags & ST0_IE) { int cpu = smp_processor_id(); - __cli(); + local_irq_disable(); if (!local_irq_count(cpu)) get_irqlock(cpu); } @@ -350,7 +350,7 @@ void __global_sti(void) if (!local_irq_count(cpu)) release_irqlock(cpu); - __sti(); + local_irq_enable(); } /* @@ -367,7 +367,7 @@ unsigned long __global_save_flags(void) unsigned long flags; int cpu = smp_processor_id(); - __save_flags(flags); + local_save_flags(flags); local_enabled = (flags & ST0_IE); /* default to local */ retval = 2 + local_enabled; @@ -393,10 +393,10 @@ void __global_restore_flags(unsigned long flags) __global_sti(); break; case 2: - __cli(); + local_irq_disable(); break; case 3: - __sti(); + local_irq_enable(); break; default: printk("global_restore_flags: %08lx\n", flags); diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 27d5bd45de6c..0b7073335b42 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -102,7 +102,7 @@ dump_tlb_addr(unsigned long addr) unsigned int flags, oldpid; int index; - __save_and_cli(flags); + local_irq_save(flags); oldpid = get_entryhi() & 0xff; BARRIER; set_entryhi((addr & PAGE_MASK) | oldpid); @@ -111,7 +111,7 @@ dump_tlb_addr(unsigned long addr) BARRIER; index = get_index(); set_entryhi(oldpid); - __restore_flags(flags); + local_irq_restore(flags); if (index < 0) { printk("No entry for address 0x%08lx in TLB\n", addr); diff --git a/arch/mips/lib/r3k_dump_tlb.c b/arch/mips/lib/r3k_dump_tlb.c index f6b6720011bf..d9cda02a1aab 100644 --- a/arch/mips/lib/r3k_dump_tlb.c +++ b/arch/mips/lib/r3k_dump_tlb.c @@ -83,13 +83,13 @@ dump_tlb_addr(unsigned long addr) unsigned int flags, oldpid; int index; - __save_and_cli(flags); + local_irq_save(flags); oldpid = get_entryhi() & 0xff; set_entryhi((addr & PAGE_MASK) | oldpid); tlb_probe(); index = get_index(); set_entryhi(oldpid); - __restore_flags(flags); + local_irq_restore(flags); if (index < 0) { printk("No entry for address 0x%08lx in TLB\n", addr); diff --git a/arch/mips/mips-boards/generic/time.c b/arch/mips/mips-boards/generic/time.c index 49c63c2bdf18..5e4658bc5d47 100644 --- a/arch/mips/mips-boards/generic/time.c +++ b/arch/mips/mips-boards/generic/time.c @@ -189,7 +189,7 @@ static unsigned long __init cal_r4koff(void) unsigned long count; unsigned int flags; - __save_and_cli(flags); + local_irq_save(flags); /* Start counter exactly on falling edge of update flag */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); @@ -205,7 +205,7 @@ static unsigned long __init cal_r4koff(void) count = read_32bit_cp0_register(CP0_COUNT); /* restore interrupts */ - __restore_flags(flags); + local_irq_restore(flags); return (count / HZ); } diff --git a/arch/mips/mm/mips32.c b/arch/mips/mm/mips32.c index ba4e5dc12dd8..611061e48623 100644 --- a/arch/mips/mm/mips32.c +++ b/arch/mips/mm/mips32.c @@ -161,18 +161,18 @@ static inline void mips32_flush_cache_all_sc(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache(); blast_icache(); blast_scache(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void mips32_flush_cache_all_pc(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache(); blast_icache(); - __restore_flags(flags); + local_irq_restore(flags); } static void @@ -198,7 +198,7 @@ mips32_flush_cache_range_sc(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -208,7 +208,7 @@ mips32_flush_cache_range_sc(struct vm_area_struct *vma, blast_scache_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -225,9 +225,9 @@ static void mips32_flush_cache_range_pc(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - __save_and_cli(flags); + local_irq_save(flags); blast_dcache(); blast_icache(); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -279,7 +279,7 @@ static void mips32_flush_cache_page_sc(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -309,7 +309,7 @@ static void mips32_flush_cache_page_sc(struct vm_area_struct *vma, } else blast_scache_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void mips32_flush_cache_page_pc(struct vm_area_struct *vma, @@ -331,7 +331,7 @@ static void mips32_flush_cache_page_pc(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -360,7 +360,7 @@ static void mips32_flush_cache_page_pc(struct vm_area_struct *vma, blast_dcache_page_indexed(page); } out: - __restore_flags(flags); + local_irq_restore(flags); } /* If the addresses passed to these routines are valid, they are @@ -420,7 +420,7 @@ mips32_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) if (size >= dcache_size) { flush_cache_all(); } else { - __save_and_cli(flags); + local_irq_save(flags); a = addr & ~(dc_lsize - 1); end = (addr + size) & ~(dc_lsize - 1); while (1) { @@ -428,7 +428,7 @@ mips32_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) if (a == end) break; a += dc_lsize; } - __restore_flags(flags); + local_irq_restore(flags); } bc_wback_inv(addr, size); } @@ -461,7 +461,7 @@ mips32_dma_cache_inv_pc(unsigned long addr, unsigned long size) if (size >= dcache_size) { flush_cache_all(); } else { - __save_and_cli(flags); + local_irq_save(flags); a = addr & ~(dc_lsize - 1); end = (addr + size) & ~(dc_lsize - 1); while (1) { @@ -469,7 +469,7 @@ mips32_dma_cache_inv_pc(unsigned long addr, unsigned long size) if (a == end) break; a += dc_lsize; } - __restore_flags(flags); + local_irq_restore(flags); } bc_inv(addr, size); @@ -524,7 +524,7 @@ void flush_tlb_all(void) printk("[tlball]"); #endif - __save_and_cli(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = (get_entryhi() & 0xff); set_entryhi(KSEG0); @@ -546,7 +546,7 @@ void flush_tlb_all(void) } BARRIER; set_entryhi(old_ctx); - __restore_flags(flags); + local_irq_restore(flags); } void flush_tlb_mm(struct mm_struct *mm) @@ -557,11 +557,11 @@ void flush_tlb_mm(struct mm_struct *mm) #ifdef DEBUG_TLB printk("[tlbmm<%d>]", mm->context); #endif - __save_and_cli(flags); + local_irq_save(flags); get_new_mmu_context(mm, asid_cache); if (mm == current->active_mm) set_entryhi(mm->context & 0xff); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -576,7 +576,7 @@ void flush_tlb_range(struct mm_struct *mm, unsigned long start, printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff), start, end); #endif - __save_and_cli(flags); + local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; size = (size + 1) >> 1; if(size <= mips_cpu.tlbsize/2) { @@ -611,7 +611,7 @@ void flush_tlb_range(struct mm_struct *mm, unsigned long start, if (mm == current->active_mm) set_entryhi(mm->context & 0xff); } - __restore_flags(flags); + local_irq_restore(flags); } } @@ -626,7 +626,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) #endif newpid = (vma->vm_mm->context & 0xff); page &= (PAGE_MASK << 1); - __save_and_cli(flags); + local_irq_save(flags); oldpid = (get_entryhi() & 0xff); set_entryhi(page | newpid); BARRIER; @@ -645,7 +645,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) finish: BARRIER; set_entryhi(oldpid); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -693,7 +693,7 @@ void update_mmu_cache(struct vm_area_struct * vma, } #endif - __save_and_cli(flags); + local_irq_save(flags); address &= (PAGE_MASK << 1); set_entryhi(address | (pid)); pgdp = pgd_offset(vma->vm_mm, address); @@ -716,7 +716,7 @@ void update_mmu_cache(struct vm_area_struct * vma, BARRIER; set_entryhi(pid); BARRIER; - __restore_flags(flags); + local_irq_restore(flags); } void show_regs(struct pt_regs * regs) @@ -752,7 +752,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long old_pagemask; unsigned long old_ctx; - __save_and_cli(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = (get_entryhi() & 0xff); old_pagemask = get_pagemask(); @@ -772,7 +772,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, BARRIER; set_pagemask (old_pagemask); flush_tlb_all(); - __restore_flags(flags); + local_irq_restore(flags); } /* Detect and size the various caches. */ @@ -895,7 +895,7 @@ static int __init probe_scache(unsigned long config) /* This is such a bitch, you'd think they would make it * easy to do this. Away you daemons of stupidity! */ - __save_and_cli(flags); + local_irq_save(flags); /* Fill each size-multiple cache line with a valid tag. */ pow2 = (64 * 1024); @@ -939,7 +939,7 @@ static int __init probe_scache(unsigned long config) break; pow2 <<= 1; } - __restore_flags(flags); + local_irq_restore(flags); addr -= begin; printk("Secondary cache sized at %dK linesize %d bytes.\n", (int) (addr >> 10), sc_lsize); diff --git a/arch/mips/mm/r4xx0.c b/arch/mips/mm/r4xx0.c index 4976b035133e..95e8c09b43cc 100644 --- a/arch/mips/mm/r4xx0.c +++ b/arch/mips/mm/r4xx0.c @@ -209,7 +209,7 @@ static void r4k_clear_page_r4600_v2(void * page) { unsigned int flags; - __save_and_cli(flags); + local_irq_save(flags); *(volatile unsigned int *)KSEG1; __asm__ __volatile__( ".set\tnoreorder\n\t" @@ -236,7 +236,7 @@ static void r4k_clear_page_r4600_v2(void * page) "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D) :"$1","memory"); - __restore_flags(flags); + local_irq_restore(flags); } /* @@ -568,7 +568,7 @@ static void r4k_copy_page_r4600_v2(void * to, void * from) unsigned long reg1, reg2, reg3, reg4; unsigned int flags; - __save_and_cli(flags); + local_irq_save(flags); __asm__ __volatile__( ".set\tnoreorder\n\t" ".set\tnoat\n\t" @@ -627,7 +627,7 @@ static void r4k_copy_page_r4600_v2(void * to, void * from) :"0" (to), "1" (from), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D)); - __restore_flags(flags); + local_irq_restore(flags); } /* @@ -911,81 +911,81 @@ static inline void r4k_flush_cache_all_s16d16i16(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache16(); blast_icache16(); blast_scache16(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_s32d16i16(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache16(); blast_icache16(); blast_scache32(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_s64d16i16(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache16(); blast_icache16(); blast_scache64(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_s128d16i16(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache16(); blast_icache16(); blast_scache128(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_s32d32i32(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache32(); blast_icache32(); blast_scache32(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_s64d32i32(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache32(); blast_icache32(); blast_scache64(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_s128d32i32(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache32(); blast_icache32(); blast_scache128(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_d16i16(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache16(); blast_icache16(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_d32i32(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache32(); blast_icache32(); - __restore_flags(flags); + local_irq_restore(flags); } static void @@ -1011,7 +1011,7 @@ r4k_flush_cache_range_s16d16i16(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1021,7 +1021,7 @@ r4k_flush_cache_range_s16d16i16(struct vm_area_struct *vma, blast_scache16_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -1049,7 +1049,7 @@ r4k_flush_cache_range_s32d16i16(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1059,7 +1059,7 @@ r4k_flush_cache_range_s32d16i16(struct vm_area_struct *vma, blast_scache32_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -1086,7 +1086,7 @@ static void r4k_flush_cache_range_s64d16i16(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1096,7 +1096,7 @@ static void r4k_flush_cache_range_s64d16i16(struct vm_area_struct *vma, blast_scache64_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -1123,7 +1123,7 @@ static void r4k_flush_cache_range_s128d16i16(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1133,7 +1133,7 @@ static void r4k_flush_cache_range_s128d16i16(struct vm_area_struct *vma, blast_scache128_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -1160,7 +1160,7 @@ static void r4k_flush_cache_range_s32d32i32(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1170,7 +1170,7 @@ static void r4k_flush_cache_range_s32d32i32(struct vm_area_struct *vma, blast_scache32_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -1197,7 +1197,7 @@ static void r4k_flush_cache_range_s64d32i32(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1207,7 +1207,7 @@ static void r4k_flush_cache_range_s64d32i32(struct vm_area_struct *vma, blast_scache64_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -1234,7 +1234,7 @@ static void r4k_flush_cache_range_s128d32i32(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1244,7 +1244,7 @@ static void r4k_flush_cache_range_s128d32i32(struct vm_area_struct *vma, blast_scache128_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -1261,9 +1261,9 @@ static void r4k_flush_cache_range_d16i16(struct mm_struct *vma, #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - __save_and_cli(flags); + local_irq_save(flags); blast_dcache16(); blast_icache16(); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -1279,9 +1279,9 @@ static void r4k_flush_cache_range_d32i32(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - __save_and_cli(flags); + local_irq_save(flags); blast_dcache32(); blast_icache32(); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -1399,7 +1399,7 @@ static void r4k_flush_cache_page_s16d16i16(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1429,7 +1429,7 @@ static void r4k_flush_cache_page_s16d16i16(struct vm_area_struct *vma, } else blast_scache16_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_s32d16i16(struct vm_area_struct *vma, @@ -1451,7 +1451,7 @@ static void r4k_flush_cache_page_s32d16i16(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1480,7 +1480,7 @@ static void r4k_flush_cache_page_s32d16i16(struct vm_area_struct *vma, } else blast_scache32_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_s64d16i16(struct vm_area_struct *vma, @@ -1502,7 +1502,7 @@ static void r4k_flush_cache_page_s64d16i16(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1531,7 +1531,7 @@ static void r4k_flush_cache_page_s64d16i16(struct vm_area_struct *vma, } else blast_scache64_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_s128d16i16(struct vm_area_struct *vma, @@ -1553,7 +1553,7 @@ static void r4k_flush_cache_page_s128d16i16(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1583,7 +1583,7 @@ static void r4k_flush_cache_page_s128d16i16(struct vm_area_struct *vma, } else blast_scache128_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_s32d32i32(struct vm_area_struct *vma, @@ -1605,7 +1605,7 @@ static void r4k_flush_cache_page_s32d32i32(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1635,7 +1635,7 @@ static void r4k_flush_cache_page_s32d32i32(struct vm_area_struct *vma, } else blast_scache32_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_s64d32i32(struct vm_area_struct *vma, @@ -1657,7 +1657,7 @@ static void r4k_flush_cache_page_s64d32i32(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1687,7 +1687,7 @@ static void r4k_flush_cache_page_s64d32i32(struct vm_area_struct *vma, } else blast_scache64_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_s128d32i32(struct vm_area_struct *vma, @@ -1709,7 +1709,7 @@ static void r4k_flush_cache_page_s128d32i32(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1738,7 +1738,7 @@ static void r4k_flush_cache_page_s128d32i32(struct vm_area_struct *vma, } else blast_scache128_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_d16i16(struct vm_area_struct *vma, @@ -1760,7 +1760,7 @@ static void r4k_flush_cache_page_d16i16(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1789,7 +1789,7 @@ static void r4k_flush_cache_page_d16i16(struct vm_area_struct *vma, blast_dcache16_page_indexed(page); } out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_d32i32(struct vm_area_struct *vma, @@ -1811,7 +1811,7 @@ static void r4k_flush_cache_page_d32i32(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1841,7 +1841,7 @@ static void r4k_flush_cache_page_d32i32(struct vm_area_struct *vma, blast_dcache32_page_indexed(page); } out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_d32i32_r4600(struct vm_area_struct *vma, @@ -1863,7 +1863,7 @@ static void r4k_flush_cache_page_d32i32_r4600(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1893,7 +1893,7 @@ static void r4k_flush_cache_page_d32i32_r4600(struct vm_area_struct *vma, blast_dcache32_page_indexed(page ^ dcache_waybit); } out: - __restore_flags(flags); + local_irq_restore(flags); } /* If the addresses passed to these routines are valid, they are @@ -1939,9 +1939,9 @@ static void r4k_flush_page_to_ram_d32_r4600(struct page *page) { unsigned long flags; - __save_and_cli(flags); /* For R4600 v1.7 bug. */ + local_irq_save(flags); /* For R4600 v1.7 bug. */ blast_dcache32_page((unsigned long)page_address(page)); - __restore_flags(flags); + local_irq_restore(flags); } static void @@ -1993,7 +1993,7 @@ r4k_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) flush_cache_all(); } else { /* Workaround for R4600 bug. See comment above. */ - __save_and_cli(flags); + local_irq_save(flags); *(volatile unsigned long *)KSEG1; a = addr & ~(dc_lsize - 1); @@ -2003,7 +2003,7 @@ r4k_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) if (a == end) break; a += dc_lsize; } - __restore_flags(flags); + local_irq_restore(flags); } bc_wback_inv(addr, size); } @@ -2037,7 +2037,7 @@ r4k_dma_cache_inv_pc(unsigned long addr, unsigned long size) flush_cache_all(); } else { /* Workaround for R4600 bug. See comment above. */ - __save_and_cli(flags); + local_irq_save(flags); *(volatile unsigned long *)KSEG1; a = addr & ~(dc_lsize - 1); @@ -2047,7 +2047,7 @@ r4k_dma_cache_inv_pc(unsigned long addr, unsigned long size) if (a == end) break; a += dc_lsize; } - __restore_flags(flags); + local_irq_restore(flags); } bc_inv(addr, size); @@ -2094,7 +2094,7 @@ static void r4600v20k_flush_cache_sigtramp(unsigned long addr) { unsigned int flags; - __save_and_cli(flags); + local_irq_save(flags); /* Clear internal cache refill buffer */ *(volatile unsigned int *)KSEG1; @@ -2102,7 +2102,7 @@ static void r4600v20k_flush_cache_sigtramp(unsigned long addr) protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); protected_flush_icache_line(addr & ~(ic_lsize - 1)); - __restore_flags(flags); + local_irq_restore(flags); } #undef DEBUG_TLB @@ -2118,7 +2118,7 @@ void flush_tlb_all(void) printk("[tlball]"); #endif - __save_and_cli(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = (get_entryhi() & 0xff); set_entryhi(KSEG0); @@ -2138,7 +2138,7 @@ void flush_tlb_all(void) } BARRIER; set_entryhi(old_ctx); - __restore_flags(flags); + local_irq_restore(flags); } void flush_tlb_mm(struct mm_struct *mm) @@ -2149,11 +2149,11 @@ void flush_tlb_mm(struct mm_struct *mm) #ifdef DEBUG_TLB printk("[tlbmm<%d>]", mm->context); #endif - __save_and_cli(flags); + local_irq_save(flags); get_new_mmu_context(mm, asid_cache); if (mm == current->active_mm) set_entryhi(mm->context & 0xff); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -2170,7 +2170,7 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff), start, end); #endif - __save_and_cli(flags); + local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; size = (size + 1) >> 1; if(size <= mips_cpu.tlbsize/2) { @@ -2204,7 +2204,7 @@ void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, if (mm == current->active_mm) set_entryhi(mm->context & 0xff); } - __restore_flags(flags); + local_irq_restore(flags); } } @@ -2219,7 +2219,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) #endif newpid = (vma->vm_mm->context & 0xff); page &= (PAGE_MASK << 1); - __save_and_cli(flags); + local_irq_save(flags); oldpid = (get_entryhi() & 0xff); set_entryhi(page | newpid); BARRIER; @@ -2237,7 +2237,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) finish: BARRIER; set_entryhi(oldpid); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -2286,7 +2286,7 @@ void update_mmu_cache(struct vm_area_struct * vma, } #endif - __save_and_cli(flags); + local_irq_save(flags); address &= (PAGE_MASK << 1); set_entryhi(address | (pid)); pgdp = pgd_offset(vma->vm_mm, address); @@ -2309,7 +2309,7 @@ void update_mmu_cache(struct vm_area_struct * vma, BARRIER; set_entryhi(pid); BARRIER; - __restore_flags(flags); + local_irq_restore(flags); } #if 0 @@ -2322,7 +2322,7 @@ static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma, pte_t *ptep; int idx; - __save_and_cli(flags); + local_irq_save(flags); address &= (PAGE_MASK << 1); set_entryhi(address | (get_entryhi() & 0xff)); pgdp = pgd_offset(vma->vm_mm, address); @@ -2338,7 +2338,7 @@ static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma, else tlb_write_indexed(); BARRIER; - __restore_flags(flags); + local_irq_restore(flags); } #endif @@ -2375,7 +2375,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long old_pagemask; unsigned long old_ctx; - __save_and_cli(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = (get_entryhi() & 0xff); old_pagemask = get_pagemask(); @@ -2395,7 +2395,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, BARRIER; set_pagemask (old_pagemask); flush_tlb_all(); - __restore_flags(flags); + local_irq_restore(flags); } /* Detect and size the various r4k caches. */ @@ -2469,7 +2469,7 @@ static int __init probe_scache(unsigned long config) /* This is such a bitch, you'd think they would make it * easy to do this. Away you daemons of stupidity! */ - __save_and_cli(flags); + local_irq_save(flags); /* Fill each size-multiple cache line with a valid tag. */ pow2 = (64 * 1024); @@ -2513,7 +2513,7 @@ static int __init probe_scache(unsigned long config) break; pow2 <<= 1; } - __restore_flags(flags); + local_irq_restore(flags); addr -= begin; printk("Secondary cache sized at %dK linesize %d bytes.\n", (int) (addr >> 10), sc_lsize); diff --git a/arch/mips/mm/r5432.c b/arch/mips/mm/r5432.c index d687ae987748..fad7d7e356f1 100644 --- a/arch/mips/mm/r5432.c +++ b/arch/mips/mm/r5432.c @@ -554,7 +554,7 @@ void flush_tlb_all(void) printk("[tlball]"); #endif - __save_and_cli(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = (get_entryhi() & 0xff); set_entryhi(KSEG0); @@ -574,7 +574,7 @@ void flush_tlb_all(void) } BARRIER; set_entryhi(old_ctx); - __restore_flags(flags); + local_irq_restore(flags); } void flush_tlb_mm(struct mm_struct *mm) @@ -585,11 +585,11 @@ void flush_tlb_mm(struct mm_struct *mm) #ifdef DEBUG_TLB printk("[tlbmm<%d>]", mm->context); #endif - __save_and_cli(flags); + local_irq_save(flags); get_new_mmu_context(mm, asid_cache); if (mm == current->active_mm) set_entryhi(mm->context & 0xff); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -604,7 +604,7 @@ void flush_tlb_range(struct mm_struct *mm, unsigned long start, printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff), start, end); #endif - __save_and_cli(flags); + local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; size = (size + 1) >> 1; if(size <= NTLB_ENTRIES_HALF) { @@ -638,7 +638,7 @@ void flush_tlb_range(struct mm_struct *mm, unsigned long start, if (mm == current->active_mm) set_entryhi(mm->context & 0xff); } - __restore_flags(flags); + local_irq_restore(flags); } } @@ -653,7 +653,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) #endif newpid = (vma->vm_mm->context & 0xff); page &= (PAGE_MASK << 1); - __save_and_cli(flags); + local_irq_save(flags); oldpid = (get_entryhi() & 0xff); set_entryhi(page | newpid); BARRIER; @@ -671,7 +671,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) finish: BARRIER; set_entryhi(oldpid); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -720,7 +720,7 @@ void update_mmu_cache(struct vm_area_struct * vma, } #endif - __save_and_cli(flags); + local_irq_save(flags); address &= (PAGE_MASK << 1); set_entryhi(address | (pid)); pgdp = pgd_offset(vma->vm_mm, address); @@ -743,7 +743,7 @@ void update_mmu_cache(struct vm_area_struct * vma, BARRIER; set_entryhi(pid); BARRIER; - __restore_flags(flags); + local_irq_restore(flags); } void show_regs(struct pt_regs * regs) @@ -779,7 +779,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long old_pagemask; unsigned long old_ctx; - __save_and_cli(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = (get_entryhi() & 0xff); old_pagemask = get_pagemask(); @@ -799,7 +799,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, BARRIER; set_pagemask (old_pagemask); flush_tlb_all(); - __restore_flags(flags); + local_irq_restore(flags); } /* Detect and size the various r4k caches. */ diff --git a/arch/mips/mm/rm7k.c b/arch/mips/mm/rm7k.c index 76b368d23e8c..192abc877f00 100644 --- a/arch/mips/mm/rm7k.c +++ b/arch/mips/mm/rm7k.c @@ -310,7 +310,7 @@ void flush_tlb_all(void) unsigned long old_ctx; int entry; - __save_and_cli(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = get_entryhi() & 0xff; set_entryhi(KSEG0); @@ -330,7 +330,7 @@ void flush_tlb_all(void) } BARRIER; set_entryhi(old_ctx); - __restore_flags(flags); + local_irq_restore(flags); } void flush_tlb_mm(struct mm_struct *mm) @@ -338,11 +338,11 @@ void flush_tlb_mm(struct mm_struct *mm) if(mm->context != 0) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); get_new_mmu_context(mm, asid_cache); if (mm == current->mm) set_entryhi(mm->context & 0xff); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -353,7 +353,7 @@ void flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long flags; int size; - __save_and_cli(flags); + local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; size = (size + 1) >> 1; if (size <= (ntlb_entries() / 2)) { @@ -387,7 +387,7 @@ void flush_tlb_range(struct mm_struct *mm, unsigned long start, if(mm == current->mm) set_entryhi(mm->context & 0xff); } - __restore_flags(flags); + local_irq_restore(flags); } } @@ -399,7 +399,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) newpid = (vma->vm_mm->context & 0xff); page &= (PAGE_MASK << 1); - __save_and_cli(flags); + local_irq_save(flags); oldpid = (get_entryhi() & 0xff); set_entryhi(page | newpid); BARRIER; @@ -417,7 +417,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) finish: BARRIER; set_entryhi(oldpid); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -460,7 +460,7 @@ void update_mmu_cache(struct vm_area_struct * vma, pid = get_entryhi() & 0xff; - __save_and_cli(flags); + local_irq_save(flags); address &= (PAGE_MASK << 1); set_entryhi(address | (pid)); pgdp = pgd_offset(vma->vm_mm, address); @@ -483,7 +483,7 @@ void update_mmu_cache(struct vm_area_struct * vma, BARRIER; set_entryhi(pid); BARRIER; - __restore_flags(flags); + local_irq_restore(flags); } void show_regs(struct pt_regs * regs) @@ -519,7 +519,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long old_pagemask; unsigned long old_ctx; - __save_and_cli(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = (get_entryhi() & 0xff); old_pagemask = get_pagemask(); @@ -539,7 +539,7 @@ void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, BARRIER; set_pagemask (old_pagemask); flush_tlb_all(); - __restore_flags(flags); + local_irq_restore(flags); } /* Used for loading TLB entries before trap_init() has started, when we @@ -557,7 +557,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, unsigned long old_pagemask; unsigned long old_ctx; - __save_and_cli(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = (get_entryhi() & 0xff); old_pagemask = get_pagemask(); @@ -582,7 +582,7 @@ __init int add_temporary_entry(unsigned long entrylo0, unsigned long entrylo1, BARRIER; set_pagemask (old_pagemask); out: - __restore_flags(flags); + local_irq_restore(flags); return ret; } diff --git a/arch/mips/mm/sb1.c b/arch/mips/mm/sb1.c index 34bef7ba999b..caf21add013d 100644 --- a/arch/mips/mm/sb1.c +++ b/arch/mips/mm/sb1.c @@ -67,7 +67,7 @@ void flush_tlb_all(void) unsigned long old_ctx; int entry; - __save_and_cli(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = (get_entryhi() & 0xff); set_entrylo0(0); @@ -78,7 +78,7 @@ void flush_tlb_all(void) tlb_write_indexed(); } set_entryhi(old_ctx); - __restore_flags(flags); + local_irq_restore(flags); } diff --git a/arch/mips/philips/nino/irq.c b/arch/mips/philips/nino/irq.c index 40ad3adc0c94..7bd0de00a9b5 100644 --- a/arch/mips/philips/nino/irq.c +++ b/arch/mips/philips/nino/irq.c @@ -177,7 +177,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs) action = *(irq + irq_action); if (action) { if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); do_random = 0; do { do_random |= action->flags; @@ -187,7 +187,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs *regs) if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); unmask_irq(irq); - __cli(); + local_irq_disable(); } else { IntClear1 = ~0; IntClear3 = ~0; diff --git a/arch/mips/sgi/kernel/indy_sc.c b/arch/mips/sgi/kernel/indy_sc.c index a60894d4fdc9..0044b1f8620d 100644 --- a/arch/mips/sgi/kernel/indy_sc.c +++ b/arch/mips/sgi/kernel/indy_sc.c @@ -75,7 +75,7 @@ static void indy_sc_wback_invalidate(unsigned long addr, unsigned long size) first_line = SC_INDEX(addr); last_line = SC_INDEX(addr + size - 1); - __save_and_cli(flags); + local_irq_save(flags); if (first_line <= last_line) { indy_sc_wipe(first_line, last_line); goto out; @@ -84,7 +84,7 @@ static void indy_sc_wback_invalidate(unsigned long addr, unsigned long size) indy_sc_wipe(first_line, SC_SIZE - SC_LINE); indy_sc_wipe(0, last_line); out: - __restore_flags(flags); + local_irq_restore(flags); } static void indy_sc_enable(void) diff --git a/arch/mips64/kernel/ptrace.c b/arch/mips64/kernel/ptrace.c index c90b1428e8c2..874ccc438aa7 100644 --- a/arch/mips64/kernel/ptrace.c +++ b/arch/mips64/kernel/ptrace.c @@ -158,10 +158,10 @@ asmlinkage int sys32_ptrace(int request, int pid, int addr, int data) break; case FPC_EIR: { /* implementation / version register */ unsigned int flags; - __save_flags(flags); + local_save_flags(flags); set_cp0_status(ST0_CU1, ST0_CU1); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); - __restore_flags(flags); + local_irq_restore(flags); break; } default: @@ -418,10 +418,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data) break; case FPC_EIR: { /* implementation / version register */ unsigned int flags; - __save_flags(flags); + local_save_flags(flags); set_cp0_status(ST0_CU1, ST0_CU1); __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp)); - __restore_flags(flags); + local_irq_restore(flags); break; } default: diff --git a/arch/mips64/lib/dump_tlb.c b/arch/mips64/lib/dump_tlb.c index feff0f7f0058..1cd822bc153c 100644 --- a/arch/mips64/lib/dump_tlb.c +++ b/arch/mips64/lib/dump_tlb.c @@ -101,7 +101,7 @@ dump_tlb_addr(unsigned long addr) unsigned int flags, oldpid; int index; - __save_and_cli(flags); + local_irq_save(flags); oldpid = get_entryhi() & 0xff; BARRIER; set_entryhi((addr & PAGE_MASK) | oldpid); @@ -110,7 +110,7 @@ dump_tlb_addr(unsigned long addr) BARRIER; index = get_index(); set_entryhi(oldpid); - __restore_flags(flags); + local_irq_restore(flags); if (index < 0) { printk("No entry for address 0x%08lx in TLB\n", addr); diff --git a/arch/mips64/mips-boards/generic/time.c b/arch/mips64/mips-boards/generic/time.c index 20786f691554..b10c65aaa7a7 100644 --- a/arch/mips64/mips-boards/generic/time.c +++ b/arch/mips64/mips-boards/generic/time.c @@ -188,7 +188,7 @@ static unsigned long __init cal_r4koff(void) unsigned long count; unsigned int flags; - __save_and_cli(flags); + local_irq_save(flags); /* Start counter exactly on falling edge of update flag */ while (CMOS_READ(RTC_REG_A) & RTC_UIP); @@ -204,7 +204,7 @@ static unsigned long __init cal_r4koff(void) count = read_32bit_cp0_register(CP0_COUNT); /* restore interrupts */ - __restore_flags(flags); + local_irq_restore(flags); return (count / HZ); } diff --git a/arch/mips64/mm/andes.c b/arch/mips64/mm/andes.c index 7f65ff0cdc2a..55dc3f905011 100644 --- a/arch/mips64/mm/andes.c +++ b/arch/mips64/mm/andes.c @@ -143,7 +143,7 @@ andes_flush_tlb_all(void) printk("[tlball]"); #endif - __save_and_cli(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = get_entryhi() & 0xff; set_entryhi(CKSEG0); @@ -159,7 +159,7 @@ andes_flush_tlb_all(void) entry++; } set_entryhi(old_ctx); - __restore_flags(flags); + local_irq_restore(flags); } static void andes_flush_tlb_mm(struct mm_struct *mm) @@ -170,11 +170,11 @@ static void andes_flush_tlb_mm(struct mm_struct *mm) #ifdef DEBUG_TLB printk("[tlbmm<%d>]", mm->context); #endif - __save_and_cli(flags); + local_irq_save(flags); get_new_cpu_mmu_context(mm, smp_processor_id()); if(mm == current->mm) set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 0xff); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -192,7 +192,7 @@ andes_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff), start, end); #endif - __save_and_cli(flags); + local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; size = (size + 1) >> 1; if(size <= NTLB_ENTRIES_HALF) { @@ -223,7 +223,7 @@ andes_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 0xff); } - __restore_flags(flags); + local_irq_restore(flags); } } @@ -239,7 +239,7 @@ andes_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) #endif newpid = (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff); page &= (PAGE_MASK << 1); - __save_and_cli(flags); + local_irq_save(flags); oldpid = (get_entryhi() & 0xff); set_entryhi(page | newpid); tlb_probe(); @@ -253,7 +253,7 @@ andes_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) finish: set_entryhi(oldpid); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -275,7 +275,7 @@ static void andes_update_mmu_cache(struct vm_area_struct * vma, if (current->active_mm != vma->vm_mm) return; - __save_and_cli(flags); + local_irq_save(flags); pid = get_entryhi() & 0xff; if((pid != (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff)) || @@ -301,7 +301,7 @@ static void andes_update_mmu_cache(struct vm_area_struct * vma, tlb_write_indexed(); } set_entryhi(pid); - __restore_flags(flags); + local_irq_restore(flags); } static void andes_show_regs(struct pt_regs *regs) diff --git a/arch/mips64/mm/r4xx0.c b/arch/mips64/mm/r4xx0.c index f5a2e54b89d1..00b5d4845df4 100644 --- a/arch/mips64/mm/r4xx0.c +++ b/arch/mips64/mm/r4xx0.c @@ -194,7 +194,7 @@ static void r4k_clear_page_r4600_v2(void * page) { unsigned int flags; - __save_and_cli(flags); + local_irq_save(flags); *(volatile unsigned int *)KSEG1; __asm__ __volatile__( ".set\tnoreorder\n\t" @@ -217,7 +217,7 @@ static void r4k_clear_page_r4600_v2(void * page) :"=r" (page) :"0" (page), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D) :"$1", "memory"); - __restore_flags(flags); + local_irq_restore(flags); } /* @@ -473,7 +473,7 @@ static void r4k_copy_page_r4600_v2(void * to, void * from) unsigned long dummy1, dummy2, reg1, reg2; unsigned int flags; - __save_and_cli(flags); + local_irq_save(flags); __asm__ __volatile__( ".set\tnoreorder\n\t" ".set\tnoat\n\t" @@ -512,7 +512,7 @@ static void r4k_copy_page_r4600_v2(void * to, void * from) :"=r" (dummy1), "=r" (dummy2), "=&r" (reg1), "=&r" (reg2) :"0" (to), "1" (from), "I" (PAGE_SIZE), "i" (Create_Dirty_Excl_D)); - __restore_flags(flags); + local_irq_restore(flags); } /* @@ -699,81 +699,81 @@ static inline void r4k_flush_cache_all_s16d16i16(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache16(); blast_icache16(); blast_scache16(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_s32d16i16(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache16(); blast_icache16(); blast_scache32(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_s64d16i16(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache16(); blast_icache16(); blast_scache64(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_s128d16i16(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache16(); blast_icache16(); blast_scache128(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_s32d32i32(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache32(); blast_icache32(); blast_scache32(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_s64d32i32(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache32(); blast_icache32(); blast_scache64(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_s128d32i32(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache32(); blast_icache32(); blast_scache128(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_d16i16(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache16(); blast_icache16(); - __restore_flags(flags); + local_irq_restore(flags); } static inline void r4k_flush_cache_all_d32i32(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache32(); blast_icache32(); - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_range_s16d16i16(struct vm_area_struct *vma, @@ -799,7 +799,7 @@ static void r4k_flush_cache_range_s16d16i16(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -809,7 +809,7 @@ static void r4k_flush_cache_range_s16d16i16(struct vm_area_struct *vma, blast_scache16_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -837,7 +837,7 @@ static void r4k_flush_cache_range_s32d16i16(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -847,7 +847,7 @@ static void r4k_flush_cache_range_s32d16i16(struct vm_area_struct *vma, blast_scache32_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -875,7 +875,7 @@ static void r4k_flush_cache_range_s64d16i16(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -885,7 +885,7 @@ static void r4k_flush_cache_range_s64d16i16(struct vm_area_struct *vma, blast_scache64_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -913,7 +913,7 @@ static void r4k_flush_cache_range_s128d16i16(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -923,7 +923,7 @@ static void r4k_flush_cache_range_s128d16i16(struct vm_area_struct *vma, blast_scache128_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -951,7 +951,7 @@ static void r4k_flush_cache_range_s32d32i32(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -961,7 +961,7 @@ static void r4k_flush_cache_range_s32d32i32(struct vm_area_struct *vma, blast_scache32_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -989,7 +989,7 @@ static void r4k_flush_cache_range_s64d32i32(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -999,7 +999,7 @@ static void r4k_flush_cache_range_s64d32i32(struct vm_area_struct *vma, blast_scache64_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -1027,7 +1027,7 @@ static void r4k_flush_cache_range_s128d32i32(struct vm_area_struct *vma, pmd_t *pmd; pte_t *pte; - __save_and_cli(flags); + local_irq_save(flags); while(start < end) { pgd = pgd_offset(mm, start); pmd = pmd_offset(pgd, start); @@ -1037,7 +1037,7 @@ static void r4k_flush_cache_range_s128d32i32(struct vm_area_struct *vma, blast_scache128_page(start); start += PAGE_SIZE; } - __restore_flags(flags); + local_irq_restore(flags); } } } @@ -1054,9 +1054,9 @@ static void r4k_flush_cache_range_d16i16(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - __save_and_cli(flags); + local_irq_save(flags); blast_dcache16(); blast_icache16(); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -1072,9 +1072,9 @@ static void r4k_flush_cache_range_d32i32(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("crange[%d,%08lx,%08lx]", (int)mm->context, start, end); #endif - __save_and_cli(flags); + local_irq_save(flags); blast_dcache32(); blast_icache32(); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -1192,7 +1192,7 @@ static void r4k_flush_cache_page_s16d16i16(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1221,7 +1221,7 @@ static void r4k_flush_cache_page_s16d16i16(struct vm_area_struct *vma, } else blast_scache16_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_s32d16i16(struct vm_area_struct *vma, @@ -1243,7 +1243,7 @@ static void r4k_flush_cache_page_s32d16i16(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1271,7 +1271,7 @@ static void r4k_flush_cache_page_s32d16i16(struct vm_area_struct *vma, } else blast_scache32_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_s64d16i16(struct vm_area_struct *vma, @@ -1293,7 +1293,7 @@ static void r4k_flush_cache_page_s64d16i16(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1322,7 +1322,7 @@ static void r4k_flush_cache_page_s64d16i16(struct vm_area_struct *vma, } else blast_scache64_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_s128d16i16(struct vm_area_struct *vma, @@ -1344,7 +1344,7 @@ static void r4k_flush_cache_page_s128d16i16(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1374,7 +1374,7 @@ static void r4k_flush_cache_page_s128d16i16(struct vm_area_struct *vma, } else blast_scache128_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_s32d32i32(struct vm_area_struct *vma, @@ -1396,7 +1396,7 @@ static void r4k_flush_cache_page_s32d32i32(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1427,7 +1427,7 @@ static void r4k_flush_cache_page_s32d32i32(struct vm_area_struct *vma, } else blast_scache32_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_s64d32i32(struct vm_area_struct *vma, @@ -1449,7 +1449,7 @@ static void r4k_flush_cache_page_s64d32i32(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1480,7 +1480,7 @@ static void r4k_flush_cache_page_s64d32i32(struct vm_area_struct *vma, } else blast_scache64_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_s128d32i32(struct vm_area_struct *vma, @@ -1502,7 +1502,7 @@ static void r4k_flush_cache_page_s128d32i32(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1531,7 +1531,7 @@ static void r4k_flush_cache_page_s128d32i32(struct vm_area_struct *vma, } else blast_scache128_page(page); out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_d16i16(struct vm_area_struct *vma, @@ -1553,7 +1553,7 @@ static void r4k_flush_cache_page_d16i16(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1581,7 +1581,7 @@ static void r4k_flush_cache_page_d16i16(struct vm_area_struct *vma, blast_dcache16_page_indexed(page); } out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_d32i32(struct vm_area_struct *vma, @@ -1603,7 +1603,7 @@ static void r4k_flush_cache_page_d32i32(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1633,7 +1633,7 @@ static void r4k_flush_cache_page_d32i32(struct vm_area_struct *vma, blast_dcache32_page_indexed(page); } out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_cache_page_d32i32_r4600(struct vm_area_struct *vma, @@ -1655,7 +1655,7 @@ static void r4k_flush_cache_page_d32i32_r4600(struct vm_area_struct *vma, #ifdef DEBUG_CACHE printk("cpage[%d,%08lx]", (int)mm->context, page); #endif - __save_and_cli(flags); + local_irq_save(flags); page &= PAGE_MASK; pgdp = pgd_offset(mm, page); pmdp = pmd_offset(pgdp, page); @@ -1685,7 +1685,7 @@ static void r4k_flush_cache_page_d32i32_r4600(struct vm_area_struct *vma, blast_dcache32_page_indexed(page ^ dcache_waybit); } out: - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_page_to_ram_s16(struct page *page) @@ -1712,18 +1712,18 @@ static void r4k_flush_page_to_ram_d16(struct page *page) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache16_page((unsigned long)page_address(page)); - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_page_to_ram_d32(struct page *page) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); blast_dcache32_page((unsigned long)page_address(page)); - __restore_flags(flags); + local_irq_restore(flags); } /* @@ -1746,7 +1746,7 @@ static void r4k_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) flush_cache_l1(); } else { /* Workaround for R4600 bug. See comment above. */ - __save_and_cli(flags); + local_irq_save(flags); *(volatile unsigned long *)KSEG1; a = addr & ~((unsigned long)dc_lsize - 1); @@ -1756,7 +1756,7 @@ static void r4k_dma_cache_wback_inv_pc(unsigned long addr, unsigned long size) if (a == end) break; a += dc_lsize; } - __restore_flags(flags); + local_irq_restore(flags); } bc_wback_inv(addr, size); } @@ -1788,7 +1788,7 @@ static void r4k_dma_cache_inv_pc(unsigned long addr, unsigned long size) flush_cache_l1(); } else { /* Workaround for R4600 bug. See comment above. */ - __save_and_cli(flags); + local_irq_save(flags); *(volatile unsigned long *)KSEG1; a = addr & ~((unsigned long)dc_lsize - 1); @@ -1798,7 +1798,7 @@ static void r4k_dma_cache_inv_pc(unsigned long addr, unsigned long size) if (a == end) break; a += dc_lsize; } - __restore_flags(flags); + local_irq_restore(flags); } bc_inv(addr, size); @@ -1844,7 +1844,7 @@ static void r4600v20k_flush_cache_sigtramp(unsigned long addr) { unsigned int flags; - __save_and_cli(flags); + local_irq_save(flags); /* Clear internal cache refill buffer */ *(volatile unsigned int *)KSEG1; @@ -1852,7 +1852,7 @@ static void r4600v20k_flush_cache_sigtramp(unsigned long addr) protected_writeback_dcache_line(addr & ~(dc_lsize - 1)); protected_flush_icache_line(addr & ~(ic_lsize - 1)); - __restore_flags(flags); + local_irq_restore(flags); } #undef DEBUG_TLB @@ -1871,7 +1871,7 @@ static inline void r4k_flush_tlb_all(void) printk("[tlball]"); #endif - __save_and_cli(flags); + local_irq_save(flags); /* Save old context and create impossible VPN2 value */ old_ctx = (get_entryhi() & 0xff); set_entryhi(KSEG0); @@ -1891,7 +1891,7 @@ static inline void r4k_flush_tlb_all(void) } BARRIER; set_entryhi(old_ctx); - __restore_flags(flags); + local_irq_restore(flags); } static void r4k_flush_tlb_mm(struct mm_struct *mm) @@ -1902,11 +1902,11 @@ static void r4k_flush_tlb_mm(struct mm_struct *mm) #ifdef DEBUG_TLB printk("[tlbmm<%d>]", mm->context); #endif - __save_and_cli(flags); + local_irq_save(flags); get_new_cpu_mmu_context(mm, smp_processor_id()); if(mm == current->mm) set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 0xff); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -1923,7 +1923,7 @@ static void r4k_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, printk("[tlbrange<%02x,%08lx,%08lx>]", (mm->context & 0xff), start, end); #endif - __save_and_cli(flags); + local_irq_save(flags); size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; size = (size + 1) >> 1; if(size <= NTLB_ENTRIES_HALF) { @@ -1958,7 +1958,7 @@ static void r4k_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, set_entryhi(CPU_CONTEXT(smp_processor_id(), mm) & 0xff); } - __restore_flags(flags); + local_irq_restore(flags); } } @@ -1973,7 +1973,7 @@ static void r4k_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) #endif newpid = (CPU_CONTEXT(smp_processor_id(), vma->vm_mm) & 0xff); page &= (PAGE_MASK << 1); - __save_and_cli(flags); + local_irq_save(flags); oldpid = (get_entryhi() & 0xff); set_entryhi(page | newpid); BARRIER; @@ -1991,7 +1991,7 @@ static void r4k_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) finish: BARRIER; set_entryhi(oldpid); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -2018,7 +2018,7 @@ static void r4k_update_mmu_cache(struct vm_area_struct * vma, if (current->active_mm != vma->vm_mm) return; - __save_and_cli(flags); + local_irq_save(flags); pid = (get_entryhi() & 0xff); #ifdef DEBUG_TLB @@ -2052,7 +2052,7 @@ static void r4k_update_mmu_cache(struct vm_area_struct * vma, BARRIER; set_entryhi(pid); BARRIER; - __restore_flags(flags); + local_irq_restore(flags); } #if 0 @@ -2065,7 +2065,7 @@ static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma, pte_t *ptep; int idx; - __save_and_cli(flags); + local_irq_save(flags); address &= (PAGE_MASK << 1); set_entryhi(address | (get_entryhi() & 0xff)); pgdp = pgd_offset(vma->vm_mm, address); @@ -2081,7 +2081,7 @@ static void r4k_update_mmu_cache_hwbug(struct vm_area_struct * vma, else tlb_write_indexed(); BARRIER; - __restore_flags(flags); + local_irq_restore(flags); } #endif @@ -2171,7 +2171,7 @@ static int __init probe_scache(unsigned long config) /* This is such a bitch, you'd think they would make it * easy to do this. Away you daemons of stupidity! */ - __save_and_cli(flags); + local_irq_save(flags); /* Fill each size-multiple cache line with a valid tag. */ pow2 = (64 * 1024); @@ -2207,7 +2207,7 @@ static int __init probe_scache(unsigned long config) break; pow2 <<= 1; } - __restore_flags(flags); + local_irq_restore(flags); addr -= begin; printk("Secondary cache sized at %dK linesize %d\n", (int) (addr >> 10), sc_lsize); diff --git a/arch/mips64/sgi-ip22/ip22-int.c b/arch/mips64/sgi-ip22/ip22-int.c index e87fd162f4d5..dcc328ab7dfc 100644 --- a/arch/mips64/sgi-ip22/ip22-int.c +++ b/arch/mips64/sgi-ip22/ip22-int.c @@ -306,7 +306,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) action = *(irq + irq_action); if (action) { if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); action = *(irq + irq_action); do_random = 0; do { @@ -316,7 +316,7 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) } while (action); if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); } irq_exit(cpu, irq); diff --git a/arch/mips64/sgi-ip22/ip22-sc.c b/arch/mips64/sgi-ip22/ip22-sc.c index 62d9db8d1c46..b550746c5a4a 100644 --- a/arch/mips64/sgi-ip22/ip22-sc.c +++ b/arch/mips64/sgi-ip22/ip22-sc.c @@ -58,7 +58,7 @@ static void indy_sc_wback_invalidate(unsigned long addr, unsigned long size) first_line = SC_INDEX(addr); last_line = SC_INDEX(addr + size - 1); - __save_and_cli(flags); + local_irq_save(flags); if (first_line <= last_line) { indy_sc_wipe(first_line, last_line); goto out; @@ -67,7 +67,7 @@ static void indy_sc_wback_invalidate(unsigned long addr, unsigned long size) indy_sc_wipe(first_line, SC_SIZE - SC_LINE); indy_sc_wipe(0, last_line); out: - __restore_flags(flags); + local_irq_restore(flags); } static void inline indy_sc_enable(void) diff --git a/arch/mips64/sgi-ip27/ip27-irq.c b/arch/mips64/sgi-ip27/ip27-irq.c index b25c98ddb9e3..aa423e31ec6a 100644 --- a/arch/mips64/sgi-ip27/ip27-irq.c +++ b/arch/mips64/sgi-ip27/ip27-irq.c @@ -175,7 +175,7 @@ static void do_IRQ(cpuid_t thiscpu, int irq, struct pt_regs * regs) action = *(irq + irq_action); if (action) { if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); do_random = 0; do { do_random |= action->flags; @@ -184,7 +184,7 @@ static void do_IRQ(cpuid_t thiscpu, int irq, struct pt_regs * regs) } while (action); if (do_random & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); } irq_exit(thiscpu, irq); @@ -506,9 +506,9 @@ static inline void wait_on_irq(int cpu) show("wait_on_irq"); count = ~0; } - __sti(); + local_irq_enable(); SYNC_OTHER_CORES(cpu); - __cli(); + local_irq_disable(); if (irqs_running()) continue; if (spin_is_locked(&global_irq_lock)) @@ -555,10 +555,10 @@ void __global_cli(void) { unsigned int flags; - __save_flags(flags); + local_save_flags(flags); if (flags & ST0_IE) { int cpu = smp_processor_id(); - __cli(); + local_irq_disable(); if (!local_irq_count(cpu)) get_irqlock(cpu); } @@ -570,7 +570,7 @@ void __global_sti(void) if (!local_irq_count(cpu)) release_irqlock(cpu); - __sti(); + local_irq_enable(); } /* @@ -587,7 +587,7 @@ unsigned long __global_save_flags(void) unsigned long flags; int cpu = smp_processor_id(); - __save_flags(flags); + local_save_flags(flags); local_enabled = (flags & ST0_IE); /* default to local */ retval = 2 + local_enabled; @@ -612,10 +612,10 @@ void __global_restore_flags(unsigned long flags) __global_sti(); break; case 2: - __cli(); + local_irq_disable(); break; case 3: - __sti(); + local_irq_enable(); break; default: printk("global_restore_flags: %08lx\n", flags); diff --git a/arch/ppc/kernel/iSeries_head.S b/arch/ppc/kernel/iSeries_head.S index 9981fc98fe2f..e1f616582ec8 100644 --- a/arch/ppc/kernel/iSeries_head.S +++ b/arch/ppc/kernel/iSeries_head.S @@ -1103,7 +1103,7 @@ _GLOBAL(HvCall7) /* enable and check for decrementers/lpEvents */ mr r3,r31 - bl __restore_flags + bl local_irq_restore /* Restore r3, r4 and LR */ lwz r3,44(r1) @@ -1292,7 +1292,7 @@ _GLOBAL(HvCall7Ret16) /* enable and check for decrementers/lpEvents */ mr r3,r31 - bl __restore_flags + bl local_irq_restore lwz r3,40(r1) mtlr r3 diff --git a/arch/ppc/kernel/iSeries_misc.S b/arch/ppc/kernel/iSeries_misc.S index dcaa807f74aa..525ace2a6d15 100644 --- a/arch/ppc/kernel/iSeries_misc.S +++ b/arch/ppc/kernel/iSeries_misc.S @@ -61,16 +61,16 @@ _GLOBAL(get_tb64) mtmsr r5 /* restore MSR_EE */ blr -/* void __save_flags(unsigned long *flags) */ -_GLOBAL(__save_flags_ptr) +/* void local_save_flags(unsigned long *flags) */ +_GLOBAL(local_save_flags_ptr) mfspr r4,SPRG1 /* Get Paca pointer */ lbz r4,PACAPROCENABLED(r4) stw r4,0(r3) blr -_GLOBAL(__save_flags_ptr_end) +_GLOBAL(local_save_flags_ptr_end) -/* void __restore_flags(unsigned long flags) */ -_GLOBAL(__restore_flags) +/* void local_irq_restore(unsigned long flags) */ +_GLOBAL(local_irq_restore) cmpi 0,r3,0 /* Are we enabling? */ beq 0f /* No - then skip interrupt checks */ @@ -104,19 +104,19 @@ _GLOBAL(__restore_flags) mfspr r4,SPRG1 stb r3,PACAPROCENABLED(r4) blr -_GLOBAL(__restore_flags_end) +_GLOBAL(local_irq_restore_end) -_GLOBAL(__cli) +_GLOBAL(local_irq_disable) mfspr r4,SPRG1 li r3,0 stb r3,PACAPROCENABLED(r4) blr /* Done */ -_GLOBAL(__cli_end) +_GLOBAL(local_irq_disable_end) -_GLOBAL(__sti) +_GLOBAL(local_irq_enable) li r3,1 - b __restore_flags -_GLOBAL(__sti_end) + b local_irq_restore +_GLOBAL(local_irq_enable_end) /* * We were about to enable interrupts but we have to simulate diff --git a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c index 30c2f797b47c..221e2dcab76e 100644 --- a/arch/ppc/kernel/idle.c +++ b/arch/ppc/kernel/idle.c @@ -120,7 +120,7 @@ void power_save(void) * Disable interrupts to prevent a lost wakeup * when going to sleep. This is necessary even with * RTLinux since we are not guaranteed an interrupt - * didn't come in and is waiting for a __sti() before + * didn't come in and is waiting for a local_irq_enable() before * emulating one. This way, we really do hard disable. * * We assume that we're sti-ed when we come in here. We @@ -163,8 +163,8 @@ void yield_shared_processor(void) u64 tb; /* Poll for I/O events */ - __cli(); - __sti(); + local_irq_disable(); + local_irq_enable(); paca = (struct Paca *)mfspr(SPRG1); if ( paca->xLpPaca.xSharedProc ) { @@ -181,8 +181,8 @@ void yield_shared_processor(void) * Disabling/enabling will check for LpEvents, IPIs * and decrementers */ - __cli(); - __sti(); + local_irq_disable(); + local_irq_enable(); ++yield_count; @@ -193,14 +193,14 @@ void yield_shared_processor(void) HvCall_yieldProcessor( HvCall_YieldTimed, tb ); /* Check here for any of the above pending or timeout expired*/ - __cli(); + local_irq_disable(); /* * The decrementer stops during the yield. Just force * a fake decrementer now and the timer_interrupt * code will straighten it all out */ paca->xLpPaca.xDecrInt = 1; - __sti(); + local_irq_enable(); } } #endif /* CONFIG_PPC_ISERIES */ diff --git a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c index e38d9b9d7826..f6d97c4933c6 100644 --- a/arch/ppc/kernel/irq.c +++ b/arch/ppc/kernel/irq.c @@ -422,7 +422,7 @@ handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action) int status = 0; if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); do { status |= action->flags; @@ -431,7 +431,7 @@ handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action) } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); } /* @@ -637,15 +637,15 @@ static inline void wait_on_irq(int cpu) show("wait_on_irq"); count = ~0; } - __sti(); + local_irq_enable(); /* - * We have to allow irqs to arrive between __sti and __cli + * We have to allow irqs to arrive between local_irq_enable and local_irq_disable * Some cpus apparently won't cause the interrupt * for several instructions. We hope that isync will * catch this --Troy */ __asm__ __volatile__ ("isync"); - __cli(); + local_irq_disable(); if (irqs_running()) continue; if (global_irq_lock) @@ -736,10 +736,10 @@ void __global_cli(void) { unsigned long flags; - __save_flags(flags); + local_save_flags(flags); if (flags & (1 << 15)) { int cpu = smp_processor_id(); - __cli(); + local_irq_disable(); if (!local_irq_count(cpu)) get_irqlock(cpu); } @@ -751,7 +751,7 @@ void __global_sti(void) if (!local_irq_count(cpu)) release_irqlock(cpu); - __sti(); + local_irq_enable(); } /* @@ -767,7 +767,7 @@ unsigned long __global_save_flags(void) int local_enabled; unsigned long flags; - __save_flags(flags); + local_save_flags(flags); local_enabled = (flags >> 15) & 1; /* default to local */ retval = 2 + local_enabled; @@ -817,10 +817,10 @@ void __global_restore_flags(unsigned long flags) __global_sti(); break; case 2: - __cli(); + local_irq_disable(); break; case 3: - __sti(); + local_irq_enable(); break; default: { diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S index f0fb7c7bb1ea..2499d5de32f3 100644 --- a/arch/ppc/kernel/misc.S +++ b/arch/ppc/kernel/misc.S @@ -207,8 +207,8 @@ _GLOBAL(call_setup_cpu) bctr #ifndef CONFIG_PPC_ISERIES /* iSeries version is in iSeries_misc.S */ -/* void __save_flags_ptr(unsigned long *flags) */ -_GLOBAL(__save_flags_ptr) +/* void local_save_flags_ptr(unsigned long *flags) */ +_GLOBAL(local_save_flags_ptr) mfmsr r4 stw r4,0(r3) blr @@ -234,10 +234,10 @@ _GLOBAL(__save_flags_ptr) nop nop nop -_GLOBAL(__save_flags_ptr_end) +_GLOBAL(local_save_flags_ptr_end) -/* void __restore_flags(unsigned long flags) */ -_GLOBAL(__restore_flags) +/* void local_irq_restore(unsigned long flags) */ +_GLOBAL(local_irq_restore) /* * Just set/clear the MSR_EE bit through restore/flags but do not * change anything else. This is needed by the RT system and makes @@ -275,9 +275,9 @@ _GLOBAL(__restore_flags) nop nop nop -_GLOBAL(__restore_flags_end) +_GLOBAL(local_irq_restore_end) -_GLOBAL(__cli) +_GLOBAL(local_irq_disable) mfmsr r0 /* Get current interrupt state */ rlwinm r3,r0,16+1,32-1,31 /* Extract old value of 'EE' */ rlwinm r0,r0,0,17,15 /* clear MSR_EE in r0 */ @@ -304,9 +304,9 @@ _GLOBAL(__cli) nop nop nop -_GLOBAL(__cli_end) +_GLOBAL(local_irq_disable_end) -_GLOBAL(__sti) +_GLOBAL(local_irq_enable) mfmsr r3 /* Get current state */ ori r3,r3,MSR_EE /* Turn on 'EE' bit */ SYNC /* Some chip revs have problems here... */ @@ -333,7 +333,7 @@ _GLOBAL(__sti) nop nop nop -_GLOBAL(__sti_end) +_GLOBAL(local_irq_enable_end) #endif /* CONFIG_PPC_ISERIES */ /* diff --git a/arch/ppc/kernel/ppc4xx_setup.c b/arch/ppc/kernel/ppc4xx_setup.c index 7bb7baf99781..d65e1d58ab37 100755 --- a/arch/ppc/kernel/ppc4xx_setup.c +++ b/arch/ppc/kernel/ppc4xx_setup.c @@ -177,7 +177,7 @@ static void ppc4xx_power_off(void) { printk("System Halted\n"); - __cli(); + local_irq_disable(); while (1) ; } @@ -185,7 +185,7 @@ static void ppc4xx_halt(void) { printk("System Halted\n"); - __cli(); + local_irq_disable(); while (1) ; } diff --git a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c index 6e732fbcd3da..15c67df84247 100644 --- a/arch/ppc/kernel/ppc_ksyms.c +++ b/arch/ppc/kernel/ppc_ksyms.c @@ -298,14 +298,14 @@ EXPORT_SYMBOL(screen_info); EXPORT_SYMBOL(__delay); #ifndef INLINE_IRQS -EXPORT_SYMBOL(__sti); -EXPORT_SYMBOL(__sti_end); -EXPORT_SYMBOL(__cli); -EXPORT_SYMBOL(__cli_end); -EXPORT_SYMBOL(__save_flags_ptr); -EXPORT_SYMBOL(__save_flags_ptr_end); -EXPORT_SYMBOL(__restore_flags); -EXPORT_SYMBOL(__restore_flags_end); +EXPORT_SYMBOL(local_irq_enable); +EXPORT_SYMBOL(local_irq_enable_end); +EXPORT_SYMBOL(local_irq_disable); +EXPORT_SYMBOL(local_irq_disable_end); +EXPORT_SYMBOL(local_save_flags_ptr); +EXPORT_SYMBOL(local_save_flags_ptr_end); +EXPORT_SYMBOL(local_irq_restore); +EXPORT_SYMBOL(local_irq_restore_end); #endif EXPORT_SYMBOL(timer_interrupt); EXPORT_SYMBOL(irq_desc); diff --git a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c index a63d75944635..7938b152319c 100644 --- a/arch/ppc/kernel/process.c +++ b/arch/ppc/kernel/process.c @@ -202,8 +202,8 @@ void __switch_to(struct task_struct *prev, struct task_struct *new) struct thread_struct *new_thread, *old_thread; unsigned long s; - __save_flags(s); - __cli(); + local_save_flags(s); + local_irq_disable(); #if CHECK_STACK check_stack(prev); check_stack(new); @@ -246,7 +246,7 @@ void __switch_to(struct task_struct *prev, struct task_struct *new) new_thread = &new->thread; old_thread = ¤t->thread; _switch(old_thread, new_thread); - __restore_flags(s); + local_irq_restore(s); } void show_regs(struct pt_regs * regs) diff --git a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c index 397059d246c0..5ac73276f493 100644 --- a/arch/ppc/kernel/smp.c +++ b/arch/ppc/kernel/smp.c @@ -164,7 +164,7 @@ void smp_send_xmon_break(int cpu) static void stop_this_cpu(void *dummy) { - __cli(); + local_irq_disable(); while (1) ; } @@ -488,9 +488,9 @@ void __init smp_commence(void) /* FIXME: This doesn't work with hotplug CPUs --RR */ if (!smp_tb_synchronized && num_online_cpus() == 2) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); smp_software_tb_sync(0); - __restore_flags(flags); + local_irq_restore(flags); } } @@ -514,7 +514,7 @@ void __init smp_callin(void) if (!smp_tb_synchronized && num_online_cpus() == 2) { smp_software_tb_sync(cpu); } - __sti(); + local_irq_enable(); } /* intel needs this */ diff --git a/arch/ppc/platforms/adir_setup.c b/arch/ppc/platforms/adir_setup.c index 2e2f48c3d81a..176a4b14b1d6 100644 --- a/arch/ppc/platforms/adir_setup.c +++ b/arch/ppc/platforms/adir_setup.c @@ -133,7 +133,7 @@ adir_setup_arch(void) static void adir_restart(char *cmd) { - __cli(); + local_irq_disable(); /* SRR0 has system reset vector, SRR1 has default MSR value */ /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */ __asm__ __volatile__ diff --git a/arch/ppc/platforms/ev64260_setup.c b/arch/ppc/platforms/ev64260_setup.c index c8ae94962934..0e3a2127f9de 100644 --- a/arch/ppc/platforms/ev64260_setup.c +++ b/arch/ppc/platforms/ev64260_setup.c @@ -286,7 +286,7 @@ ev64260_find_end_of_memory(void) static void ev64260_reset_board(void) { - __cli(); + local_irq_disable(); /* Set exception prefix high - to the firmware */ _nmask_and_or_msr(0, MSR_IP); @@ -310,7 +310,7 @@ ev64260_restart(char *cmd) static void ev64260_halt(void) { - __cli(); + local_irq_disable(); while (1); /* NOTREACHED */ } diff --git a/arch/ppc/platforms/gemini_setup.c b/arch/ppc/platforms/gemini_setup.c index 206f613f8eec..db86f459abd4 100644 --- a/arch/ppc/platforms/gemini_setup.c +++ b/arch/ppc/platforms/gemini_setup.c @@ -305,7 +305,7 @@ void __init gemini_init_l2(void) void gemini_restart(char *cmd) { - __cli(); + local_irq_disable(); /* make a clean restart, not via the MPIC */ _gemini_reboot(); for(;;); diff --git a/arch/ppc/platforms/iSeries_pic.c b/arch/ppc/platforms/iSeries_pic.c index 1c32a7d1d25a..c4f79b017f64 100644 --- a/arch/ppc/platforms/iSeries_pic.c +++ b/arch/ppc/platforms/iSeries_pic.c @@ -65,10 +65,10 @@ int do_IRQ(struct pt_regs *regs) lpq = paca->lpQueuePtr; if ( lpq ) { - __save_flags( flags ); - __cli(); + local_save_flags( flags ); + local_irq_disable(); lpEvent_count += ItLpQueue_process( lpq, regs ); - __restore_flags( flags ); + local_irq_restore( flags ); } hardirq_exit( cpu ); diff --git a/arch/ppc/platforms/k2_setup.c b/arch/ppc/platforms/k2_setup.c index 26ba26243ddc..c64f3e5bccaf 100644 --- a/arch/ppc/platforms/k2_setup.c +++ b/arch/ppc/platforms/k2_setup.c @@ -205,7 +205,7 @@ k2_setup_arch(void) static void k2_restart(char *cmd) { - __cli(); + local_irq_disable(); /* SRR0 has system reset vector, SRR1 has default MSR value */ /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */ __asm__ __volatile__ diff --git a/arch/ppc/platforms/lopec_setup.c b/arch/ppc/platforms/lopec_setup.c index 2c63c6f8ad5c..75aff85a5880 100644 --- a/arch/ppc/platforms/lopec_setup.c +++ b/arch/ppc/platforms/lopec_setup.c @@ -84,7 +84,7 @@ lopec_restart(char *cmd) reg |= 0x80; *((unsigned char *) LOPEC_SYSSTAT1) = reg; - __cli(); + local_irq_disable(); while(1); #undef LOPEC_SYSSTAT1 } @@ -92,7 +92,7 @@ lopec_restart(char *cmd) static void lopec_halt(void) { - __cli(); + local_irq_disable(); while(1); } diff --git a/arch/ppc/platforms/mcpn765_setup.c b/arch/ppc/platforms/mcpn765_setup.c index 1ec1a539a92d..2b77156877a4 100644 --- a/arch/ppc/platforms/mcpn765_setup.c +++ b/arch/ppc/platforms/mcpn765_setup.c @@ -226,7 +226,7 @@ mcpn765_map_io(void) static void mcpn765_reset_board(void) { - __cli(); + local_irq_disable(); /* Set exception prefix high - to the firmware */ _nmask_and_or_msr(0, MSR_IP); @@ -257,7 +257,7 @@ mcpn765_power_off(void) static void mcpn765_halt(void) { - __cli(); + local_irq_disable(); while (1); /* NOTREACHED */ } diff --git a/arch/ppc/platforms/menf1_setup.c b/arch/ppc/platforms/menf1_setup.c index 2c456cfd5ae6..42b83fc0edd9 100644 --- a/arch/ppc/platforms/menf1_setup.c +++ b/arch/ppc/platforms/menf1_setup.c @@ -93,7 +93,7 @@ menf1_restart(char *cmd) int picr1; struct pci_dev *pdev; - __cli(); + local_irq_disable(); /* * Firmware doesn't like re-entry using Map B (CHRP), so make sure the @@ -130,7 +130,7 @@ menf1_restart(char *cmd) static void menf1_halt(void) { - __cli(); + local_irq_disable(); while (1); } diff --git a/arch/ppc/platforms/mvme5100_setup.c b/arch/ppc/platforms/mvme5100_setup.c index 71c2d6e19c85..15413da09523 100644 --- a/arch/ppc/platforms/mvme5100_setup.c +++ b/arch/ppc/platforms/mvme5100_setup.c @@ -199,7 +199,7 @@ mvme5100_map_io(void) static void mvme5100_reset_board(void) { - __cli(); + local_irq_disable(); /* Set exception prefix high - to the firmware */ _nmask_and_or_msr(0, MSR_IP); @@ -223,7 +223,7 @@ mvme5100_restart(char *cmd) static void mvme5100_halt(void) { - __cli(); + local_irq_disable(); while (1); } diff --git a/arch/ppc/platforms/pcore_setup.c b/arch/ppc/platforms/pcore_setup.c index 5ad848ea734f..14a01e866b07 100644 --- a/arch/ppc/platforms/pcore_setup.c +++ b/arch/ppc/platforms/pcore_setup.c @@ -138,7 +138,7 @@ pcore_setup_arch(void) static void pcore_restart(char *cmd) { - __cli(); + local_irq_disable(); /* Hard reset */ writeb(0x11, 0xfe000332); while(1); @@ -147,7 +147,7 @@ pcore_restart(char *cmd) static void pcore_halt(void) { - __cli(); + local_irq_disable(); /* Turn off user LEDs */ writeb(0x00, 0xfe000300); while (1); diff --git a/arch/ppc/platforms/powerpmc250.c b/arch/ppc/platforms/powerpmc250.c index 3dd0f22aac0e..25bd9165698f 100644 --- a/arch/ppc/platforms/powerpmc250.c +++ b/arch/ppc/platforms/powerpmc250.c @@ -174,7 +174,7 @@ powerpmc250_calibrate_decr(void) static void powerpmc250_restart(char *cmd) { - __cli(); + local_irq_disable(); /* Hard reset */ writeb(0x11, 0xfe000332); while(1); @@ -183,7 +183,7 @@ powerpmc250_restart(char *cmd) static void powerpmc250_halt(void) { - __cli(); + local_irq_disable(); while (1); } diff --git a/arch/ppc/platforms/pplus_setup.c b/arch/ppc/platforms/pplus_setup.c index 74d2aac096bd..5af73b599e54 100644 --- a/arch/ppc/platforms/pplus_setup.c +++ b/arch/ppc/platforms/pplus_setup.c @@ -155,7 +155,7 @@ pplus_restart(char *cmd) { unsigned long i = 10000; - __cli(); + local_irq_disable(); /* set VIA IDE controller into native mode */ pplus_set_VIA_IDE_native(); @@ -176,7 +176,7 @@ static void pplus_halt(void) { unsigned long flags; - __cli(); + local_irq_disable(); /* set exception prefix high - to the prom */ save_flags( flags ); restore_flags( flags|MSR_IP ); diff --git a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c index 96db1accd38d..8fafd380b413 100644 --- a/arch/ppc/platforms/prep_setup.c +++ b/arch/ppc/platforms/prep_setup.c @@ -473,7 +473,7 @@ prep_calibrate_decr(void) if (request_irq(0, prep_calibrate_decr_handler, 0, "timer", NULL) != 0) panic("Could not allocate timer IRQ!"); - __sti(); + local_irq_enable(); /* wait for calibrate */ while ( calibrate_steps ) ; @@ -565,7 +565,7 @@ prep_restart(char *cmd) { unsigned long i = 10000; - __cli(); + local_irq_disable(); /* set exception prefix high - to the prom */ _nmask_and_or_msr(0, MSR_IP); @@ -583,7 +583,7 @@ static void __prep prep_halt(void) { unsigned long flags; - __cli(); + local_irq_disable(); /* set exception prefix high - to the prom */ save_flags( flags ); restore_flags( flags|MSR_IP ); @@ -650,7 +650,7 @@ prep_power_off(void) { if ( _prep_type == _PREP_IBM) { unsigned long flags; - __cli(); + local_irq_disable(); /* set exception prefix high - to the prom */ save_flags( flags ); restore_flags( flags|MSR_IP ); diff --git a/arch/ppc/platforms/prpmc750_setup.c b/arch/ppc/platforms/prpmc750_setup.c index 29199450c7fd..7b4daa9ff99c 100644 --- a/arch/ppc/platforms/prpmc750_setup.c +++ b/arch/ppc/platforms/prpmc750_setup.c @@ -184,7 +184,7 @@ prpmc750_calibrate_decr(void) static void prpmc750_restart(char *cmd) { - __cli(); + local_irq_disable(); writeb(PRPMC750_MODRST_MASK, PRPMC750_MODRST_REG); while(1); } @@ -192,7 +192,7 @@ prpmc750_restart(char *cmd) static void prpmc750_halt(void) { - __cli(); + local_irq_disable(); while (1); } diff --git a/arch/ppc/platforms/prpmc800_setup.c b/arch/ppc/platforms/prpmc800_setup.c index efeb8050f501..69874d0e7502 100644 --- a/arch/ppc/platforms/prpmc800_setup.c +++ b/arch/ppc/platforms/prpmc800_setup.c @@ -178,7 +178,7 @@ prpmc800_calibrate_decr(void) static void prpmc800_restart(char *cmd) { - __cli(); + local_irq_disable(); writeb(HARRIER_RSTOUT_MASK, HARRIER_MISC_CSR_REG); while(1); } @@ -186,7 +186,7 @@ prpmc800_restart(char *cmd) static void prpmc800_halt(void) { - __cli(); + local_irq_disable(); while (1); } diff --git a/arch/ppc/platforms/sandpoint_setup.c b/arch/ppc/platforms/sandpoint_setup.c index 2aaa391069ec..f22f5d3208c7 100644 --- a/arch/ppc/platforms/sandpoint_setup.c +++ b/arch/ppc/platforms/sandpoint_setup.c @@ -390,7 +390,7 @@ sandpoint_map_io(void) static void sandpoint_restart(char *cmd) { - __cli(); + local_irq_disable(); /* Set exception prefix high - to the firmware */ _nmask_and_or_msr(0, MSR_IP); @@ -404,7 +404,7 @@ sandpoint_restart(char *cmd) static void sandpoint_power_off(void) { - __cli(); + local_irq_disable(); for(;;); /* No way to shut power off with software */ /* NOTREACHED */ } diff --git a/arch/ppc/platforms/spruce_setup.c b/arch/ppc/platforms/spruce_setup.c index 693cc58c6ee6..4a8c03dc880f 100644 --- a/arch/ppc/platforms/spruce_setup.c +++ b/arch/ppc/platforms/spruce_setup.c @@ -158,7 +158,7 @@ spruce_setup_arch(void) static void spruce_restart(char *cmd) { - __cli(); + local_irq_disable(); /* SRR0 has system reset vector, SRR1 has default MSR value */ /* rfi restores MSR from SRR1 and sets the PC to the SRR0 value */ diff --git a/arch/ppc/platforms/zx4500_setup.c b/arch/ppc/platforms/zx4500_setup.c index 5748432e9dcd..523c40dba257 100644 --- a/arch/ppc/platforms/zx4500_setup.c +++ b/arch/ppc/platforms/zx4500_setup.c @@ -191,7 +191,7 @@ zx4500_init_IRQ(void) static void zx4500_restart(char *cmd) { - __cli(); + local_irq_disable(); out_8((volatile u_char *)ZX4500_CPLD_RESET, ZX4500_CPLD_RESET_XBUS); for (;;); @@ -203,7 +203,7 @@ zx4500_restart(char *cmd) static void zx4500_power_off(void) { - __cli(); + local_irq_disable(); for(;;); /* No way to shut power off with software */ /* NOTREACHED */ } diff --git a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c index 1c61b61fa2a8..04da06a73d09 100644 --- a/arch/ppc/xmon/xmon.c +++ b/arch/ppc/xmon/xmon.c @@ -243,11 +243,11 @@ void xmon_irq(int irq, void *d, struct pt_regs *regs) { unsigned long flags; - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); printf("Keyboard interrupt\n"); xmon(regs); - __restore_flags(flags); + local_irq_restore(flags); } int diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c index 0eb3cfe8aa4b..9ae8c0c5ae8e 100644 --- a/arch/ppc64/kernel/irq.c +++ b/arch/ppc64/kernel/irq.c @@ -382,7 +382,7 @@ handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action) int status = 0; if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); do { status |= action->flags; @@ -391,7 +391,7 @@ handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action) } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); } #ifdef CONFIG_SMP @@ -696,9 +696,9 @@ again: show("get_irqlock"); count = (~0 >> 1); } - __sti(); + local_irq_enable(); barrier(); - __cli(); + local_irq_disable(); } goto again; } @@ -722,10 +722,10 @@ void __global_cli(void) { unsigned long flags; - __save_flags(flags); + local_save_flags(flags); if (flags & (1UL << 15)) { int cpu = smp_processor_id(); - __cli(); + local_irq_disable(); if (!local_irq_count(cpu)) get_irqlock(cpu); } @@ -737,7 +737,7 @@ void __global_sti(void) if (!local_irq_count(cpu)) release_irqlock(cpu); - __sti(); + local_irq_enable(); } /* @@ -753,7 +753,7 @@ unsigned long __global_save_flags(void) int local_enabled; unsigned long flags; - __save_flags(flags); + local_save_flags(flags); local_enabled = (flags >> 15) & 1; /* default to local */ retval = 2 + local_enabled; @@ -778,10 +778,10 @@ void __global_restore_flags(unsigned long flags) __global_sti(); break; case 2: - __cli(); + local_irq_disable(); break; case 3: - __sti(); + local_irq_enable(); break; default: printk("global_restore_flags: %016lx caller %p\n", diff --git a/arch/ppc64/kernel/open_pic.c b/arch/ppc64/kernel/open_pic.c index 7d2d1630a154..7ffff7735086 100644 --- a/arch/ppc64/kernel/open_pic.c +++ b/arch/ppc64/kernel/open_pic.c @@ -775,7 +775,7 @@ static void openpic_end_ipi(unsigned int irq_nr) * SA_INTERRUPT flag and let them execute with all interrupts OFF. * This would have the side effect of either running cross-CPU * functions with interrupts off, or we can re-enable them explicitely - * with a __sti() in smp_call_function_interrupt(), since + * with a local_irq_enable() in smp_call_function_interrupt(), since * smp_call_function() is protected by a spinlock. * Or maybe we shouldn't set the IRQ_PER_CPU flag on cross-CPU * function calls IPI at all but that would make a special case. diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c index 916644cc27c7..91a2501cada2 100644 --- a/arch/ppc64/kernel/process.c +++ b/arch/ppc64/kernel/process.c @@ -99,9 +99,9 @@ _switch_to(struct task_struct *prev, struct task_struct *new) new_thread = &new->thread; old_thread = ¤t->thread; - __save_and_cli(flags); + local_irq_save(flags); _switch(old_thread, new_thread); - __restore_flags(flags); + local_irq_restore(flags); } void show_regs(struct pt_regs * regs) diff --git a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c index 2ff11a4437e3..9fbd6ed8ca0f 100644 --- a/arch/ppc64/kernel/smp.c +++ b/arch/ppc64/kernel/smp.c @@ -427,7 +427,7 @@ void smp_send_xmon_break(int cpu) static void stop_this_cpu(void *dummy) { - __cli(); + local_irq_disable(); while (1) ; } @@ -707,7 +707,7 @@ void __init smp_callin(void) while(!smp_commenced) { barrier(); } - __sti(); + local_irq_enable(); } /* intel needs this */ diff --git a/arch/ppc64/kernel/stab.c b/arch/ppc64/kernel/stab.c index 4818c6f191de..bad13d5f7ca7 100644 --- a/arch/ppc64/kernel/stab.c +++ b/arch/ppc64/kernel/stab.c @@ -371,7 +371,7 @@ void flush_stab(struct task_struct *tsk, struct mm_struct *mm) /* Force previous translations to complete. DRENG */ asm volatile("isync" : : : "memory"); - __save_and_cli(flags); + local_irq_save(flags); if (get_paca()->stab_cache_pointer != 0xff && !STAB_PRESSURE) { int i; unsigned char *segments = get_paca()->xSegments; @@ -417,7 +417,7 @@ void flush_stab(struct task_struct *tsk, struct mm_struct *mm) } get_paca()->stab_cache_pointer = 0; - __restore_flags(flags); + local_irq_restore(flags); } if (ppc64_stab_preload) diff --git a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c index 8a4fb5865e11..732efcec5905 100644 --- a/arch/ppc64/xmon/xmon.c +++ b/arch/ppc64/xmon/xmon.c @@ -440,11 +440,11 @@ void xmon_irq(int irq, void *d, struct pt_regs *regs) { unsigned long flags; - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); printf("Keyboard interrupt\n"); xmon(regs); - __restore_flags(flags); + local_irq_restore(flags); } int diff --git a/arch/s390/kernel/irq.c b/arch/s390/kernel/irq.c index 1333ddb62fb3..24c5655424bb 100644 --- a/arch/s390/kernel/irq.c +++ b/arch/s390/kernel/irq.c @@ -161,9 +161,9 @@ static inline void wait_on_irq(int cpu) show("wait_on_irq"); count = ~0; } - __sti(); + local_irq_enable(); SYNC_OTHER_CORES(cpu); - __cli(); + local_irq_disable(); check_smp_invalidate(cpu); if (atomic_read(&global_irq_count)) continue; @@ -249,10 +249,10 @@ void __global_cli(void) { unsigned long flags; - __save_flags(flags); + local_save_flags(flags); if (flags & (1 << EFLAGS_I_SHIFT)) { int cpu = smp_processor_id(); - __cli(); + local_irq_disable(); if (!in_irq()) get_irqlock(cpu); } @@ -263,7 +263,7 @@ void __global_sti(void) if (!in_irq()) release_irqlock(smp_processor_id()); - __sti(); + local_irq_enable(); } /* @@ -279,7 +279,7 @@ unsigned long __global_save_flags(void) int local_enabled; unsigned long flags; - __save_flags(flags); + local_save_flags(flags); local_enabled = (flags >> EFLAGS_I_SHIFT) & 1; /* default to local */ retval = 2 + local_enabled; @@ -305,10 +305,10 @@ void __global_restore_flags(unsigned long flags) __global_sti(); break; case 2: - __cli(); + local_irq_disable(); break; case 3: - __sti(); + local_irq_enable(); break; default: printk("global_restore_flags: %08lx (%08lx)\n", diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 42720922019a..ca87c8ad85db 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -86,7 +86,7 @@ void __init cpu_init (void) if (test_and_set_bit(nr,&cpu_initialized)) { printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr); - for (;;) __sti(); + for (;;) local_irq_enable(); } cpus_initialized++; diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 8f28efda890c..3fa5bb6a779b 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -280,7 +280,7 @@ static void inline do_trap(long interruption_code, int signr, char *str, * now safely switch on interrupts. */ if (regs->psw.mask & PSW_PROBLEM_STATE) - __sti(); + local_irq_enable(); if (regs->psw.mask & PSW_PROBLEM_STATE) { struct task_struct *tsk = current; @@ -416,7 +416,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) * now safely switch on interrupts. */ if (regs->psw.mask & PSW_PROBLEM_STATE) - __sti(); + local_irq_enable(); if (regs->psw.mask & PSW_PROBLEM_STATE) get_user(*((__u16 *) opcode), location); @@ -477,7 +477,7 @@ specification_exception(struct pt_regs * regs, long interruption_code) * now safely switch on interrupts. */ if (regs->psw.mask & PSW_PROBLEM_STATE) - __sti(); + local_irq_enable(); if (regs->psw.mask & PSW_PROBLEM_STATE) { get_user(*((__u16 *) opcode), location); @@ -540,7 +540,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) * now safely switch on interrupts. */ if (regs->psw.mask & PSW_PROBLEM_STATE) - __sti(); + local_irq_enable(); if (MACHINE_HAS_IEEE) __asm__ volatile ("stfpc %0\n\t" diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 19234d87476b..da58d8386533 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c @@ -199,7 +199,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) * task's user address space, so we can switch on the * interrupts again and then search the VMAs */ - __sti(); + local_irq_enable(); down_read(&mm->mmap_sem); @@ -528,7 +528,7 @@ pfault_interrupt(struct pt_regs *regs, __u16 error_code) * now safely switch on interrupts. */ if (regs->psw.mask & PSW_PROBLEM_STATE) - __sti(); + local_irq_enable(); if (subcode & 0x0080) { /* signal bit is set -> a page has been swapped in by VM */ diff --git a/arch/s390x/kernel/irq.c b/arch/s390x/kernel/irq.c index 751afdc2f344..2b9de1e708e2 100644 --- a/arch/s390x/kernel/irq.c +++ b/arch/s390x/kernel/irq.c @@ -162,9 +162,9 @@ static inline void wait_on_irq(int cpu) show("wait_on_irq"); count = ~0; } - __sti(); + local_irq_enable(); SYNC_OTHER_CORES(cpu); - __cli(); + local_irq_disable(); check_smp_invalidate(cpu); if (atomic_read(&global_irq_count)) continue; @@ -250,10 +250,10 @@ void __global_cli(void) { unsigned long flags; - __save_flags(flags); + local_save_flags(flags); if (flags & (1UL << EFLAGS_I_SHIFT)) { int cpu = smp_processor_id(); - __cli(); + local_irq_disable(); if (!in_irq()) get_irqlock(cpu); } @@ -264,7 +264,7 @@ void __global_sti(void) if (!in_irq()) release_irqlock(smp_processor_id()); - __sti(); + local_irq_enable(); } /* @@ -280,7 +280,7 @@ unsigned long __global_save_flags(void) int local_enabled; unsigned long flags; - __save_flags(flags); + local_save_flags(flags); local_enabled = (flags >> EFLAGS_I_SHIFT) & 1; /* default to local */ retval = 2 + local_enabled; @@ -306,10 +306,10 @@ void __global_restore_flags(unsigned long flags) __global_sti(); break; case 2: - __cli(); + local_irq_disable(); break; case 3: - __sti(); + local_irq_enable(); break; default: printk("global_restore_flags: %08lx (%08lx)\n", diff --git a/arch/s390x/kernel/setup.c b/arch/s390x/kernel/setup.c index 231fe54ab59b..94e67bdadd80 100644 --- a/arch/s390x/kernel/setup.c +++ b/arch/s390x/kernel/setup.c @@ -86,7 +86,7 @@ void __init cpu_init (void) if (test_and_set_bit(nr,&cpu_initialized)) { printk("CPU#%d ALREADY INITIALIZED!!!!!!!!!\n", nr); - for (;;) __sti(); + for (;;) local_irq_enable(); } cpus_initialized++; diff --git a/arch/s390x/kernel/traps.c b/arch/s390x/kernel/traps.c index 0f00eac30601..6579705d07c4 100644 --- a/arch/s390x/kernel/traps.c +++ b/arch/s390x/kernel/traps.c @@ -282,7 +282,7 @@ static void inline do_trap(long interruption_code, int signr, char *str, * now safely switch on interrupts. */ if (regs->psw.mask & PSW_PROBLEM_STATE) - __sti(); + local_irq_enable(); if (regs->psw.mask & PSW_PROBLEM_STATE) { struct task_struct *tsk = current; @@ -419,7 +419,7 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code) * now safely switch on interrupts. */ if (regs->psw.mask & PSW_PROBLEM_STATE) - __sti(); + local_irq_enable(); /* WARNING don't change this check back to */ /* int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); */ @@ -452,7 +452,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code) * now safely switch on interrupts. */ if (regs->psw.mask & PSW_PROBLEM_STATE) - __sti(); + local_irq_enable(); __asm__ volatile ("stfpc %0\n\t" : "=m" (current->thread.fp_regs.fpc)); diff --git a/arch/s390x/mm/fault.c b/arch/s390x/mm/fault.c index 5e1b70d89908..a37064d1e0ba 100644 --- a/arch/s390x/mm/fault.c +++ b/arch/s390x/mm/fault.c @@ -199,7 +199,7 @@ extern inline void do_exception(struct pt_regs *regs, unsigned long error_code) * task's user address space, so we can switch on the * interrupts again and then search the VMAs */ - __sti(); + local_irq_enable(); down_read(&mm->mmap_sem); @@ -440,7 +440,7 @@ pfault_interrupt(struct pt_regs *regs, __u16 error_code) * now safely switch on interrupts. */ if (regs->psw.mask & PSW_PROBLEM_STATE) - __sti(); + local_irq_enable(); if (subcode & 0x0080) { /* signal bit is set -> a page has been swapped in by VM */ diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 8a96a8c34ed1..32e86b0bab0e 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -130,7 +130,7 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * status = 1; /* Force the "do bottom halves" bit */ if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); do { status |= action->flags; @@ -139,7 +139,7 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); irq_exit(cpu, irq); diff --git a/arch/sh/kernel/process.c b/arch/sh/kernel/process.c index 4c897ef284d2..9dbd03c355b7 100644 --- a/arch/sh/kernel/process.c +++ b/arch/sh/kernel/process.c @@ -46,13 +46,13 @@ void cpu_idle(void *unused) if (need_resched()) break; } else { - __cli(); + local_irq_disable(); while (!need_resched()) { - __sti(); + local_irq_enable(); asm volatile("sleep" : : : "memory"); - __cli(); + local_irq_disable(); } - __sti(); + local_irq_enable(); } schedule(); check_pgt_cache(); diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index 0235faa1a96c..e8208e461b23 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -231,7 +231,7 @@ static void show(char * str) /* - * We have to allow irqs to arrive between __sti and __cli + * We have to allow irqs to arrive between local_irq_enable and local_irq_disable */ #define SYNC_OTHER_CORES(x) barrier() @@ -276,9 +276,9 @@ again: show("get_irqlock"); count = (~0 >> 1); } - __sti(); + local_irq_enable(); SYNC_OTHER_CORES(cpu); - __cli(); + local_irq_disable(); } goto again; } @@ -302,11 +302,11 @@ void __global_cli(void) { unsigned long flags; - __save_flags(flags); + local_save_flags(flags); if ((flags & PSR_PIL) != PSR_PIL) { int cpu = smp_processor_id(); - __cli(); + local_irq_disable(); if (!local_irq_count(cpu)) get_irqlock(cpu); } @@ -318,7 +318,7 @@ void __global_sti(void) if (!local_irq_count(cpu)) release_irqlock(cpu); - __sti(); + local_irq_enable(); } /* @@ -333,7 +333,7 @@ unsigned long __global_save_flags(void) unsigned long flags, retval; unsigned long local_enabled = 0; - __save_flags(flags); + local_save_flags(flags); if ((flags & PSR_PIL) != PSR_PIL) local_enabled = 1; @@ -361,10 +361,10 @@ void __global_restore_flags(unsigned long flags) __global_sti(); break; case 2: - __cli(); + local_irq_disable(); break; case 3: - __sti(); + local_irq_enable(); break; default: { diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 0bc967629b66..1a81405fb38e 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -780,7 +780,7 @@ void __init pci_time_init(void) prom_printf("time_init: unable to attach IRQ%d\n", timer_irq); prom_halt(); } - __sti(); + local_irq_enable(); } static __inline__ unsigned long do_gettimeoffset(void) diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c index 3e329fa532ef..cb994b3a2520 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -253,7 +253,7 @@ void smp_reschedule_irq(void) /* Stopping processors. */ void smp_stop_cpu_irq(void) { - __sti(); + local_irq_enable(); while(1) barrier(); } diff --git a/arch/sparc/kernel/sun4d_irq.c b/arch/sparc/kernel/sun4d_irq.c index c53e219dfc9f..9c241d1603b4 100644 --- a/arch/sparc/kernel/sun4d_irq.c +++ b/arch/sparc/kernel/sun4d_irq.c @@ -488,14 +488,14 @@ static void __init sun4d_init_timers(void (*counter_fn)(int, void *, struct pt_r * has copied the firmwares level 14 vector into boot cpu's * trap table, we must fix this now or we get squashed. */ - __save_and_cli(flags); + local_irq_save(flags); patchme_maybe_smp_msg[0] = 0x01000000; /* NOP out the branch */ trap_table->inst_one = lvl14_save[0]; trap_table->inst_two = lvl14_save[1]; trap_table->inst_three = lvl14_save[2]; trap_table->inst_four = lvl14_save[3]; local_flush_cache_all(); - __restore_flags(flags); + local_irq_restore(flags); } #endif } @@ -539,7 +539,7 @@ static char *sun4d_irq_itoa(unsigned int irq) void __init sun4d_init_IRQ(void) { - __cli(); + local_irq_disable(); BTFIXUPSET_CALL(enable_irq, sun4d_enable_irq, BTFIXUPCALL_NORM); BTFIXUPSET_CALL(disable_irq, sun4d_disable_irq, BTFIXUPCALL_NORM); diff --git a/arch/sparc/kernel/sun4d_smp.c b/arch/sparc/kernel/sun4d_smp.c index 234bd350a231..6c7022e6afee 100644 --- a/arch/sparc/kernel/sun4d_smp.c +++ b/arch/sparc/kernel/sun4d_smp.c @@ -144,7 +144,7 @@ void __init smp4d_callin(void) local_flush_cache_all(); local_flush_tlb_all(); - __sti(); /* We don't allow PIL 14 yet */ + local_irq_enable(); /* We don't allow PIL 14 yet */ while(!smp_commenced) barrier(); @@ -182,7 +182,7 @@ void __init smp4d_boot_cpus(void) if (boot_cpu_id) current_set[0] = NULL; - __sti(); + local_irq_enable(); cpu_present_map = 0; for(i=0; i < linux_num_cpus; i++) cpu_present_map |= (1<<linux_cpus[i].mid); diff --git a/arch/sparc/kernel/sun4m_irq.c b/arch/sparc/kernel/sun4m_irq.c index 41ef36a5883b..0e2ee8545a9c 100644 --- a/arch/sparc/kernel/sun4m_irq.c +++ b/arch/sparc/kernel/sun4m_irq.c @@ -297,13 +297,13 @@ static void __init sun4m_init_timers(void (*counter_fn)(int, void *, struct pt_r * has copied the firmwares level 14 vector into boot cpu's * trap table, we must fix this now or we get squashed. */ - __save_and_cli(flags); + local_irq_save(flags); trap_table->inst_one = lvl14_save[0]; trap_table->inst_two = lvl14_save[1]; trap_table->inst_three = lvl14_save[2]; trap_table->inst_four = lvl14_save[3]; local_flush_cache_all(); - __restore_flags(flags); + local_irq_restore(flags); } #endif } @@ -315,7 +315,7 @@ void __init sun4m_init_IRQ(void) int num_regs; struct resource r; - __cli(); + local_irq_disable(); if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 || (ie_node = prom_getchild (ie_node)) == 0 || (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) { diff --git a/arch/sparc/kernel/sun4m_smp.c b/arch/sparc/kernel/sun4m_smp.c index 083760565638..d31f054abc15 100644 --- a/arch/sparc/kernel/sun4m_smp.c +++ b/arch/sparc/kernel/sun4m_smp.c @@ -127,7 +127,7 @@ void __init smp4m_callin(void) local_flush_cache_all(); local_flush_tlb_all(); - __sti(); + local_irq_enable(); } extern int cpu_idle(void *unused); @@ -153,7 +153,7 @@ void __init smp4m_boot_cpus(void) printk("Entering SMP Mode...\n"); - __sti(); + local_irq_enable(); cpu_present_map = 0; for(i=0; i < linux_num_cpus; i++) diff --git a/arch/sparc/kernel/time.c b/arch/sparc/kernel/time.c index 90d3e8528358..1cb4ed19e5e7 100644 --- a/arch/sparc/kernel/time.c +++ b/arch/sparc/kernel/time.c @@ -437,7 +437,7 @@ void __init sbus_time_init(void) #endif /* Now that OBP ticker has been silenced, it is safe to enable IRQ. */ - __sti(); + local_irq_enable(); } void __init time_init(void) diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index 020b25a19bde..719ad55a2bde 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -657,7 +657,7 @@ static void cypress_flush_cache_mm(struct mm_struct *mm) FLUSH_BEGIN(mm) flush_user_windows(); - __save_and_cli(flags); + local_irq_save(flags); octx = srmmu_get_context(); srmmu_set_context(mm->context); a = 0x20; b = 0x40; c = 0x60; @@ -681,7 +681,7 @@ static void cypress_flush_cache_mm(struct mm_struct *mm) "r" (e), "r" (f), "r" (g)); } while(faddr); srmmu_set_context(octx); - __restore_flags(flags); + local_irq_restore(flags); FLUSH_END } @@ -694,7 +694,7 @@ static void cypress_flush_cache_range(struct vm_area_struct *vma, unsigned long FLUSH_BEGIN(mm) flush_user_windows(); - __save_and_cli(flags); + local_irq_save(flags); octx = srmmu_get_context(); srmmu_set_context(mm->context); a = 0x20; b = 0x40; c = 0x60; @@ -723,7 +723,7 @@ static void cypress_flush_cache_range(struct vm_area_struct *vma, unsigned long start += SRMMU_PMD_SIZE; } srmmu_set_context(octx); - __restore_flags(flags); + local_irq_restore(flags); FLUSH_END } @@ -736,7 +736,7 @@ static void cypress_flush_cache_page(struct vm_area_struct *vma, unsigned long p FLUSH_BEGIN(mm) flush_user_windows(); - __save_and_cli(flags); + local_irq_save(flags); octx = srmmu_get_context(); srmmu_set_context(mm->context); a = 0x20; b = 0x40; c = 0x60; @@ -762,7 +762,7 @@ static void cypress_flush_cache_page(struct vm_area_struct *vma, unsigned long p "r" (e), "r" (f), "r" (g)); } while(line != page); srmmu_set_context(octx); - __restore_flags(flags); + local_irq_restore(flags); FLUSH_END } diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c index cd838b8f8a1e..453e86390437 100644 --- a/arch/sparc64/kernel/irq.c +++ b/arch/sparc64/kernel/irq.c @@ -634,9 +634,9 @@ again: show("get_irqlock"); count = (~0 >> 1); } - __sti(); + local_irq_enable(); SYNC_OTHER_ULTRAS(cpu); - __cli(); + local_irq_disable(); } goto again; } @@ -648,10 +648,10 @@ void __global_cli(void) { unsigned long flags; - __save_flags(flags); + local_save_flags(flags); if(flags == 0) { int cpu = smp_processor_id(); - __cli(); + local_irq_disable(); if (! local_irq_count(cpu)) get_irqlock(cpu); } @@ -663,14 +663,14 @@ void __global_sti(void) if (! local_irq_count(cpu)) release_irqlock(cpu); - __sti(); + local_irq_enable(); } unsigned long __global_save_flags(void) { unsigned long flags, local_enabled, retval; - __save_flags(flags); + local_save_flags(flags); local_enabled = ((flags == 0) ? 1 : 0); retval = 2 + local_enabled; if (! local_irq_count(smp_processor_id())) { @@ -692,10 +692,10 @@ void __global_restore_flags(unsigned long flags) __global_sti(); break; case 2: - __cli(); + local_irq_disable(); break; case 3: - __sti(); + local_irq_enable(); break; default: { diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c index 59efc5033e12..79c762389aee 100644 --- a/arch/sparc64/kernel/smp.c +++ b/arch/sparc64/kernel/smp.c @@ -199,7 +199,7 @@ void __init smp_callin(void) smp_setup_percpu_timer(); - __sti(); + local_irq_enable(); calibrate_delay(); smp_store_cpu_info(cpuid); @@ -243,7 +243,7 @@ void __init smp_boot_cpus(void) int cpucount = 0, i; printk("Entering UltraSMPenguin Mode...\n"); - __sti(); + local_irq_enable(); smp_store_cpu_info(boot_cpu_id); if (linux_num_cpus == 1) { @@ -1222,7 +1222,7 @@ static void __init smp_tune_scheduling(void) __get_free_pages(GFP_KERNEL, order = get_order(ecache_size)); if (flush_base != 0UL) { - __save_and_cli(flags); + local_irq_save(flags); /* Scan twice the size once just to get the TLB entries * loaded and make sure the second scan measures pure misses. @@ -1271,7 +1271,7 @@ static void __init smp_tune_scheduling(void) : "g1", "g2", "g3", "g5"); } - __restore_flags(flags); + local_irq_restore(flags); raw = (tick2 - tick1); diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c index 447f56926b16..bfeb62e5bac3 100644 --- a/arch/sparc64/kernel/time.c +++ b/arch/sparc64/kernel/time.c @@ -432,7 +432,7 @@ void __init clock_probe(void) return; } - __save_and_cli(flags); + local_irq_save(flags); cbus = central_bus; if (cbus != NULL) @@ -610,7 +610,7 @@ try_isa_clock: set_system_time(); - __restore_flags(flags); + local_irq_restore(flags); } extern void init_timers(void (*func)(int, void *, struct pt_regs *), diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c index b77be61d1c26..b0e4077ea60f 100644 --- a/arch/sparc64/mm/init.c +++ b/arch/sparc64/mm/init.c @@ -1411,7 +1411,7 @@ void __init paging_init(void) */ pt = phys_base | _PAGE_VALID | _PAGE_SZ4MB; pt |= _PAGE_CP | _PAGE_CV | _PAGE_P | _PAGE_L | _PAGE_W; - __save_and_cli(flags); + local_irq_save(flags); if (tlb_type == spitfire) { __asm__ __volatile__( " stxa %1, [%0] %3\n" @@ -1469,7 +1469,7 @@ void __init paging_init(void) : "memory"); } } - __restore_flags(flags); + local_irq_restore(flags); /* Now set kernel pgd to upper alias so physical page computations * work. diff --git a/arch/sparc64/prom/misc.c b/arch/sparc64/prom/misc.c index 5605a0674b7c..e90dde2f32ce 100644 --- a/arch/sparc64/prom/misc.c +++ b/arch/sparc64/prom/misc.c @@ -52,7 +52,7 @@ prom_cmdline(void) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); #ifdef CONFIG_SUN_CONSOLE if(!serial_console && prom_palette) @@ -75,7 +75,7 @@ prom_cmdline(void) prom_palette (0); #endif - __restore_flags(flags); + local_irq_restore(flags); } #ifdef CONFIG_SMP diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index 6602a1424936..d42316c4cb81 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c @@ -474,13 +474,13 @@ static void apic_pm_suspend(void *data) apic_pm_state.apic_tmict = apic_read(APIC_TMICT); apic_pm_state.apic_tdcr = apic_read(APIC_TDCR); apic_pm_state.apic_thmr = apic_read(APIC_LVTTHMR); - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); disable_local_APIC(); rdmsr(MSR_IA32_APICBASE, l, h); l &= ~MSR_IA32_APICBASE_ENABLE; wrmsr(MSR_IA32_APICBASE, l, h); - __restore_flags(flags); + local_irq_restore(flags); } static void apic_pm_resume(void *data) @@ -488,8 +488,8 @@ static void apic_pm_resume(void *data) unsigned int l, h; unsigned long flags; - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); rdmsr(MSR_IA32_APICBASE, l, h); l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; @@ -512,7 +512,7 @@ static void apic_pm_resume(void *data) apic_write(APIC_LVTERR, apic_pm_state.apic_lvterr); apic_write(APIC_ESR, 0); apic_read(APIC_ESR); - __restore_flags(flags); + local_irq_restore(flags); if (apic_pm_state.perfctr_pmdev) pm_send(apic_pm_state.perfctr_pmdev, PM_RESUME, data); } @@ -785,8 +785,8 @@ void setup_APIC_timer(void * data) unsigned long flags; int delta; - __save_flags(flags); - __sti(); + local_save_flags(flags); + local_irq_enable(); /* * ok, Intel has some smart code in their APIC that knows * if a CPU was in 'hlt' lowpower mode, and this increases @@ -825,7 +825,7 @@ void setup_APIC_timer(void * data) printk("CPU%d<T0:%u,T1:%u,D:%d,S:%u,C:%u>\n", smp_processor_id(), t0, t1, delta, slice, clocks); - __restore_flags(flags); + local_irq_restore(flags); } /* @@ -916,7 +916,7 @@ void __init setup_APIC_clocks (void) printk("Using local APIC timer interrupts.\n"); using_apic_timer = 1; - __cli(); + local_irq_disable(); calibration_result = calibrate_APIC_clock(); /* @@ -924,7 +924,7 @@ void __init setup_APIC_clocks (void) */ setup_APIC_timer((void *)(u64)calibration_result); - __sti(); + local_irq_enable(); /* and update all other cpus */ smp_call_function(setup_APIC_timer, (void *)(u64)calibration_result, 1, 1); diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c index 286d31c97b9e..7e4d8ff2544e 100644 --- a/arch/x86_64/kernel/irq.c +++ b/arch/x86_64/kernel/irq.c @@ -254,7 +254,7 @@ static void show(char * str) # define SYNC_OTHER_CORES(x) udelay(x+1) #else /* - * We have to allow irqs to arrive between __sti and __cli + * We have to allow irqs to arrive between local_irq_enable and local_irq_disable */ # define SYNC_OTHER_CORES(x) __asm__ __volatile__ ("nop") #endif @@ -282,9 +282,9 @@ static inline void wait_on_irq(int cpu) show("wait_on_irq"); count = ~0; } - __sti(); + local_irq_enable(); SYNC_OTHER_CORES(cpu); - __cli(); + local_irq_disable(); if (irqs_running()) continue; if (global_irq_lock) @@ -356,10 +356,10 @@ void __global_cli(void) { unsigned long flags; - __save_flags(flags); + local_save_flags(flags); if (flags & (1 << EFLAGS_IF_SHIFT)) { int cpu = smp_processor_id(); - __cli(); + local_irq_disable(); if (!local_irq_count(cpu)) get_irqlock(cpu); } @@ -371,7 +371,7 @@ void __global_sti(void) if (!local_irq_count(cpu)) release_irqlock(cpu); - __sti(); + local_irq_enable(); } /* @@ -388,7 +388,7 @@ unsigned long __global_save_flags(void) unsigned long flags; int cpu = smp_processor_id(); - __save_flags(flags); + local_save_flags(flags); local_enabled = (flags >> EFLAGS_IF_SHIFT) & 1; /* default to local */ retval = 2 + local_enabled; @@ -413,10 +413,10 @@ void __global_restore_flags(unsigned long flags) __global_sti(); break; case 2: - __cli(); + local_irq_disable(); break; case 3: - __sti(); + local_irq_enable(); break; default: printk("global_restore_flags: %08lx (%08lx)\n", @@ -442,7 +442,7 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * status = 1; /* Force the "do bottom halves" bit */ if (!(action->flags & SA_INTERRUPT)) - __sti(); + local_irq_enable(); do { status |= action->flags; @@ -451,7 +451,7 @@ int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); - __cli(); + local_irq_disable(); irq_exit(0, irq); diff --git a/arch/x86_64/kernel/ldt.c b/arch/x86_64/kernel/ldt.c index d8767f3dbe56..15593c65deec 100644 --- a/arch/x86_64/kernel/ldt.c +++ b/arch/x86_64/kernel/ldt.c @@ -132,7 +132,8 @@ int init_new_context(struct task_struct *tsk, struct mm_struct *mm) void release_segments(struct mm_struct *mm) { if (mm->context.size) { - clear_LDT(); + if (mm == current->active_mm) + clear_LDT(); if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE) vfree(mm->context.ldt); else diff --git a/arch/x86_64/kernel/mtrr.c b/arch/x86_64/kernel/mtrr.c index b0c43563a30a..2cfede2696f2 100644 --- a/arch/x86_64/kernel/mtrr.c +++ b/arch/x86_64/kernel/mtrr.c @@ -117,8 +117,8 @@ static void set_mtrr_prepare (struct set_mtrr_context *ctxt) u64 cr0; /* Disable interrupts locally */ - __save_flags(ctxt->flags); - __cli(); + local_save_flags(ctxt->flags); + local_irq_disable(); /* Save value of CR4 and clear Page Global Enable (bit 7) */ if (cpu_has_pge) { @@ -156,7 +156,7 @@ static void set_mtrr_done (struct set_mtrr_context *ctxt) write_cr4 (ctxt->cr4val); /* Re-enable interrupts locally (if enabled previously) */ - __restore_flags(ctxt->flags); + local_irq_restore(ctxt->flags); } diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index f00fff0638de..5acb19702564 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -89,11 +89,11 @@ void enable_hlt(void) void default_idle(void) { if (!hlt_counter) { - __cli(); + local_irq_disable(); if (!need_resched()) safe_halt(); else - __sti(); + local_irq_enable(); } } @@ -106,7 +106,7 @@ static void poll_idle (void) { int oldval; - __sti(); + local_irq_enable(); /* * Deal with another CPU just having chosen a thread to diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c index f0d99edfec0e..2078148fe8ce 100644 --- a/arch/x86_64/kernel/smp.c +++ b/arch/x86_64/kernel/smp.c @@ -97,8 +97,8 @@ static inline void send_IPI_mask(int mask, int vector) unsigned long cfg; unsigned long flags; - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); /* * Wait for idle. @@ -120,7 +120,7 @@ static inline void send_IPI_mask(int mask, int vector) * Send the IPI. The write to APIC_ICR fires this off. */ apic_write_around(APIC_ICR, cfg); - __restore_flags(flags); + local_irq_restore(flags); } /* @@ -438,7 +438,7 @@ static void stop_this_cpu (void * dummy) * Remove this CPU: */ clear_bit(smp_processor_id(), &cpu_online_map); - __cli(); + local_irq_disable(); disable_local_APIC(); for(;;) __asm__("hlt"); for (;;); @@ -453,9 +453,9 @@ void smp_send_stop(void) smp_call_function(stop_this_cpu, NULL, 1, 0); smp_num_cpus = 1; - __cli(); + local_irq_disable(); disable_local_APIC(); - __sti(); + local_irq_enable(); } /* diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index fe7a298db43c..32df41330f69 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -344,7 +344,7 @@ void die(const char * str, struct pt_regs * regs, long err) printk("%s: %04lx\n", str, err & 0xffff); cpu = smp_processor_id(); /* racy, but better than risking deadlock. */ - __cli(); + local_irq_disable(); if (!spin_trylock(&die_lock)) { if (cpu == die_owner) /* nested oops. should stop eventually */; diff --git a/arch/x86_64/pci/direct.c b/arch/x86_64/pci/direct.c index aff679e20aaa..ea4f3c51f377 100644 --- a/arch/x86_64/pci/direct.c +++ b/arch/x86_64/pci/direct.c @@ -306,7 +306,7 @@ static struct pci_ops * __devinit pci_check_direct(void) unsigned int tmp; unsigned long flags; - __save_flags(flags); __cli(); + local_save_flags(flags); local_irq_disable(); /* * Check if configuration type 1 works. @@ -318,7 +318,7 @@ static struct pci_ops * __devinit pci_check_direct(void) if (inl (0xCF8) == 0x80000000 && pci_sanity_check(&pci_direct_conf1)) { outl (tmp, 0xCF8); - __restore_flags(flags); + local_irq_restore(flags); printk(KERN_INFO "PCI: Using configuration type 1\n"); if (!request_region(0xCF8, 8, "PCI conf1")) return NULL; @@ -336,7 +336,7 @@ static struct pci_ops * __devinit pci_check_direct(void) outb (0x00, 0xCFA); if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00 && pci_sanity_check(&pci_direct_conf2)) { - __restore_flags(flags); + local_irq_restore(flags); printk(KERN_INFO "PCI: Using configuration type 2\n"); if (!request_region(0xCF8, 4, "PCI conf2")) return NULL; @@ -344,7 +344,7 @@ static struct pci_ops * __devinit pci_check_direct(void) } } - __restore_flags(flags); + local_irq_restore(flags); return NULL; } diff --git a/drivers/Makefile b/drivers/Makefile index e858842760d3..3348f9765ba6 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_PCI) += pci/ obj-$(CONFIG_ACPI) += acpi/ obj-$(CONFIG_PARPORT) += parport/ -obj-y += base/ char/ block/ misc/ net/ media/ +obj-y += base/ serial/ char/ block/ misc/ net/ media/ obj-$(CONFIG_NUBUS) += nubus/ obj-$(CONFIG_ATM) += atm/ obj-$(CONFIG_IDE) += ide/ diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c index fd41fe9d58b7..309fc7c4d47d 100644 --- a/drivers/acorn/block/mfmhd.c +++ b/drivers/acorn/block/mfmhd.c @@ -184,8 +184,6 @@ struct mfm_info { #define NEED_1_RECAL -2 #define NEED_2_RECAL -3 int cylinder; - unsigned int access_count; - unsigned int busy; struct { char recal; char report; @@ -197,7 +195,6 @@ struct mfm_info { static struct hd_struct mfm[MFM_MAXDRIVES << 6]; static int mfm_sizes[MFM_MAXDRIVES << 6]; -static DECLARE_WAIT_QUEUE_HEAD(mfm_wait_open); /* Stuff from the assembly routines */ extern unsigned int hdc63463_baseaddress; /* Controller base address */ @@ -1195,22 +1192,11 @@ static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long a return -EFAULT; return 0; - case BLKSECTGET: - return put_user(max_sectors[major][minor], (long *) arg); - case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; return mfm_reread_partitions(dev); - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKFLSBUF: - case BLKROSET: - case BLKROGET: - case BLKPG: - return blk_ioctl(inode->i_bdev, cmd, arg); - default: return -EINVAL; } @@ -1219,24 +1205,8 @@ static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long a static int mfm_open(struct inode *inode, struct file *file) { int dev = DEVICE_NR(minor(inode->i_rdev)); - if (dev >= mfm_drives) return -ENODEV; - - while (mfm_info[dev].busy) - sleep_on (&mfm_wait_open); - - mfm_info[dev].access_count++; - return 0; -} - -/* - * Releasing a block device means we sync() it, so that it can safely - * be forgotten about... - */ -static int mfm_release(struct inode *inode, struct file *file) -{ - mfm_info[DEVICE_NR(minor(inode->i_rdev))].access_count--; return 0; } @@ -1254,10 +1224,11 @@ void mfm_setup(char *str, int *ints) * since if there are any non-ADFS partitions on the disk, this won't work! * Hence, I want to get rid of this... */ -void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads, - unsigned long discsize, unsigned int secsize) +void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack, + unsigned char heads, unsigned int secsize) { - int drive = minor(dev) >> 6; + int drive = MINOR(bdev->bd_dev) >> 6; + unsigned long disksize = bdev->bd_inode->i_size; if (mfm_info[drive].cylinders == 1) { mfm_info[drive].sectors = secsptrack; @@ -1265,7 +1236,7 @@ void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads, mfm_info[drive].cylinders = discsize / (secsptrack * heads * secsize); if ((heads < 1) || (mfm_info[drive].cylinders > 1024)) { - printk("mfm%c: Insane disc shape! Setting to 512/4/32\n",'a' + (dev >> 6)); + printk("mfm%c: Insane disc shape! Setting to 512/4/32\n",'a' + drive); /* These values are fairly arbitary, but are there so that if your * lucky you can pick apart your disc to find out what is going on - @@ -1295,7 +1266,6 @@ static struct block_device_operations mfm_fops = { owner: THIS_MODULE, open: mfm_open, - release: mfm_release, ioctl: mfm_ioctl, }; @@ -1424,38 +1394,19 @@ int mfm_init (void) /* * This routine is called to flush all partitions and partition tables * for a changed MFM disk, and then re-read the new partition table. - * If we are revalidating due to an ioctl, we have USAGE == 1. */ static int mfm_reread_partitions(kdev_t dev) { - unsigned int start, i, maxp, target = DEVICE_NR(minor(dev)); - unsigned long flags; - - local_irq_save(flags); - if (mfm_info[target].busy || mfm_info[target].access_count > 1) { - local_irq_restore (flags); - return -EBUSY; - } - mfm_info[target].busy = 1; - local_irq_restore (flags); - - maxp = 1 << mfm_gendisk.minor_shift; - start = target << mfm_gendisk.minor_shift; - - for (i = maxp - 1; i >= 0; i--) { - int minor = start + i; - invalidate_device (mk_kdev(MAJOR_NR, minor), 1); - mfm_gendisk.part[minor].start_sect = 0; - mfm_gendisk.part[minor].nr_sects = 0; - } - + unsigned int unit = DEVICE_NR(minor(dev)); + kdev_t device = mk_kdev(MAJOR_NR, unit << mfm_gendisk.minor_shift); + int err = dev_lock_part(device); + if (err) + return err; + wipe_partitions(device); /* Divide by 2, since sectors are 2 times smaller than usual ;-) */ - - grok_partitions(&mfm_gendisk, target, 1<<6, mfm_info[target].heads * - mfm_info[target].cylinders * mfm_info[target].sectors / 2); - - mfm_info[target].busy = 0; - wake_up (&mfm_wait_open); + grok_partitions(device, mfm_info[unit].heads * + mfm_info[unit].cylinders * mfm_info[unit].sectors / 2); + dev_unlock_part(device); return 0; } diff --git a/drivers/acpi/processor.c b/drivers/acpi/processor.c index 3d5fb04358af..028ee228dcb0 100644 --- a/drivers/acpi/processor.c +++ b/drivers/acpi/processor.c @@ -416,7 +416,7 @@ acpi_processor_idle (void) * Interrupts must be disabled during bus mastering calculations and * for C2/C3 transitions. */ - __cli(); + local_irq_disable(); cx = &(pr->power.states[pr->power.state]); @@ -461,7 +461,7 @@ acpi_processor_idle (void) * issues (e.g. floppy DMA transfer overrun/underrun). */ if (pr->power.bm_activity & cx->demotion.threshold.bm) { - __sti(); + local_irq_enable(); next_state = cx->demotion.state; goto end; } @@ -497,7 +497,7 @@ acpi_processor_idle (void) /* Get end time (ticks) */ t2 = inl(acpi_fadt.Xpm_tmr_blk.address); /* Re-enable interrupts */ - __sti(); + local_irq_enable(); /* Compute time (ticks) that we were actually asleep */ sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; break; @@ -516,13 +516,13 @@ acpi_processor_idle (void) /* Enable bus master arbitration */ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_DO_NOT_LOCK); /* Re-enable interrupts */ - __sti(); + local_irq_enable(); /* Compute time (ticks) that we were actually asleep */ sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD; break; default: - __sti(); + local_irq_enable(); return; } @@ -1170,7 +1170,7 @@ acpi_processor_get_throttling ( pr->throttling.state = 0; - __cli(); + local_irq_disable(); duty_mask = pr->throttling.state_count - 1; @@ -1192,7 +1192,7 @@ acpi_processor_get_throttling ( pr->throttling.state = state; - __sti(); + local_irq_enable(); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Throttling state is T%d (%d%% throttling applied)\n", @@ -1225,7 +1225,7 @@ acpi_processor_set_throttling ( if (state == pr->throttling.state) return_VALUE(0); - __cli(); + local_irq_disable(); /* * Calculate the duty_value and duty_mask. @@ -1267,7 +1267,7 @@ acpi_processor_set_throttling ( pr->throttling.state = state; - __sti(); + local_irq_enable(); ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Throttling state set to T%d (%d%%)\n", state, diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 210449ad1715..dc372aa4dbb1 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -2055,29 +2055,20 @@ static void DAC960_ComputeGenericDiskInfo(DAC960_Controller_T *Controller) static void DAC960_RegisterDisk(DAC960_Controller_T *Controller, int LogicalDriveNumber) { - if (Controller->FirmwareType == DAC960_V1_Controller) - { + long size; + if (Controller->FirmwareType == DAC960_V1_Controller) { if (LogicalDriveNumber > Controller->LogicalDriveCount - 1) return; - register_disk(&Controller->GenericDiskInfo, - DAC960_KernelDevice(Controller->ControllerNumber, - LogicalDriveNumber, 0), - DAC960_MaxPartitions, - &DAC960_BlockDeviceOperations, - Controller->V1.LogicalDriveInformation - [LogicalDriveNumber].LogicalDriveSize); - } - else - { + size = Controller->V1.LogicalDriveInformation + [LogicalDriveNumber].LogicalDriveSize; + } else { DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo = Controller->V2.LogicalDeviceInformation[LogicalDriveNumber]; if (LogicalDeviceInfo == NULL) return; - register_disk(&Controller->GenericDiskInfo, - DAC960_KernelDevice(Controller->ControllerNumber, - LogicalDriveNumber, 0), - DAC960_MaxPartitions, - &DAC960_BlockDeviceOperations, - LogicalDeviceInfo->ConfigurableDeviceSize); - } + size = LogicalDeviceInfo->ConfigurableDeviceSize; + } + register_disk(&Controller->GenericDiskInfo, + DAC960_KernelDevice(Controller->ControllerNumber, LogicalDriveNumber, 0), + DAC960_MaxPartitions, &DAC960_BlockDeviceOperations, size); } @@ -5399,15 +5390,9 @@ static int DAC960_IOCTL(Inode_T *Inode, File_T *File, LogicalDeviceInfo->ConfigurableDeviceSize / (Geometry.heads * Geometry.sectors); } - Geometry.start = get_start_sect(Inode->i_rdev); + Geometry.start = get_start_sect(Inode->i_bdev); return (copy_to_user(UserGeometry, &Geometry, sizeof(DiskGeometry_T)) ? -EFAULT : 0); - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKFLSBUF: - case BLKBSZGET: - case BLKBSZSET: - return blk_ioctl(Inode->i_bdev, Request, Argument); case BLKRRPART: /* Re-Read Partition Table. */ diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c index c35ef7f77e40..f616f01847b7 100644 --- a/drivers/block/acsi.c +++ b/drivers/block/acsi.c @@ -248,8 +248,6 @@ static int NDevices = 0; static int acsi_sizes[MAX_DEV<<4] = { 0, }; static struct hd_struct acsi_part[MAX_DEV<<4] = { {0,0}, }; static int access_count[MAX_DEV] = { 0, }; -static char busy[MAX_DEV] = { 0, }; -static DECLARE_WAIT_QUEUE_HEAD(busy_wait); static int CurrentNReq; static int CurrentNSect; @@ -1107,7 +1105,7 @@ static int acsi_ioctl( struct inode *inode, struct file *file, put_user( 64, &geo->heads ); put_user( 32, &geo->sectors ); put_user( acsi_info[dev].size >> 11, &geo->cylinders ); - put_user(get_start_sect(inode->i_rdev), &geo->start); + put_user(get_start_sect(inode->i_bdev), &geo->start); return 0; } @@ -1118,14 +1116,6 @@ static int acsi_ioctl( struct inode *inode, struct file *file, put_user( 0, &((Scsi_Idlun *) arg)->host_unique_id ); return 0; - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKROSET: - case BLKROGET: - case BLKFLSBUF: - case BLKPG: - return blk_ioctl(inode->i_bdev, cmd, arg); - case BLKRRPART: /* Re-read partition tables */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -1161,8 +1151,6 @@ static int acsi_open( struct inode * inode, struct file * filp ) if (device >= NDevices) return -ENXIO; aip = &acsi_info[device]; - while (busy[device]) - sleep_on(&busy_wait); if (access_count[device] == 0 && aip->removable) { #if 0 @@ -1803,10 +1791,6 @@ void cleanup_module(void) } #endif -#define DEVICE_BUSY busy[device] -#define USAGE access_count[device] -#define GENDISK_STRUCT acsi_gendisk - /* * This routine is called to flush all partitions and partition tables * for a changed scsi disk, and then re-read the new partition table. @@ -1828,24 +1812,15 @@ void cleanup_module(void) static int revalidate_acsidisk( int dev, int maxusage ) { - int device; - struct gendisk * gdev; - int res; - struct acsi_info_struct *aip; - - device = DEVICE_NR(minor(dev)); - aip = &acsi_info[device]; - gdev = &GENDISK_STRUCT; + int unit = DEVICE_NR(minor(dev)); + struct acsi_info_struct *aip = &acsi_info[unit]; + kdev_t device = mk_kdev(MAJOR_NR, unit<<4); + int res = dev_lock_part(device); - cli(); - if (DEVICE_BUSY || USAGE > maxusage) { - sti(); - return -EBUSY; - }; - DEVICE_BUSY = 1; - sti(); + if (res < 0) + return res; - res = wipe_partitions(dev); + res = wipe_partitions(device); stdma_lock( NULL, NULL ); @@ -1862,10 +1837,9 @@ static int revalidate_acsidisk( int dev, int maxusage ) stdma_release(); if (!res) - grok_partitions(dev, aip->size); + grok_partitions(device, aip->size); - DEVICE_BUSY = 0; - wake_up(&busy_wait); + dev_unlock_part(device); return res; } diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index af8f966f4eb3..04a8ce00c6a7 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -1559,12 +1559,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, struct floppy_struct setprm; device = inode->i_rdev; - switch (cmd) { - case BLKROSET: - case BLKROGET: - case BLKFLSBUF: - return blk_ioctl(inode->i_bdev, cmd, param); - } drive = minor (device); type = drive >> 2; drive &= 3; diff --git a/drivers/block/blkpg.c b/drivers/block/blkpg.c index 37e244777963..83826af84b6a 100644 --- a/drivers/block/blkpg.c +++ b/drivers/block/blkpg.c @@ -69,8 +69,9 @@ int add_partition(struct block_device *bdev, struct blkpg_partition *p) struct gendisk *g; long long ppstart, pplength; long pstart, plength; - int i, drive, first_minor, end_minor, minor; + int i; kdev_t dev = to_kdev_t(bdev->bd_dev); + struct hd_struct *part; /* convert bytes to sectors, check for fit in a hd_struct */ ppstart = (p->start >> 9); @@ -85,37 +86,32 @@ int add_partition(struct block_device *bdev, struct blkpg_partition *p) g = get_gendisk(dev); if (!g) return -ENXIO; + part = g->part + minor(dev); /* existing drive? */ - drive = (minor(dev) >> g->minor_shift); - first_minor = (drive << g->minor_shift); - end_minor = first_minor + (1 << g->minor_shift); - if (drive >= g->nr_real) - return -ENXIO; /* drive and partition number OK? */ - if (first_minor != minor(dev)) + if (bdev != bdev->bd_contains) return -EINVAL; if (p->pno <= 0 || p->pno >= (1 << g->minor_shift)) return -EINVAL; /* partition number in use? */ - minor = first_minor + p->pno; - if (g->part[minor].nr_sects != 0) + if (part[p->pno].nr_sects != 0) return -EBUSY; /* overlap? */ - for (i=first_minor+1; i<end_minor; i++) - if (!(pstart+plength <= g->part[i].start_sect || - pstart >= g->part[i].start_sect + g->part[i].nr_sects)) + for (i = 1; i < (1<<g->minor_shift); i++) + if (!(pstart+plength <= part[i].start_sect || + pstart >= part[i].start_sect + part[i].nr_sects)) return -EBUSY; /* all seems OK */ - g->part[minor].start_sect = pstart; - g->part[minor].nr_sects = plength; + part[p->pno].start_sect = pstart; + part[p->pno].nr_sects = plength; if (g->sizes) - g->sizes[minor] = (plength >> (BLOCK_SIZE_BITS - 9)); - devfs_register_partitions (g, first_minor, 0); + g->sizes[minor(dev)+p->pno] = (plength >> (BLOCK_SIZE_BITS-9)); + devfs_register_partitions (g, minor(dev), 0); return 0; } @@ -133,33 +129,27 @@ int del_partition(struct block_device *bdev, struct blkpg_partition *p) { kdev_t dev = to_kdev_t(bdev->bd_dev); struct gendisk *g; - kdev_t devp; struct block_device *bdevp; - int drive, first_minor, minor; + struct hd_struct *part; int holder; /* find the drive major */ g = get_gendisk(dev); if (!g) return -ENXIO; + part = g->part + minor(dev); - /* drive and partition number OK? */ - drive = (minor(dev) >> g->minor_shift); - first_minor = (drive << g->minor_shift); - - if (first_minor != minor(dev)) + if (bdev != bdev->bd_contains) return -EINVAL; if (p->pno <= 0 || p->pno >= (1 << g->minor_shift)) return -EINVAL; /* existing drive and partition? */ - minor = first_minor + p->pno; - if (drive >= g->nr_real || g->part[minor].nr_sects == 0) + if (part[p->pno].nr_sects == 0) return -ENXIO; /* partition in use? Incomplete check for now. */ - devp = mk_kdev(major(dev), minor); - bdevp = bdget(kdev_t_to_nr(devp)); + bdevp = bdget(MKDEV(major(dev), minor(dev) + p->pno)); if (!bdevp) return -ENOMEM; if (bd_claim(bdevp, &holder) < 0) { @@ -171,11 +161,11 @@ int del_partition(struct block_device *bdev, struct blkpg_partition *p) fsync_bdev(bdevp); invalidate_bdev(bdevp, 0); - g->part[minor].start_sect = 0; - g->part[minor].nr_sects = 0; + part[p->pno].start_sect = 0; + part[p->pno].nr_sects = 0; if (g->sizes) - g->sizes[minor] = 0; - devfs_register_partitions (g, first_minor, 0); + g->sizes[minor(dev) + p->pno] = 0; + devfs_register_partitions (g, minor(dev), 0); bd_release(bdevp); bdput(bdevp); @@ -223,10 +213,6 @@ int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg) int holder; struct backing_dev_info *bdi; - intval = block_ioctl(bdev, cmd, arg); - if (intval != -ENOTTY) - return intval; - switch (cmd) { case BLKROSET: if (!capable(CAP_SYS_ADMIN)) @@ -296,14 +282,6 @@ int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg) case BLKPG: return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg *) arg); - - /* - * deprecated, use the /proc/iosched interface instead - */ - case BLKELVGET: - case BLKELVSET: - return -ENOTTY; - case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */ intval = block_size(bdev); @@ -330,5 +308,3 @@ int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg) return -EINVAL; } } - -EXPORT_SYMBOL(blk_ioctl); diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index e06fd274b653..939d70269415 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -440,15 +440,6 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, case BLKRRPART: return revalidate_logvol(inode->i_rdev, 1); - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKFLSBUF: - case BLKBSZSET: - case BLKBSZGET: - case BLKROSET: - case BLKROGET: - case BLKPG: - return blk_ioctl(inode->i_bdev, cmd, arg); case CCISS_GETPCIINFO: { cciss_pci_info_struct pciinfo; @@ -735,6 +726,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep, } /* Borrowed and adapted from sd.c */ +/* + * FIXME: we are missing the exclusion with ->open() here - it can happen + * just as we are rereading partition tables. + */ static int revalidate_logvol(kdev_t dev, int maxusage) { int ctlr, target; @@ -860,18 +855,9 @@ static int deregister_disk(int ctlr, int logvol) /* invalidate the devices and deregister the disk */ max_p = 1 << gdev->minor_shift; start = logvol << gdev->minor_shift; + wipe_partitions(mk_kdev(MAJOR_NR+ctlr, start)); for (i=max_p-1; i>=0; i--) - { - int minor = start+i; - kdev_t kdev = mk_kdev(MAJOR_NR+ctlr, minor); - // printk("invalidating( %d %d)\n", ctlr, minor); - invalidate_device(kdev, 1); - /* so open will now fail */ - h->sizes[minor] = 0; - /* so it will no longer appear in /proc/partitions */ - gdev->part[minor].start_sect = 0; - gdev->part[minor].nr_sects = 0; - } + h->sizes[start + i] = 0; /* check to see if it was the last disk */ if (logvol == h->highest_lun) { @@ -1313,19 +1299,12 @@ static int register_new_disk(kdev_t dev, int ctlr) hba[ctlr]->drv[logvol].usage_count = 0; max_p = 1 << gdev->minor_shift; start = logvol<< gdev->minor_shift; + kdev = mk_kdev(MAJOR_NR + ctlr, logvol<< gdev->minor_shift); - for(i=max_p-1; i>=0; i--) { - int minor = start+i; - kdev = mk_kdev(MAJOR_NR + ctlr, minor); - invalidate_device(kdev, 1); - gdev->part[minor].start_sect = 0; - gdev->part[minor].nr_sects = 0; - } - + wipe_partitions(kdev); ++hba[ctlr]->num_luns; gdev->nr_real = hba[ctlr]->highest_lun + 1; /* setup partitions per disk */ - kdev = mk_kdev(MAJOR_NR + ctlr, logvol<< gdev->minor_shift); grok_partitions(kdev, hba[ctlr]->drv[logvol].nr_blocks); kfree(ld_buff); diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c index fccef1bb792c..31276ef0e87c 100644 --- a/drivers/block/cpqarray.c +++ b/drivers/block/cpqarray.c @@ -1116,7 +1116,7 @@ static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, put_user(diskinfo[0], &geo->heads); put_user(diskinfo[1], &geo->sectors); put_user(diskinfo[2], &geo->cylinders); - put_user(get_start_sect(inode->i_rdev), &geo->start); + put_user(get_start_sect(inode->i_bdev), &geo->start); return 0; case IDAGETDRVINFO: if (copy_to_user(&io->c.drv, &hba[ctlr]->drv[dsk], @@ -1157,16 +1157,6 @@ static int ida_ioctl(struct inode *inode, struct file *filep, unsigned int cmd, return(0); } - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKFLSBUF: - case BLKBSZSET: - case BLKBSZGET: - case BLKROSET: - case BLKROGET: - case BLKPG: - return blk_ioctl(inode->i_bdev, cmd, arg); - default: return -EINVAL; } @@ -1533,6 +1523,9 @@ static int revalidate_allvol(kdev_t dev) } /* Borrowed and adapted from sd.c */ +/* + * FIXME: exclusion with ->open() + */ static int revalidate_logvol(kdev_t dev, int maxusage) { int ctlr, target; diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index aff8acff0ef3..fdc6e904464a 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -3468,12 +3468,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, const char *outparam; /* parameters passed back to user space */ device = inode->i_rdev; - switch (cmd) { - case BLKROSET: - case BLKROGET: - case BLKFLSBUF: - return blk_ioctl(inode->i_bdev, cmd, param); - } type = TYPE(device); drive = DRIVE(device); diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 7c30fbe37c16..0fc011f610d1 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -117,31 +117,6 @@ get_gendisk(kdev_t dev) EXPORT_SYMBOL(get_gendisk); - -unsigned long -get_start_sect(kdev_t dev) -{ - struct gendisk *gp; - - gp = get_gendisk(dev); - if (gp) - return gp->part[minor(dev)].start_sect; - return 0; -} - -EXPORT_SYMBOL(get_start_sect); - -unsigned long -get_nr_sects(kdev_t dev) -{ - struct gendisk *gp; - - gp = get_gendisk(dev); - if (gp) - return gp->part[minor(dev)].nr_sects; - return 0; -} - #ifdef CONFIG_PROC_FS /* iterator */ static void *part_start(struct seq_file *part, loff_t *pos) @@ -209,7 +184,6 @@ int __init device_init(void) { rwlock_init(&gendisk_lock); blk_dev_init(); - sti(); #ifdef CONFIG_I2O i2o_init(); #endif diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 48616f94f5ee..c23f57a0ed16 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -1573,16 +1573,10 @@ end_io: static inline void blk_partition_remap(struct bio *bio) { struct block_device *bdev = bio->bi_bdev; - struct gendisk *g; - if (bdev == bdev->bd_contains) return; - g = get_gendisk(to_kdev_t(bdev->bd_dev)); - if (!g) - BUG(); - - bio->bi_sector += g->part[minor(to_kdev_t((bdev->bd_dev)))].start_sect; + bio->bi_sector += bdev->bd_offset; bio->bi_bdev = bdev->bd_contains; /* lots of checks are possible */ } @@ -2047,9 +2041,6 @@ int __init blk_dev_init(void) #if defined(CONFIG_IDE) && defined(CONFIG_BLK_DEV_HD) hd_init(); #endif -#if defined(__i386__) /* Do we even need this? */ - outb_p(0xc, 0x3f2); -#endif return 0; }; diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 982604ff6bfd..50c1052cae74 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -912,10 +912,6 @@ static int lo_ioctl(struct inode * inode, struct file * file, } err = put_user((u64)loop_sizes[lo->lo_number] << 10, (u64*)arg); break; - case BLKBSZGET: - case BLKBSZSET: - err = blk_ioctl(inode->i_bdev, cmd, arg); - break; default: err = lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL; } diff --git a/drivers/block/paride/Makefile b/drivers/block/paride/Makefile index d62c39cb9b55..b1294e64f414 100644 --- a/drivers/block/paride/Makefile +++ b/drivers/block/paride/Makefile @@ -5,14 +5,9 @@ # Rewritten to use lists instead of if-statements. # -export-objs := paride.o bpck6.o +export-objs := paride.o obj-$(CONFIG_PARIDE) += paride.o -obj-$(CONFIG_PARIDE_PD) += pd.o -obj-$(CONFIG_PARIDE_PCD) += pcd.o -obj-$(CONFIG_PARIDE_PF) += pf.o -obj-$(CONFIG_PARIDE_PT) += pt.o -obj-$(CONFIG_PARIDE_PG) += pg.o obj-$(CONFIG_PARIDE_ATEN) += aten.o obj-$(CONFIG_PARIDE_BPCK) += bpck.o obj-$(CONFIG_PARIDE_COMM) += comm.o @@ -20,13 +15,18 @@ obj-$(CONFIG_PARIDE_DSTR) += dstr.o obj-$(CONFIG_PARIDE_KBIC) += kbic.o obj-$(CONFIG_PARIDE_EPAT) += epat.o obj-$(CONFIG_PARIDE_EPIA) += epia.o -obj-$(CONFIG_PARIDE_FIT2) += fit2.o -obj-$(CONFIG_PARIDE_FIT3) += fit3.o obj-$(CONFIG_PARIDE_FRPW) += frpw.o obj-$(CONFIG_PARIDE_FRIQ) += friq.o +obj-$(CONFIG_PARIDE_FIT2) += fit2.o +obj-$(CONFIG_PARIDE_FIT3) += fit3.o obj-$(CONFIG_PARIDE_ON20) += on20.o obj-$(CONFIG_PARIDE_ON26) += on26.o obj-$(CONFIG_PARIDE_KTTI) += ktti.o obj-$(CONFIG_PARIDE_BPCK6) += bpck6.o +obj-$(CONFIG_PARIDE_PD) += pd.o +obj-$(CONFIG_PARIDE_PCD) += pcd.o +obj-$(CONFIG_PARIDE_PF) += pf.o +obj-$(CONFIG_PARIDE_PT) += pt.o +obj-$(CONFIG_PARIDE_PG) += pg.o include $(TOPDIR)/Rules.make diff --git a/drivers/block/paride/aten.c b/drivers/block/paride/aten.c index b22d34da348a..763fc50d7f76 100644 --- a/drivers/block/paride/aten.c +++ b/drivers/block/paride/aten.c @@ -18,6 +18,7 @@ #define ATEN_VERSION "1.01" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/wait.h> @@ -140,35 +141,33 @@ static void aten_release_proto( PIA *pi ) { MOD_DEC_USE_COUNT; } -struct pi_protocol aten = {"aten",0,2,2,1,1, - aten_write_regr, - aten_read_regr, - aten_write_block, - aten_read_block, - aten_connect, - aten_disconnect, - 0, - 0, - 0, - aten_log_adapter, - aten_init_proto, - aten_release_proto - }; - - -#ifdef MODULE - -int init_module(void) - -{ return pi_register( &aten ) - 1; +static struct pi_protocol aten = { + .name = "aten", + .max_mode = 2, + .epp_first = 2, + .default_delay = 1, + .max_units = 1, + .write_regr = aten_write_regr, + .read_regr = aten_read_regr, + .write_block = aten_write_block, + .read_block = aten_read_block, + .connect = aten_connect, + .disconnect = aten_disconnect, + .log_adapter = aten_log_adapter, + .init_proto = aten_init_proto, + .release_proto = aten_release_proto, +}; + +static int __init aten_init(void) +{ + return pi_register(&aten)-1; } -void cleanup_module(void) - -{ pi_unregister( &aten ); +static void __exit aten_exit(void) +{ + pi_unregister( &aten ); } -#endif - -/* end of aten.c */ MODULE_LICENSE("GPL"); +module_init(aten_init) +module_exit(aten_exit) diff --git a/drivers/block/paride/bpck.c b/drivers/block/paride/bpck.c index 3e20e6b7054a..b15ff97fe7af 100644 --- a/drivers/block/paride/bpck.c +++ b/drivers/block/paride/bpck.c @@ -17,6 +17,7 @@ #define BPCK_VERSION "1.02" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/types.h> @@ -452,34 +453,36 @@ static void bpck_release_proto( PIA *pi) { MOD_DEC_USE_COUNT; } -struct pi_protocol bpck = { "bpck",0,5,2,4,256, - bpck_write_regr, - bpck_read_regr, - bpck_write_block, - bpck_read_block, - bpck_connect, - bpck_disconnect, - bpck_test_port, - bpck_probe_unit, - bpck_test_proto, - bpck_log_adapter, - bpck_init_proto, - bpck_release_proto - }; - -#ifdef MODULE - -int init_module(void) - -{ return pi_register(&bpck) - 1; +static struct pi_protocol bpck = { + .name = "bpck", + .max_mode = 5, + .epp_first = 2, + .default_delay = 4, + .max_units = 255, + .write_regr = bpck_write_regr, + .read_regr = bpck_read_regr, + .write_block = bpck_write_block, + .read_block = bpck_read_block, + .connect = bpck_connect, + .disconnect = bpck_disconnect, + .test_port = bpck_test_port, + .probe_unit = bpck_probe_unit, + .test_proto = bpck_test_proto, + .log_adapter = bpck_log_adapter, + .init_proto = bpck_init_proto, + .release_proto = bpck_release_proto, +}; + +static int __init bpck_init(void) +{ + return pi_register(&bpck)-1; } -void cleanup_module(void) - -{ pi_unregister(&bpck); +static void __exit bpck_exit(void) +{ + pi_unregister(&bpck); } -#endif - -/* end of bpck.c */ MODULE_LICENSE("GPL"); +module_init(bpck_init) +module_exit(bpck_exit) diff --git a/drivers/block/paride/bpck6.c b/drivers/block/paride/bpck6.c index f2febfcfd268..c1fcdd9f4e94 100644 --- a/drivers/block/paride/bpck6.c +++ b/drivers/block/paride/bpck6.c @@ -26,6 +26,7 @@ int verbose=0; /* set this to 1 to see debugging messages and whatnot */ #define BACKPACK_VERSION "2.0.2" #include <linux/module.h> +#include <linux/init.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/types.h> @@ -252,65 +253,41 @@ static void bpck6_release_proto(PIA *pi) kfree((void *)(pi->private)); } -struct pi_protocol bpck6 = { "bpck6", /* name for proto*/ - 0, /* index into proto table */ - 5, /* max mode =5 */ - 2, /* 2-5 use epp (need 8 ports) */ - 0, /* no delay (not used anyway) */ - 255, /* we can have units up to 255 */ - bpck6_write_regr, - bpck6_read_regr, - bpck6_write_block, - bpck6_read_block, - bpck6_connect, - bpck6_disconnect, - bpck6_test_port, - bpck6_probe_unit, - 0, - bpck6_log_adapter, - bpck6_init_proto, - bpck6_release_proto - }; - - -EXPORT_SYMBOL(bpck6_write_regr); -EXPORT_SYMBOL(bpck6_read_regr); -EXPORT_SYMBOL(bpck6_write_block); -EXPORT_SYMBOL(bpck6_read_block); -EXPORT_SYMBOL(bpck6_connect); -EXPORT_SYMBOL(bpck6_disconnect); -EXPORT_SYMBOL(bpck6_test_port); -EXPORT_SYMBOL(bpck6_probe_unit); -EXPORT_SYMBOL(bpck6_log_adapter); -EXPORT_SYMBOL(bpck6_init_proto); -EXPORT_SYMBOL(bpck6_release_proto); - -/*---------------------------MODULE STUFF-----------------------*/ - -#ifdef MODULE -/*module information*/ - -static int init_module(void) +static struct pi_protocol bpck6 = { + .name = "bpck6", + .max_mode = 5, + .epp_first = 2, /* 2-5 use epp (need 8 ports) */ + .max_units = 255, + .write_regr = bpck6_write_regr, + .read_regr = bpck6_read_regr, + .write_block = bpck6_write_block, + .read_block = bpck6_read_block, + .connect = bpck6_connect, + .disconnect = bpck6_disconnect, + .test_port = bpck6_test_port, + .probe_unit = bpck6_probe_unit, + .log_adapter = bpck6_log_adapter, + .init_proto = bpck6_init_proto, + .release_proto = bpck6_release_proto, +}; + +static int __init bpck6_init(void) { printk(KERN_INFO "bpck6: BACKPACK Protocol Driver V"BACKPACK_VERSION"\n"); printk(KERN_INFO "bpck6: Copyright 2001 by Micro Solutions, Inc., DeKalb IL. USA\n"); - if(verbose) - { printk(KERN_DEBUG "bpck6: verbose debug enabled.\n"); - } - return pi_register(&bpck6) - 1; } -void cleanup_module(void) +static void __exit bpck6_exit(void) { pi_unregister(&bpck6); } +MODULE_LICENSE("GPL"); MODULE_AUTHOR("Micro Solutions Inc."); MODULE_DESCRIPTION("BACKPACK Protocol module, compatible with PARIDE"); MODULE_PARM(verbose,"i"); - -#endif - +module_init(bpck6_init) +module_exit(bpck6_exit) diff --git a/drivers/block/paride/comm.c b/drivers/block/paride/comm.c index 058a7d68572c..f3010d6fc73b 100644 --- a/drivers/block/paride/comm.c +++ b/drivers/block/paride/comm.c @@ -17,6 +17,7 @@ #define COMM_VERSION "1.01" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/types.h> @@ -196,35 +197,33 @@ static void comm_release_proto(PIA *pi) { MOD_DEC_USE_COUNT; } -struct pi_protocol comm = {"comm",0,5,2,1,1, - comm_write_regr, - comm_read_regr, - comm_write_block, - comm_read_block, - comm_connect, - comm_disconnect, - 0, - 0, - 0, - comm_log_adapter, - comm_init_proto, - comm_release_proto - }; - - -#ifdef MODULE - -int init_module(void) - -{ return pi_register( &comm ) - 1; +static struct pi_protocol comm = { + .name = "comm", + .max_mode = 5, + .epp_first = 2, + .default_delay = 1, + .max_units = 1, + .write_regr = comm_write_regr, + .read_regr = comm_read_regr, + .write_block = comm_write_block, + .read_block = comm_read_block, + .connect = comm_connect, + .disconnect = comm_disconnect, + .log_adapter = comm_log_adapter, + .init_proto = comm_init_proto, + .release_proto = comm_release_proto, +}; + +static int __init comm_init(void) +{ + return pi_register(&comm)-1; } -void cleanup_module(void) - -{ pi_unregister( &comm ); +static void __exit comm_exit(void) +{ + pi_unregister(&comm); } -#endif - -/* end of comm.c */ MODULE_LICENSE("GPL"); +module_init(comm_init) +module_exit(comm_exit) diff --git a/drivers/block/paride/dstr.c b/drivers/block/paride/dstr.c index 438735b6ce10..204fe75df233 100644 --- a/drivers/block/paride/dstr.c +++ b/drivers/block/paride/dstr.c @@ -16,6 +16,7 @@ #define DSTR_VERSION "1.01" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/types.h> @@ -211,35 +212,33 @@ static void dstr_release_proto( PIA *pi) { MOD_DEC_USE_COUNT; } -struct pi_protocol dstr = {"dstr",0,5,2,1,1, - dstr_write_regr, - dstr_read_regr, - dstr_write_block, - dstr_read_block, - dstr_connect, - dstr_disconnect, - 0, - 0, - 0, - dstr_log_adapter, - dstr_init_proto, - dstr_release_proto - }; - - -#ifdef MODULE - -int init_module(void) - -{ return pi_register( &dstr ) - 1; +static struct pi_protocol dstr = { + .name = "dstr", + .max_mode = 5, + .epp_first = 2, + .default_delay = 1, + .max_units = 1, + .write_regr = dstr_write_regr, + .read_regr = dstr_read_regr, + .write_block = dstr_write_block, + .read_block = dstr_read_block, + .connect = dstr_connect, + .disconnect = dstr_disconnect, + .log_adapter = dstr_log_adapter, + .init_proto = dstr_init_proto, + .release_proto = dstr_release_proto, +}; + +static int __init dstr_init(void) +{ + return pi_register(&dstr)-1; } -void cleanup_module(void) - -{ pi_unregister( &dstr ); +static void __exit dstr_exit(void) +{ + pi_unregister(&dstr); } -#endif - -/* end of dstr.c */ MODULE_LICENSE("GPL"); +module_init(dstr_init) +module_exit(dstr_exit) diff --git a/drivers/block/paride/epat.c b/drivers/block/paride/epat.c index 624a5ba32cfd..0a7126756371 100644 --- a/drivers/block/paride/epat.c +++ b/drivers/block/paride/epat.c @@ -19,6 +19,7 @@ #define EPAT_VERSION "1.02" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/types.h> @@ -311,35 +312,34 @@ static void epat_release_proto( PIA *pi) { MOD_DEC_USE_COUNT; } -struct pi_protocol epat = {"epat",0,6,3,1,1, - epat_write_regr, - epat_read_regr, - epat_write_block, - epat_read_block, - epat_connect, - epat_disconnect, - 0, - 0, - epat_test_proto, - epat_log_adapter, - epat_init_proto, - epat_release_proto - }; - - -#ifdef MODULE - -int init_module(void) - -{ return pi_register( &epat) - 1; +static struct pi_protocol epat = { + .name = "epat", + .max_mode = 6, + .epp_first = 3, + .default_delay = 1, + .max_units = 1, + .write_regr = epat_write_regr, + .read_regr = epat_read_regr, + .write_block = epat_write_block, + .read_block = epat_read_block, + .connect = epat_connect, + .disconnect = epat_disconnect, + .test_proto = epat_test_proto, + .log_adapter = epat_log_adapter, + .init_proto = epat_init_proto, + .release_proto = epat_release_proto, +}; + +static int __init epat_init(void) +{ + return pi_register(&epat)-1; } -void cleanup_module(void) - -{ pi_unregister( &epat); +static void __exit epat_exit(void) +{ + pi_unregister(&epat); } -#endif - -/* end of epat.c */ MODULE_LICENSE("GPL"); +module_init(epat_init) +module_exit(epat_exit) diff --git a/drivers/block/paride/epia.c b/drivers/block/paride/epia.c index c27edd64ecc1..c2728af843dd 100644 --- a/drivers/block/paride/epia.c +++ b/drivers/block/paride/epia.c @@ -20,6 +20,7 @@ #define EPIA_VERSION "1.02" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/types.h> @@ -293,36 +294,34 @@ static void epia_release_proto( PIA *pi) { MOD_DEC_USE_COUNT; } -struct pi_protocol epia = {"epia",0,6,3,1,1, - epia_write_regr, - epia_read_regr, - epia_write_block, - epia_read_block, - epia_connect, - epia_disconnect, - 0, - 0, - epia_test_proto, - epia_log_adapter, - epia_init_proto, - epia_release_proto - }; - - -#ifdef MODULE - -int init_module(void) - -{ return pi_register( &epia ) - 1; +static struct pi_protocol epia = { + .name = "epia", + .max_mode = 6, + .epp_first = 3, + .default_delay = 1, + .max_units = 1, + .write_regr = epia_write_regr, + .read_regr = epia_read_regr, + .write_block = epia_write_block, + .read_block = epia_read_block, + .connect = epia_connect, + .disconnect = epia_disconnect, + .test_proto = epia_test_proto, + .log_adapter = epia_log_adapter, + .init_proto = epia_init_proto, + .release_proto = epia_release_proto, +}; + +static int __init epia_init(void) +{ + return pi_register(&epia)-1; } -void cleanup_module(void) - -{ pi_unregister( &epia ); +static void __exit epia_exit(void) +{ + pi_unregister(&epia); } -#endif - -/* end of epia.c */ - MODULE_LICENSE("GPL"); +module_init(epia_init) +module_exit(epia_exit) diff --git a/drivers/block/paride/fit2.c b/drivers/block/paride/fit2.c index 7f45529c80b1..42b2880a82ac 100644 --- a/drivers/block/paride/fit2.c +++ b/drivers/block/paride/fit2.c @@ -16,6 +16,7 @@ #define FIT2_VERSION "1.0" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/types.h> @@ -129,35 +130,33 @@ static void fit2_release_proto( PIA *pi) { MOD_DEC_USE_COUNT; } -struct pi_protocol fit2 = {"fit2",0,1,2,1,1, - fit2_write_regr, - fit2_read_regr, - fit2_write_block, - fit2_read_block, - fit2_connect, - fit2_disconnect, - 0, - 0, - 0, - fit2_log_adapter, - fit2_init_proto, - fit2_release_proto - }; - - -#ifdef MODULE - -int init_module(void) - -{ return pi_register( &fit2 ) - 1; +static struct pi_protocol fit2 = { + .name = "fit2", + .max_mode = 1, + .epp_first = 2, + .default_delay = 1, + .max_units = 1, + .write_regr = fit2_write_regr, + .read_regr = fit2_read_regr, + .write_block = fit2_write_block, + .read_block = fit2_read_block, + .connect = fit2_connect, + .disconnect = fit2_disconnect, + .log_adapter = fit2_log_adapter, + .init_proto = fit2_init_proto, + .release_proto = fit2_release_proto, +}; + +static int __init fit2_init(void) +{ + return pi_register(&fit2)-1; } -void cleanup_module(void) - -{ pi_unregister( &fit2 ); +static void __exit fit2_exit(void) +{ + pi_unregister(&fit2); } -#endif - -/* end of fit2.c */ MODULE_LICENSE("GPL"); +module_init(fit2_init) +module_exit(fit2_exit) diff --git a/drivers/block/paride/fit3.c b/drivers/block/paride/fit3.c index 8b5ad4bd5ad0..4d9286562c3c 100644 --- a/drivers/block/paride/fit3.c +++ b/drivers/block/paride/fit3.c @@ -20,6 +20,7 @@ #define FIT3_VERSION "1.0" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/types.h> @@ -189,35 +190,33 @@ static void fit3_release_proto(PIA *pi) { MOD_DEC_USE_COUNT; } -struct pi_protocol fit3 = {"fit3",0,3,2,1,1, - fit3_write_regr, - fit3_read_regr, - fit3_write_block, - fit3_read_block, - fit3_connect, - fit3_disconnect, - 0, - 0, - 0, - fit3_log_adapter, - fit3_init_proto, - fit3_release_proto - }; - - -#ifdef MODULE - -int init_module(void) - -{ return pi_register( &fit3 ) - 1; +static struct pi_protocol fit3 = { + .name = "fit3", + .max_mode = 3, + .epp_first = 2, + .default_delay = 1, + .max_units = 1, + .write_regr = fit3_write_regr, + .read_regr = fit3_read_regr, + .write_block = fit3_write_block, + .read_block = fit3_read_block, + .connect = fit3_connect, + .disconnect = fit3_disconnect, + .log_adapter = fit3_log_adapter, + .init_proto = fit3_init_proto, + .release_proto = fit3_release_proto, +}; + +static int __init fit3_init(void) +{ + return pi_register(&fit3)-1; } -void cleanup_module(void) - -{ pi_unregister( &fit3 ); +static void __exit fit3_exit(void) +{ + pi_unregister(&fit3); } -#endif - -/* end of fit3.c */ MODULE_LICENSE("GPL"); +module_init(fit3_init) +module_exit(fit3_exit) diff --git a/drivers/block/paride/friq.c b/drivers/block/paride/friq.c index 74b2eaab1c19..10b994a456da 100644 --- a/drivers/block/paride/friq.c +++ b/drivers/block/paride/friq.c @@ -28,6 +28,7 @@ #define FRIQ_VERSION "1.01" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/types.h> @@ -250,35 +251,34 @@ static void friq_release_proto( PIA *pi) MOD_DEC_USE_COUNT; } -struct pi_protocol friq = {"friq",0,5,2,1,1, - friq_write_regr, - friq_read_regr, - friq_write_block, - friq_read_block, - friq_connect, - friq_disconnect, - 0, - 0, - friq_test_proto, - friq_log_adapter, - friq_init_proto, - friq_release_proto - }; - - -#ifdef MODULE - -int init_module(void) - -{ return pi_register( &friq ) - 1; +static struct pi_protocol friq = { + .name = "friq", + .max_mode = 5, + .epp_first = 2, + .default_delay = 1, + .max_units = 1, + .write_regr = friq_write_regr, + .read_regr = friq_read_regr, + .write_block = friq_write_block, + .read_block = friq_read_block, + .connect = friq_connect, + .disconnect = friq_disconnect, + .test_proto = friq_test_proto, + .log_adapter = friq_log_adapter, + .init_proto = friq_init_proto, + .release_proto = friq_release_proto, +}; + +static int __init friq_init(void) +{ + return pi_register(&friq)-1; } -void cleanup_module(void) - -{ pi_unregister( &friq ); +static void __exit friq_exit(void) +{ + pi_unregister(&friq); } -#endif - -/* end of friq.c */ MODULE_LICENSE("GPL"); +module_init(friq_init) +module_exit(friq_exit) diff --git a/drivers/block/paride/frpw.c b/drivers/block/paride/frpw.c index 817004a3f7dc..ee0cad3807a1 100644 --- a/drivers/block/paride/frpw.c +++ b/drivers/block/paride/frpw.c @@ -26,6 +26,7 @@ #define FRPW_VERSION "1.03" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/types.h> @@ -291,35 +292,34 @@ static void frpw_release_proto( PIA *pi) { MOD_DEC_USE_COUNT; } -struct pi_protocol frpw = {"frpw",0,6,2,2,1, - frpw_write_regr, - frpw_read_regr, - frpw_write_block, - frpw_read_block, - frpw_connect, - frpw_disconnect, - 0, - 0, - frpw_test_proto, - frpw_log_adapter, - frpw_init_proto, - frpw_release_proto - }; - - -#ifdef MODULE - -int init_module(void) - -{ return pi_register( &frpw ) - 1; +static struct pi_protocol frpw = { + .name = "frpw", + .max_mode = 6, + .epp_first = 2, + .default_delay = 2, + .max_units = 1, + .write_regr = frpw_write_regr, + .read_regr = frpw_read_regr, + .write_block = frpw_write_block, + .read_block = frpw_read_block, + .connect = frpw_connect, + .disconnect = frpw_disconnect, + .test_proto = frpw_test_proto, + .log_adapter = frpw_log_adapter, + .init_proto = frpw_init_proto, + .release_proto = frpw_release_proto, +}; + +static int __init frpw_init(void) +{ + return pi_register(&frpw)-1; } -void cleanup_module(void) - -{ pi_unregister( &frpw ); +static void __exit frpw_exit(void) +{ + pi_unregister(&frpw); } -#endif - -/* end of frpw.c */ MODULE_LICENSE("GPL"); +module_init(frpw_init) +module_exit(frpw_exit) diff --git a/drivers/block/paride/kbic.c b/drivers/block/paride/kbic.c index 2f20c9b0fa4e..f97233b39b7b 100644 --- a/drivers/block/paride/kbic.c +++ b/drivers/block/paride/kbic.c @@ -21,6 +21,7 @@ #define KBIC_VERSION "1.01" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/types.h> @@ -258,56 +259,51 @@ static void kbic_release_proto( PIA *pi) { MOD_DEC_USE_COUNT; } -struct pi_protocol k951 = {"k951",0,6,3,1,1, - kbic_write_regr, - kbic_read_regr, - kbic_write_block, - kbic_read_block, - k951_connect, - k951_disconnect, - 0, - 0, - 0, - k951_log_adapter, - kbic_init_proto, - kbic_release_proto - }; - - -struct pi_protocol k971 = {"k971",0,6,3,1,1, - kbic_write_regr, - kbic_read_regr, - kbic_write_block, - kbic_read_block, - k971_connect, - k971_disconnect, - 0, - 0, - 0, - k971_log_adapter, - kbic_init_proto, - kbic_release_proto - }; - -#ifdef MODULE - -int init_module(void) - -{ int s5,s7; - - s5 = pi_register(&k951); - s7 = pi_register(&k971); - - return (s5 || s7) - 1; +static struct pi_protocol k951 = { + .name = "k951", + .max_mode = 6, + .epp_first = 3, + .default_delay = 1, + .max_units = 1, + .write_regr = kbic_write_regr, + .read_regr = kbic_read_regr, + .write_block = kbic_write_block, + .read_block = kbic_read_block, + .connect = k951_connect, + .disconnect = k951_disconnect, + .log_adapter = k951_log_adapter, + .init_proto = kbic_init_proto, + .release_proto = kbic_release_proto +}; + +static struct pi_protocol k971 = { + .name = "k971", + .max_mode = 6, + .epp_first = 3, + .default_delay = 1, + .max_units = 1, + .write_regr = kbic_write_regr, + .read_regr = kbic_read_regr, + .write_block = kbic_write_block, + .read_block = kbic_read_block, + .connect = k971_connect, + .disconnect = k971_disconnect, + .log_adapter = k971_log_adapter, + .init_proto = kbic_init_proto, + .release_proto = kbic_release_proto +}; + +static int __init kbic_init(void) +{ + return (pi_register(&k951)||pi_register(&k971))-1; } -void cleanup_module(void) - -{ pi_unregister( &k951 ); - pi_unregister( &k971 ); +static void __exit kbic_exit(void) +{ + pi_unregister(&k951); + pi_unregister(&k971); } -#endif - -/* end of kbic.c */ MODULE_LICENSE("GPL"); +module_init(kbic_init) +module_exit(kbic_exit) diff --git a/drivers/block/paride/ktti.c b/drivers/block/paride/ktti.c index 60778192e0c1..bee083b4da9c 100644 --- a/drivers/block/paride/ktti.c +++ b/drivers/block/paride/ktti.c @@ -12,6 +12,7 @@ #define KTTI_VERSION "1.0" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/types.h> @@ -106,35 +107,33 @@ static void ktti_release_proto( PIA *pi) { MOD_DEC_USE_COUNT; } -struct pi_protocol ktti = {"ktti",0,1,2,1,1, - ktti_write_regr, - ktti_read_regr, - ktti_write_block, - ktti_read_block, - ktti_connect, - ktti_disconnect, - 0, - 0, - 0, - ktti_log_adapter, - ktti_init_proto, - ktti_release_proto - }; - - -#ifdef MODULE - -int init_module(void) - -{ return pi_register( &ktti ) - 1; +static struct pi_protocol ktti = { + .name = "ktti", + .max_mode = 1, + .epp_first = 2, + .default_delay = 1, + .max_units = 1, + .write_regr = ktti_write_regr, + .read_regr = ktti_read_regr, + .write_block = ktti_write_block, + .read_block = ktti_read_block, + .connect = ktti_connect, + .disconnect = ktti_disconnect, + .log_adapter = ktti_log_adapter, + .init_proto = ktti_init_proto, + .release_proto = ktti_release_proto, +}; + +static int __init ktti_init(void) +{ + return pi_register(&ktti)-1; } -void cleanup_module(void) - -{ pi_unregister( &ktti ); +static void __exit ktti_exit(void) +{ + pi_unregister(&ktti); } -#endif - -/* end of ktti.c */ MODULE_LICENSE("GPL"); +module_init(ktti_init) +module_exit(ktti_exit) diff --git a/drivers/block/paride/on20.c b/drivers/block/paride/on20.c index b3c8d3d325e0..8528e0212591 100644 --- a/drivers/block/paride/on20.c +++ b/drivers/block/paride/on20.c @@ -15,6 +15,7 @@ #define ON20_VERSION "1.01" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/types.h> @@ -131,35 +132,33 @@ static void on20_release_proto( PIA *pi) { MOD_DEC_USE_COUNT; } -struct pi_protocol on20 = {"on20",0,2,2,1,1, - on20_write_regr, - on20_read_regr, - on20_write_block, - on20_read_block, - on20_connect, - on20_disconnect, - 0, - 0, - 0, - on20_log_adapter, - on20_init_proto, - on20_release_proto - }; - - -#ifdef MODULE - -int init_module(void) - -{ return pi_register( &on20 ) - 1; +static struct pi_protocol on20 = { + .name = "on20", + .max_mode = 2, + .epp_first = 2, + .default_delay = 1, + .max_units = 1, + .write_regr = on20_write_regr, + .read_regr = on20_read_regr, + .write_block = on20_write_block, + .read_block = on20_read_block, + .connect = on20_connect, + .disconnect = on20_disconnect, + .log_adapter = on20_log_adapter, + .init_proto = on20_init_proto, + .release_proto = on20_release_proto, +}; + +static int __init on20_init(void) +{ + return pi_register(&on20)-1; } -void cleanup_module(void) - -{ pi_unregister( &on20 ); +static void __exit on20_exit(void) +{ + pi_unregister(&on20); } -#endif - -/* end of on20.c */ MODULE_LICENSE("GPL"); +module_init(on20_init) +module_exit(on20_exit) diff --git a/drivers/block/paride/on26.c b/drivers/block/paride/on26.c index 0688c6317972..c08111db5a21 100644 --- a/drivers/block/paride/on26.c +++ b/drivers/block/paride/on26.c @@ -19,6 +19,7 @@ #define ON26_VERSION "1.04" #include <linux/module.h> +#include <linux/init.h> #include <linux/delay.h> #include <linux/kernel.h> #include <linux/types.h> @@ -296,36 +297,34 @@ static void on26_release_proto( PIA *pi) { MOD_DEC_USE_COUNT; } -struct pi_protocol on26 = {"on26",0,5,2,1,1, - on26_write_regr, - on26_read_regr, - on26_write_block, - on26_read_block, - on26_connect, - on26_disconnect, - on26_test_port, - 0, - 0, - on26_log_adapter, - on26_init_proto, - on26_release_proto - }; - - -#ifdef MODULE - -int init_module(void) - -{ return pi_register( &on26 ) - 1; +static struct pi_protocol on26 = { + .name = "on26", + .max_mode = 5, + .epp_first = 2, + .default_delay = 1, + .max_units = 1, + .write_regr = on26_write_regr, + .read_regr = on26_read_regr, + .write_block = on26_write_block, + .read_block = on26_read_block, + .connect = on26_connect, + .disconnect = on26_disconnect, + .test_port = on26_test_port, + .log_adapter = on26_log_adapter, + .init_proto = on26_init_proto, + .release_proto = on26_release_proto, +}; + +static int __init on26_init(void) +{ + return pi_register(&on26)-1; } -void cleanup_module(void) - -{ pi_unregister( &on26 ); +static void __exit on26_exit(void) +{ + pi_unregister(&on26); } -#endif - -/* end of on26.c */ - MODULE_LICENSE("GPL"); +module_init(on26_init) +module_exit(on26_exit) diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c index e3a6150acff6..18bd7892269c 100644 --- a/drivers/block/paride/paride.c +++ b/drivers/block/paride/paride.c @@ -431,136 +431,3 @@ int pi_init(PIA *pi, int autoprobe, int port, int mode, } EXPORT_SYMBOL(pi_init); - -#ifdef MODULE - -int init_module(void) - -{ - int k; - const char *indicate_pp = ""; -#ifdef CONFIG_PARPORT - indicate_pp = " (parport)"; -#endif - - for (k=0;k<MAX_PROTOS;k++) protocols[k] = 0; - - printk("paride: version %s installed%s\n",PI_VERSION,indicate_pp); - return 0; -} - -void cleanup_module(void) - -{ -} - -#else - -void paride_init( void ) - -{ - -#ifdef CONFIG_PARIDE_ATEN - { extern struct pi_protocol aten; - pi_register(&aten); - }; -#endif -#ifdef CONFIG_PARIDE_BPCK - { extern struct pi_protocol bpck; - pi_register(&bpck); - }; -#endif -#ifdef CONFIG_PARIDE_COMM - { extern struct pi_protocol comm; - pi_register(&comm); - }; -#endif -#ifdef CONFIG_PARIDE_DSTR - { extern struct pi_protocol dstr; - pi_register(&dstr); - }; -#endif -#ifdef CONFIG_PARIDE_EPAT - { extern struct pi_protocol epat; - pi_register(&epat); - }; -#endif -#ifdef CONFIG_PARIDE_EPIA - { extern struct pi_protocol epia; - pi_register(&epia); - }; -#endif -#ifdef CONFIG_PARIDE_FRPW - { extern struct pi_protocol frpw; - pi_register(&frpw); - }; -#endif -#ifdef CONFIG_PARIDE_FRIQ - { extern struct pi_protocol friq; - pi_register(&friq); - }; -#endif -#ifdef CONFIG_PARIDE_FIT2 - { extern struct pi_protocol fit2; - pi_register(&fit2); - }; -#endif -#ifdef CONFIG_PARIDE_FIT3 - { extern struct pi_protocol fit3; - pi_register(&fit3); - }; -#endif -#ifdef CONFIG_PARIDE_KBIC - { extern struct pi_protocol k951; - extern struct pi_protocol k971; - pi_register(&k951); - pi_register(&k971); - }; -#endif -#ifdef CONFIG_PARIDE_KTTI - { extern struct pi_protocol ktti; - pi_register(&ktti); - }; -#endif -#ifdef CONFIG_PARIDE_ON20 - { extern struct pi_protocol on20; - pi_register(&on20); - }; -#endif -#ifdef CONFIG_PARIDE_ON26 - { extern struct pi_protocol on26; - pi_register(&on26); - }; -#endif - -#ifdef CONFIG_PARIDE_PD - { extern int pd_init(void); - pd_init(); - }; -#endif -#ifdef CONFIG_PARIDE_PCD - { extern int pcd_init(void); - pcd_init(); - }; -#endif -#ifdef CONFIG_PARIDE_PF - { extern int pf_init(void); - pf_init(); - }; -#endif -#ifdef CONFIG_PARIDE_PT - { extern int pt_init(void); - pt_init(); - }; -#endif -#ifdef CONFIG_PARIDE_PG - { extern int pg_init(void); - pg_init(); - }; -#endif -} - -#endif - -/* end of paride.c */ -MODULE_LICENSE("GPL"); diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index e9839726b20e..25273d4ba1b8 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -137,6 +137,7 @@ static int pcd_drive_count; /* end of parameters */ #include <linux/module.h> +#include <linux/init.h> #include <linux/errno.h> #include <linux/fs.h> #include <linux/kernel.h> @@ -200,9 +201,6 @@ MODULE_PARM(drive3,"1-6i"); #define IDE_READY 0x40 #define IDE_BUSY 0x80 -int pcd_init(void); -void cleanup_module( void ); - static int pcd_open(struct cdrom_device_info *cdi, int purpose); static void pcd_release(struct cdrom_device_info *cdi); static int pcd_drive_status(struct cdrom_device_info *cdi, int slot_nr); @@ -327,84 +325,18 @@ static void pcd_init_units( void ) } } -int pcd_init (void) /* preliminary initialisation */ -{ - int unit; - - if (disable) return -1; - - pcd_init_units(); - - if (pcd_detect()) return -1; - - /* get the atapi capabilities page */ - pcd_probe_capabilities(); - - if (register_blkdev(MAJOR_NR,name,&pcd_bdops)) { - printk("pcd: unable to get major number %d\n",MAJOR_NR); - return -1; - } - - for (unit=0;unit<PCD_UNITS;unit++) { - if (PCD.present) { - register_cdrom(&PCD.info); - devfs_plain_cdrom(&PCD.info, &pcd_bdops); - } - } - - blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_pcd_request, &pcd_lock); - - return 0; -} - static int pcd_open(struct cdrom_device_info *cdi, int purpose) - -{ int unit = DEVICE_NR(cdi->dev); - - if ((unit >= PCD_UNITS) || (!PCD.present)) return -ENODEV; - +{ + int unit = DEVICE_NR(cdi->dev); + if ((unit >= PCD_UNITS) || (!PCD.present)) + return -ENODEV; return 0; } static void pcd_release(struct cdrom_device_info *cdi) - { } -#ifdef MODULE - -/* Glue for modules ... */ - -int init_module(void) - -{ int err; - -#ifdef PARIDE_JUMBO - { extern paride_init(); - paride_init(); - } -#endif - - err = pcd_init(); - - return err; -} - -void cleanup_module(void) - -{ int unit; - - for (unit=0;unit<PCD_UNITS;unit++) - if (PCD.present) { - pi_release(PI); - unregister_cdrom(&PCD.info); - } - - unregister_blkdev(MAJOR_NR,name); -} - -#endif - #define WR(c,r,v) pi_write_regr(PI,c,r,v) #define RR(c,r) (pi_read_regr(PI,c,r)) @@ -950,6 +882,50 @@ static int pcd_get_mcn (struct cdrom_device_info *cdi, struct cdrom_mcn *mcn) return 0; } -/* end of pcd.c */ + +static int __init pcd_init(void) +{ + int unit; + + if (disable) + return -1; + + pcd_init_units(); + + if (pcd_detect()) + return -1; + + /* get the atapi capabilities page */ + pcd_probe_capabilities(); + + if (register_blkdev(MAJOR_NR,name,&pcd_bdops)) { + printk("pcd: unable to get major number %d\n",MAJOR_NR); + return -1; + } + + for (unit=0;unit<PCD_UNITS;unit++) { + if (PCD.present) { + register_cdrom(&PCD.info); + devfs_plain_cdrom(&PCD.info, &pcd_bdops); + } + } + + blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_pcd_request, &pcd_lock); + + return 0; +} + +static void __exit pcd_exit(void) +{ + int unit; + for (unit=0;unit<PCD_UNITS;unit++) + if (PCD.present) { + pi_release(PI); + unregister_cdrom(&PCD.info); + } + unregister_blkdev(MAJOR_NR,name); +} MODULE_LICENSE("GPL"); +module_init(pcd_init) +module_exit(pcd_exit) diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index cb10da16d136..f9b681ac6b86 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -153,16 +153,12 @@ static int pd_drive_count; /* end of parameters */ +#include <linux/init.h> #include <linux/module.h> -#include <linux/errno.h> #include <linux/fs.h> -#include <linux/devfs_fs_kernel.h> -#include <linux/kernel.h> #include <linux/delay.h> -#include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/cdrom.h> /* for the eject ioctl */ -#include <linux/spinlock.h> #include <asm/uaccess.h> @@ -181,8 +177,8 @@ static STT pd_stt[7] = {{"drive0",8,drive0}, {"nice",1,&nice}}; void pd_setup( char *str, int *ints) - -{ generic_setup(pd_stt,7,str); +{ + generic_setup(pd_stt,7,str); } #endif @@ -199,19 +195,15 @@ MODULE_PARM(drive3,"1-8i"); #include "paride.h" -#define PD_BITS 4 - -/* set up defines for blk.h, why don't all drivers do it this way ? */ - #define MAJOR_NR major -#define DEVICE_NR(device) (minor(device)>>PD_BITS) -#define DEVICE_OFF(device) #include <linux/blk.h> #include <linux/blkpg.h> #include "pseudo.h" +#define PD_BITS 4 +#define DEVICE_NR(device) (minor(device)>>PD_BITS) #define PD_PARTNS (1<<PD_BITS) #define PD_DEVS PD_PARTNS*PD_UNITS @@ -258,11 +250,7 @@ MODULE_PARM(drive3,"1-8i"); #define IDE_IDENTIFY 0xec #define IDE_EJECT 0xed -int pd_init(void); void pd_setup(char * str, int * ints); -#ifdef MODULE -void cleanup_module( void ); -#endif static int pd_open(struct inode *inode, struct file *file); static void do_pd_request(request_queue_t * q); static int pd_ioctl(struct inode *inode,struct file *file, @@ -296,6 +284,7 @@ struct pd_unit { int heads; /* physical geometry */ int sectors; int cylinders; + int can_lba; int drive; /* master=0 slave=1 */ int changed; /* Have we seen a disk change ? */ int removable; /* removable media device ? */ @@ -303,7 +292,7 @@ struct pd_unit { int alt_geom; int present; char name[PD_NAMELEN]; /* pda, pdb, etc ... */ - }; +}; struct pd_unit pd[PD_UNITS]; @@ -312,7 +301,6 @@ struct pd_unit pd[PD_UNITS]; #define PD pd[unit] #define PI PD.pi -static int pd_valid = 1; /* serialise partition checks */ static char pd_scratch[512]; /* scratch block buffer */ /* the variables below are used mainly in the I/O request engine, which @@ -379,47 +367,12 @@ void pd_init_units( void ) } } -int pd_init (void) -{ - request_queue_t * q; - - if (disable) return -1; - if (devfs_register_blkdev(MAJOR_NR,name,&pd_fops)) { - printk("%s: unable to get major number %d\n", - name,major); - return -1; - } - q = BLK_DEFAULT_QUEUE(MAJOR_NR); - blk_init_queue(q, do_pd_request, &pd_lock); - blk_queue_max_sectors(q, cluster); - - pd_gendisk.major = major; - pd_gendisk.major_name = name; - add_gendisk(&pd_gendisk); - - printk("%s: %s version %s, major %d, cluster %d, nice %d\n", - name,name,PD_VERSION,major,cluster,nice); - pd_init_units(); - pd_valid = 0; - pd_gendisk.nr_real = pd_detect(); - pd_valid = 1; - -#ifdef MODULE - if (!pd_gendisk.nr_real) { - cleanup_module(); - return -1; - } -#endif - return 0; -} - static int pd_open (struct inode *inode, struct file *file) +{ + int unit = DEVICE_NR(inode->i_rdev); -{ int unit = DEVICE_NR(inode->i_rdev); - - if ((unit >= PD_UNITS) || (!PD.present)) return -ENODEV; - - wait_event (pd_wait_open, pd_valid); + if ((unit >= PD_UNITS) || (!PD.present)) + return -ENODEV; PD.access++; @@ -434,11 +387,8 @@ static int pd_ioctl(struct inode *inode,struct file *file, unsigned int cmd, unsigned long arg) { struct hd_geometry *geo = (struct hd_geometry *) arg; - int err, unit; + int err, unit = DEVICE_NR(inode->i_rdev); - if (!inode || kdev_none(inode->i_rdev)) - return -EINVAL; - unit = DEVICE_NR(inode->i_rdev); if (!PD.present) return -ENODEV; @@ -461,50 +411,34 @@ static int pd_ioctl(struct inode *inode,struct file *file, put_user(PD.heads, (char *) &geo->heads); put_user(PD.sectors, (char *) &geo->sectors); } - put_user(get_start_sect(inode->i_rdev), (long *)&geo->start); + put_user(get_start_sect(inode->i_bdev), (long *)&geo->start); return 0; case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; return pd_revalidate(inode->i_rdev); - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKROSET: - case BLKROGET: - case BLKFLSBUF: - case BLKPG: - return blk_ioctl(inode->i_bdev, cmd, arg); default: return -EINVAL; } } static int pd_release (struct inode *inode, struct file *file) +{ + int unit = DEVICE_NR(inode->i_rdev); -{ kdev_t devp; - int unit; - - devp = inode->i_rdev; - unit = DEVICE_NR(devp); - - if ((unit >= PD_UNITS) || (PD.access <= 0)) - return -EINVAL; - - PD.access--; - - if (!PD.access && PD.removable) + if (!--PD.access && PD.removable) pd_doorlock(unit,IDE_DOORUNLOCK); return 0; } static int pd_check_media( kdev_t dev) - -{ int r, unit; - - unit = DEVICE_NR(dev); - if ((unit >= PD_UNITS) || (!PD.present)) return -ENODEV; - if (!PD.removable) return 0; +{ + int r, unit = DEVICE_NR(dev); + if ((unit >= PD_UNITS) || (!PD.present)) + return -ENODEV; + if (!PD.removable) + return 0; pd_media_check(unit); r = PD.changed; PD.changed = 0; @@ -513,64 +447,26 @@ static int pd_check_media( kdev_t dev) static int pd_revalidate(kdev_t dev) { - int unit, res; - long flags; + int unit = DEVICE_NR(dev); + kdev_t device = mk_kdev(MAJOR_NR, unit << PD_BITS); + int res; - unit = DEVICE_NR(dev); if ((unit >= PD_UNITS) || !PD.present) return -ENODEV; - save_flags(flags); - cli(); - if (PD.access > 1) { - restore_flags(flags); - return -EBUSY; - } - pd_valid = 0; - restore_flags(flags); - - res = wipe_partitions(dev); + res = dev_lock_part(device); + if (res < 0) + return res; + res = wipe_partitions(device); if (res == 0 && pd_identify(unit)) - grok_partitions(dev, PD.capacity); + grok_partitions(device, PD.capacity); - pd_valid = 1; - wake_up(&pd_wait_open); + dev_unlock_part(device); return res; } -#ifdef MODULE - -/* Glue for modules ... */ - -void cleanup_module(void); - -int init_module(void) - -{ - -#ifdef PARIDE_JUMBO - { extern paride_init(); - paride_init(); - } -#endif - return pd_init(); -} - -void cleanup_module(void) -{ - int unit; - - devfs_unregister_blkdev(MAJOR_NR, name); - del_gendisk(&pd_gendisk); - - for (unit=0; unit<PD_UNITS; unit++) - if (PD.present) - pi_release(PI); -} -#endif - #define WR(c,r,v) pi_write_regr(PI,c,r,v) #define RR(c,r) (pi_read_regr(PI,c,r)) @@ -619,7 +515,6 @@ static int pd_wait_for( int unit, int w, char * msg ) /* polled wait */ static void pd_send_command( int unit, int n, int s, int h, int c0, int c1, int func ) - { WR(0,6,DRIVE+h); WR(0,1,0); /* the IDE task file */ @@ -633,16 +528,20 @@ static void pd_send_command( int unit, int n, int s, int h, } static void pd_ide_command( int unit, int func, int block, int count ) - -/* Don't use this call if the capacity is zero. */ - -{ int c1, c0, h, s; - - s = ( block % PD.sectors) + 1; - h = ( block / PD.sectors) % PD.heads; - c0 = ( block / (PD.sectors*PD.heads)) % 256; - c1 = ( block / (PD.sectors*PD.heads*256)); - +{ + int c1, c0, h, s; + + if (PD.can_lba) { + s = block & 255; + c0 = (block >>= 8) & 255; + c1 = (block >>= 8) & 255; + h = ((block >>= 8) & 15) + 0x40; + } else { + s = ( block % PD.sectors) + 1; + h = ( block /= PD.sectors) % PD.heads; + c0 = ( block /= PD.heads) % 256; + c1 = (block >>= 8); + } pd_send_command(unit,count,s,h,c0,c1,func); } @@ -742,10 +641,14 @@ static int pd_identify( int unit ) } pi_read_block(PI,pd_scratch,512); pi_disconnect(PI); - PD.sectors = word_val(6); - PD.heads = word_val(3); - PD.cylinders = word_val(1); - PD.capacity = PD.sectors*PD.heads*PD.cylinders; + PD.can_lba = pd_scratch[99] & 2; + PD.sectors = le16_to_cpu(*(u16*)(pd_scratch+12)); + PD.heads = le16_to_cpu(*(u16*)(pd_scratch+6)); + PD.cylinders = le16_to_cpu(*(u16*)(pd_scratch+2)); + if (PD.can_lba) + PD.capacity = le32_to_cpu(*(u32*)(pd_scratch + 120)); + else + PD.capacity = PD.sectors*PD.heads*PD.cylinders; for(j=0;j<PD_ID_LEN;j++) id[j^1] = pd_scratch[j+PD_ID_OFF]; j = PD_ID_LEN-1; @@ -763,7 +666,7 @@ static int pd_identify( int unit ) if (PD.capacity) pd_init_dev_parms(unit); if (!PD.standby) pd_standby_off(unit); - + return 1; } @@ -1031,6 +934,50 @@ static void do_pd_write_done( void ) spin_unlock_irqrestore(&pd_lock,saved_flags); } -/* end of pd.c */ +static int __init pd_init(void) +{ + request_queue_t * q; + int unit; + + if (disable) return -1; + if (devfs_register_blkdev(MAJOR_NR,name,&pd_fops)) { + printk("%s: unable to get major number %d\n", + name,major); + return -1; + } + q = BLK_DEFAULT_QUEUE(MAJOR_NR); + blk_init_queue(q, do_pd_request, &pd_lock); + blk_queue_max_sectors(q, cluster); + + pd_gendisk.major = major; + pd_gendisk.major_name = name; + add_gendisk(&pd_gendisk); + + printk("%s: %s version %s, major %d, cluster %d, nice %d\n", + name,name,PD_VERSION,major,cluster,nice); + pd_init_units(); + pd_gendisk.nr_real = pd_detect(); + if (!pd_gendisk.nr_real) { + devfs_unregister_blkdev(MAJOR_NR, name); + del_gendisk(&pd_gendisk); + for (unit=0; unit<PD_UNITS; unit++) + if (PD.present) + pi_release(PI); + return -1; + } + return 0; +} + +static void __exit pd_exit(void) +{ + int unit; + devfs_unregister_blkdev(MAJOR_NR, name); + del_gendisk(&pd_gendisk); + for (unit=0; unit<PD_UNITS; unit++) + if (PD.present) + pi_release(PI); +} MODULE_LICENSE("GPL"); +module_init(pd_init) +module_exit(pd_exit) diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 578feaadbb38..a117aa6df61a 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -153,11 +153,9 @@ static int pf_drive_count; #include <linux/module.h> -#include <linux/errno.h> +#include <linux/init.h> #include <linux/fs.h> -#include <linux/kernel.h> #include <linux/delay.h> -#include <linux/genhd.h> #include <linux/hdreg.h> #include <linux/cdrom.h> #include <linux/spinlock.h> @@ -240,7 +238,6 @@ MODULE_PARM(drive3,"1-7i"); #define ATAPI_READ_10 0x28 #define ATAPI_WRITE_10 0x2a -int pf_init(void); #ifdef MODULE void cleanup_module( void ); #endif @@ -337,34 +334,6 @@ void pf_init_units( void ) } } -int pf_init (void) /* preliminary initialisation */ - -{ int i; - request_queue_t * q; - - if (disable) return -1; - - pf_init_units(); - - if (pf_detect()) return -1; - pf_busy = 0; - - if (register_blkdev(MAJOR_NR,name,&pf_fops)) { - printk("pf_init: unable to get major number %d\n", - major); - return -1; - } - q = BLK_DEFAULT_QUEUE(MAJOR_NR); - blk_init_queue(q, do_pf_request, &pf_spin_lock); - blk_queue_max_phys_segments(q, cluster); - blk_queue_max_hw_segments(q, cluster); - - for (i=0;i<PF_UNITS;i++) - register_disk(NULL, mk_kdev(MAJOR_NR, i), 1, &pf_fops, 0); - - return 0; -} - static int pf_open (struct inode *inode, struct file *file) { int unit = DEVICE_NR(inode->i_rdev); @@ -423,10 +392,6 @@ static int pf_ioctl(struct inode *inode,struct file *file, return put_user(PF.capacity,(long *) arg); case BLKGETSIZE64: return put_user((u64)PF.capacity << 9,(u64 *)arg); - case BLKROSET: - case BLKROGET: - case BLKFLSBUF: - return blk_ioctl(inode->i_bdev, cmd, arg); default: return -EINVAL; } @@ -458,39 +423,6 @@ static int pf_check_media( kdev_t dev) { return 1; } -#ifdef MODULE - -/* Glue for modules ... */ - -void cleanup_module(void); - -int init_module(void) - -{ int err; - -#ifdef PARIDE_JUMBO - { extern paride_init(); - paride_init(); - } -#endif - - err = pf_init(); - - return err; -} - -void cleanup_module(void) - -{ int unit; - - unregister_blkdev(MAJOR_NR,name); - - for (unit=0;unit<PF_UNITS;unit++) - if (PF.present) pi_release(PI); -} - -#endif - #define WR(c,r,v) pi_write_regr(PI,c,r,v) #define RR(c,r) (pi_read_regr(PI,c,r)) @@ -1040,6 +972,44 @@ static void do_pf_write_done( void ) spin_unlock_irqrestore(&pf_spin_lock,saved_flags); } -/* end of pf.c */ +static int __init pf_init(void) /* preliminary initialisation */ +{ + int i; + request_queue_t * q; + + if (disable) + return -1; + + pf_init_units(); + + if (pf_detect()) + return -1; + pf_busy = 0; + + if (register_blkdev(MAJOR_NR,name,&pf_fops)) { + printk("pf_init: unable to get major number %d\n", major); + return -1; + } + q = BLK_DEFAULT_QUEUE(MAJOR_NR); + blk_init_queue(q, do_pf_request, &pf_spin_lock); + blk_queue_max_phys_segments(q, cluster); + blk_queue_max_hw_segments(q, cluster); + + for (i=0;i<PF_UNITS;i++) + register_disk(NULL, mk_kdev(MAJOR_NR, i), 1, &pf_fops, 0); + return 0; +} + +static void __exit pf_exit(void) +{ + int unit; + unregister_blkdev(MAJOR_NR,name); + for (unit=0;unit<PF_UNITS;unit++) + if (PF.present) + pi_release(PI); +} + MODULE_LICENSE("GPL"); +module_init(pf_init) +module_exit(pf_exit) diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index 5f5af68fc86c..0a43b4a5d61b 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -162,16 +162,13 @@ static int pg_drive_count; #include <linux/module.h> -#include <linux/errno.h> +#include <linux/init.h> #include <linux/fs.h> #include <linux/devfs_fs_kernel.h> -#include <linux/kernel.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/mtio.h> #include <linux/pg.h> -#include <linux/wait.h> -#include <linux/smp_lock.h> #include <asm/uaccess.h> @@ -218,11 +215,6 @@ MODULE_PARM(drive3,"1-6i"); #define ATAPI_IDENTIFY 0x12 -int pg_init(void); -#ifdef MODULE -void cleanup_module( void ); -#endif - static int pg_open(struct inode *inode, struct file *file); static int pg_release (struct inode *inode, struct file *file); static ssize_t pg_read(struct file * filp, char * buf, @@ -291,64 +283,6 @@ void pg_init_units( void ) static devfs_handle_t devfs_handle; -int pg_init (void) /* preliminary initialisation */ - -{ int unit; - - if (disable) return -1; - - pg_init_units(); - - if (pg_detect()) return -1; - - if (devfs_register_chrdev(major,name,&pg_fops)) { - printk("pg_init: unable to get major number %d\n", - major); - for (unit=0;unit<PG_UNITS;unit++) - if (PG.present) pi_release(PI); - return -1; - } - devfs_handle = devfs_mk_dir (NULL, "pg", NULL); - devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT, - major, 0, S_IFCHR | S_IRUSR | S_IWUSR, - &pg_fops, NULL); - return 0; -} - -#ifdef MODULE - -/* Glue for modules ... */ - -void cleanup_module(void); - -int init_module(void) - -{ int err; - -#ifdef PARIDE_JUMBO - { extern paride_init(); - paride_init(); - } -#endif - - err = pg_init(); - - return err; -} - -void cleanup_module(void) - -{ int unit; - - devfs_unregister (devfs_handle); - devfs_unregister_chrdev(major,name); - - for (unit=0;unit<PG_UNITS;unit++) - if (PG.present) pi_release(PI); -} - -#endif - #define WR(c,r,v) pi_write_regr(PI,c,r,v) #define RR(c,r) (pi_read_regr(PI,c,r)) @@ -691,6 +625,43 @@ static ssize_t pg_read(struct file * filp, char * buf, return copy+hs; } -/* end of pg.c */ +static int __init pg_init(void) +{ + int unit; + + if (disable) + return -1; + + pg_init_units(); + + if (pg_detect()) + return -1; + + if (devfs_register_chrdev(major,name,&pg_fops)) { + printk("pg_init: unable to get major number %d\n", + major); + for (unit=0;unit<PG_UNITS;unit++) + if (PG.present) pi_release(PI); + return -1; + } + devfs_handle = devfs_mk_dir (NULL, "pg", NULL); + devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT, + major, 0, S_IFCHR | S_IRUSR | S_IWUSR, + &pg_fops, NULL); + return 0; +} + +static void __exit pg_exit(void) +{ + int unit; + + devfs_unregister (devfs_handle); + devfs_unregister_chrdev(major,name); + + for (unit=0;unit<PG_UNITS;unit++) + if (PG.present) pi_release(PI); +} MODULE_LICENSE("GPL"); +module_init(pg_init) +module_exit(pg_exit) diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index ccf3db7b1463..bc987791fd32 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -141,15 +141,12 @@ static int pt_drive_count; #include <linux/module.h> -#include <linux/errno.h> +#include <linux/init.h> #include <linux/fs.h> #include <linux/devfs_fs_kernel.h> -#include <linux/kernel.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/mtio.h> -#include <linux/wait.h> -#include <linux/smp_lock.h> #include <asm/uaccess.h> @@ -209,11 +206,6 @@ MODULE_PARM(drive3,"1-6i"); #define ATAPI_MODE_SENSE 0x1a #define ATAPI_LOG_SENSE 0x4d -int pt_init(void); -#ifdef MODULE -void cleanup_module( void ); -#endif - static int pt_open(struct inode *inode, struct file *file); static int pt_ioctl(struct inode *inode,struct file *file, unsigned int cmd, unsigned long arg); @@ -291,71 +283,9 @@ void pt_init_units( void ) PT.name[j] = 0; if (DU[D_PRT]) pt_drive_count++; } -} - -static devfs_handle_t devfs_handle; - -int pt_init (void) /* preliminary initialisation */ - -{ int unit; - - if (disable) return -1; - - pt_init_units(); - - if (pt_detect()) return -1; - - if (devfs_register_chrdev(major,name,&pt_fops)) { - printk("pt_init: unable to get major number %d\n", - major); - for (unit=0;unit<PT_UNITS;unit++) - if (PT.present) pi_release(PI); - return -1; - } - - devfs_handle = devfs_mk_dir (NULL, "pt", NULL); - devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT, - major, 0, S_IFCHR | S_IRUSR | S_IWUSR, - &pt_fops, NULL); - devfs_register_series (devfs_handle, "%un", 4, DEVFS_FL_DEFAULT, - major, 128, S_IFCHR | S_IRUSR | S_IWUSR, - &pt_fops, NULL); - return 0; } -#ifdef MODULE - -/* Glue for modules ... */ - -void cleanup_module(void); - -int init_module(void) - -{ int err; - -#ifdef PARIDE_JUMBO - { extern paride_init(); - paride_init(); - } -#endif - - err = pt_init(); - - return err; -} - -void cleanup_module(void) - -{ int unit; - - devfs_unregister (devfs_handle); - devfs_unregister_chrdev(major,name); - - for (unit=0;unit<PT_UNITS;unit++) - if (PT.present) pi_release(PI); -} - -#endif +static devfs_handle_t devfs_handle; #define WR(c,r,v) pi_write_regr(PI,c,r,v) #define RR(c,r) (pi_read_regr(PI,c,r)) @@ -965,6 +895,46 @@ static ssize_t pt_write(struct file * filp, const char * buf, return t; } -/* end of pt.c */ +static int __init pt_init(void) +{ + int unit; + + if (disable) + return -1; + + pt_init_units(); + + if (pt_detect()) + return -1; + + if (devfs_register_chrdev(major,name,&pt_fops)) { + printk("pt_init: unable to get major number %d\n", + major); + for (unit=0;unit<PT_UNITS;unit++) + if (PT.present) pi_release(PI); + return -1; + } + + devfs_handle = devfs_mk_dir (NULL, "pt", NULL); + devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT, + major, 0, S_IFCHR | S_IRUSR | S_IWUSR, + &pt_fops, NULL); + devfs_register_series (devfs_handle, "%un", 4, DEVFS_FL_DEFAULT, + major, 128, S_IFCHR | S_IRUSR | S_IWUSR, + &pt_fops, NULL); + return 0; +} + +static void __exit pt_exit(void) +{ + int unit; + devfs_unregister (devfs_handle); + devfs_unregister_chrdev(major,name); + for (unit=0;unit<PT_UNITS;unit++) + if (PT.present) + pi_release(PI); +} MODULE_LICENSE("GPL"); +module_init(pt_init) +module_exit(pt_exit) diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c index bd604cee4663..1d734f15cab2 100644 --- a/drivers/block/ps2esdi.c +++ b/drivers/block/ps2esdi.c @@ -93,8 +93,6 @@ static void ps2esdi_geometry_int_handler(u_int); static int ps2esdi_open(struct inode *inode, struct file *file); -static int ps2esdi_release(struct inode *inode, struct file *file); - static int ps2esdi_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg); @@ -111,11 +109,8 @@ static void ps2esdi_reset_timer(unsigned long unused); static u_int dma_arb_level; /* DMA arbitration level */ static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_int); -static DECLARE_WAIT_QUEUE_HEAD(ps2esdi_wait_open); static int no_int_yet; -static int access_count[MAX_HD]; -static char ps2esdi_valid[MAX_HD]; static int ps2esdi_sizes[MAX_HD << 6]; static int ps2esdi_drives; static struct hd_struct ps2esdi[MAX_HD << 6]; @@ -152,7 +147,6 @@ static struct block_device_operations ps2esdi_fops = { owner: THIS_MODULE, open: ps2esdi_open, - release: ps2esdi_release, ioctl: ps2esdi_ioctl, }; @@ -441,13 +435,11 @@ static int __init ps2esdi_geninit(void) } blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), 128); - for (i = 0; i < ps2esdi_drives; i++) { + for (i = 0; i < ps2esdi_drives; i++) register_disk(&ps2esdi_gendisk,mk_kdev(MAJOR_NR,i<<6),1<<6, &ps2esdi_fops, ps2esdi_info[i].head * ps2esdi_info[i].sect * ps2esdi_info[i].cyl); - ps2esdi_valid[i] = 1; - } return 0; err_out3: @@ -1083,32 +1075,11 @@ static void dump_cmd_complete_status(u_int int_ret_code) static int ps2esdi_open(struct inode *inode, struct file *file) { int dev = DEVICE_NR(inode->i_rdev); - - if (dev < ps2esdi_drives) { - while (!ps2esdi_valid[dev]) - sleep_on(&ps2esdi_wait_open); - - access_count[dev]++; - - return (0); - } else - return (-ENODEV); -} - - - -static int ps2esdi_release(struct inode *inode, struct file *file) -{ - int dev = DEVICE_NR(inode->i_rdev); - - if (dev < ps2esdi_drives) { - access_count[dev]--; - } + if (dev >= ps2esdi_drives) + return -ENODEV; return 0; } - - static int ps2esdi_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg) { @@ -1125,7 +1096,7 @@ static int ps2esdi_ioctl(struct inode *inode, put_user(ps2esdi_info[dev].head, (char *) &geometry->heads); put_user(ps2esdi_info[dev].sect, (char *) &geometry->sectors); put_user(ps2esdi_info[dev].cyl, (short *) &geometry->cylinders); - put_user(get_start_sect(inode->i_rdev), + put_user(get_start_sect(inode->b_rdev), (long *) &geometry->start); return 0; @@ -1136,16 +1107,6 @@ static int ps2esdi_ioctl(struct inode *inode, if (!capable(CAP_SYS_ADMIN)) return -EACCES; return (ps2esdi_reread_partitions(inode->i_rdev)); - - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKROSET: - case BLKROGET: - case BLKFLSBUF: - case BLKBSZGET: - case BLKBSZSET: - case BLKPG: - return blk_ioctl(inode->i_bdev, cmd, arg); } return (-EINVAL); } @@ -1155,24 +1116,20 @@ static int ps2esdi_ioctl(struct inode *inode, static int ps2esdi_reread_partitions(kdev_t dev) { int target = DEVICE_NR(dev); - int res; + kdev_t device = mk_kdev(MAJOR_NR, target << 6); + int res = dev_lock_part(device); - cli(); - ps2esdi_valid[target] = (access_count[target] != 1); - sti(); - if (ps2esdi_valid[target]) - return (-EBUSY); + if (res < 0) + return res; - res = wipe_partitions(dev); + res = wipe_partitions(device); if (res == 0) - grok_partitions(dev, ps2esdi_info[target].head + grok_partitions(device, ps2esdi_info[target].head * ps2esdi_info[target].cyl * ps2esdi_info[target].sect); - ps2esdi_valid[target] = 1; - wake_up(&ps2esdi_wait_open); - - return (res); + dev_unlock_part(device); + return res; } static void ps2esdi_reset_timer(unsigned long unused) diff --git a/drivers/block/rd.c b/drivers/block/rd.c index 7b60e75d5584..662020429ba6 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -303,12 +303,6 @@ static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un } up(&inode->i_bdev->bd_sem); break; - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKROSET: - case BLKROGET: - case BLKSSZGET: - error = blk_ioctl(inode->i_bdev, cmd, arg); } out: return error; diff --git a/drivers/block/umem.c b/drivers/block/umem.c index e046885bb67b..a1575eb830b0 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -65,7 +65,7 @@ #define MM_BLKSIZE 1024 /* 1k blocks */ #define MM_HARDSECT 512 /* 512-byte hardware sectors */ #define MM_SHIFT 6 /* max 64 partitions on 4 cards */ -#define DEVICE_NR(device) (MINOR(device)>>MM_SHIFT) +#define DEVICE_NR(device) (minor(device)>>MM_SHIFT) /* * Version Information @@ -150,7 +150,6 @@ struct cardinfo { unsigned long last_change; } battery[2]; - atomic_t usage; spinlock_t lock; int check_batteries; @@ -813,31 +812,21 @@ static void del_battery_timer(void) * Note no locks taken out here. In a worst case scenario, we could drop * a chunk of system memory. But that should never happen, since validation * happens at open or mount time, when locks are held. + * + * That's crap, since doing that while some partitions are opened + * or mounted will give you really nasty results. */ static int mm_revalidate(kdev_t i_rdev) { - int i; - - int card_number = DEVICE_NR(kdev_val(i_rdev)); - /* first partition, # of partitions */ - int part1 = (card_number << MM_SHIFT) + 1; - int npart = (1 << MM_SHIFT) -1; - - /* first clear old partition information */ - for (i=0; i<npart ;i++) { - mm_gendisk.sizes[part1+i]=0; - mm_gendisk.part[part1+i].start_sect = 0; - mm_gendisk.part[part1+i].nr_sects = 0; - } - - mm_gendisk.part[card_number << MM_SHIFT].nr_sects = - cards[card_number].mm_size << 1; - - - /* then fill new info */ + int card_number = DEVICE_NR(i_rdev); + kdev_t device = mk_mdev(MAJOR_NR, card_number << MM_SHIFT); + int res = dev_lock_part(device); + if (res < 0) + return res; + wipe_partitions(device); printk(KERN_INFO "mm partition check: (%d)\n", card_number); - grok_partitions(mk_kdev(major_nr,part1-1), - mm_gendisk.sizes[card_number<<MM_SHIFT]); + grok_partitions(device, cards[card_number].mm_size << 1); + dev_unlock_part(device); return 0; } /* @@ -859,16 +848,6 @@ static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned switch(cmd) { - - case BLKGETSIZE: - /* Return the device size, expressed in sectors */ - err = ! access_ok (VERIFY_WRITE, arg, sizeof(long)); - if (err) return -EFAULT; - size = mm_gendisk.part[minor].nr_sects; - if (copy_to_user((long *) arg, &size, sizeof (long))) - return -EFAULT; - return 0; - case BLKRRPART: return (mm_revalidate(i->i_rdev)); @@ -883,16 +862,15 @@ static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned size = cards[card_number].mm_size * (1024 / MM_HARDSECT); geo.heads = 64; geo.sectors = 32; - geo.start = mm_gendisk.part[minor].start_sect; + geo.start = get_start_sect(inode->i_bdev); geo.cylinders = size / (geo.heads * geo.sectors); if (copy_to_user((void *) arg, &geo, sizeof(geo))) return -EFAULT; return 0; - default: - return blk_ioctl(i->i_bdev, cmd, arg); + return -EINVAL; } return -ENOTTY; /* unknown command */ @@ -905,7 +883,7 @@ static int mm_ioctl(struct inode *i, struct file *f, unsigned int cmd, unsigned */ static int mm_check_change(kdev_t i_rdev) { - int card_number = DEVICE_NR(kdev_val(i_rdev)); + int card_number = DEVICE_NR(i_rdev); /* struct cardinfo *dev = cards + card_number; */ if (card_number >= num_cards) /* paranoid */ return 0; @@ -920,38 +898,8 @@ static int mm_check_change(kdev_t i_rdev) */ static int mm_open(struct inode *i, struct file *filp) { - int num; - struct cardinfo *card; - - num = DEVICE_NR(kdev_val(i->i_rdev)); - if (num >= num_cards) + if (DEVICE_NR(i->i_rdev) >= num_cards) return -ENXIO; - - card = cards + num; - - atomic_inc(&card->usage); - MOD_INC_USE_COUNT; - - return 0; -} -/* ------------------------------------------------------------------------------------ --- mm_do_release ------------------------------------------------------------------------------------ -*/ -static int mm_do_release(struct inode *i, struct file *filp) -{ - int num; - struct cardinfo *card; - - num = DEVICE_NR(kdev_val(i->i_rdev)); - - card = cards + num; - - if (atomic_dec_and_test(&card->usage)) - invalidate_device(i->i_rdev, 1); - - MOD_DEC_USE_COUNT; return 0; } /* @@ -962,7 +910,6 @@ static int mm_do_release(struct inode *i, struct file *filp) static struct block_device_operations mm_fops = { owner: THIS_MODULE, open: mm_open, - release: mm_do_release, ioctl: mm_ioctl, revalidate: mm_revalidate, check_media_change: mm_check_change, @@ -1243,7 +1190,7 @@ static struct pci_driver mm_pci_driver = { static request_queue_t * mm_queue_proc(kdev_t dev) { - int c = DEVICE_NR(kdev_val(dev)); + int c = DEVICE_NR(dev); if (c < MM_MAXCARDS) return &cards[c].queue; @@ -1293,7 +1240,6 @@ int __init mm_init(void) blk_dev[MAJOR_NR].queue = mm_queue_proc; add_gendisk(&mm_gendisk); - blk_size[MAJOR_NR] = mm_gendisk.sizes; for (i = 0; i < num_cards; i++) { register_disk(&mm_gendisk, mk_kdev(MAJOR_NR, i<<MM_SHIFT), MM_SHIFT, &mm_fops, cards[i].mm_size << 1); @@ -1325,9 +1271,6 @@ void __exit mm_cleanup(void) unregister_blkdev(MAJOR_NR, "umem"); - for (i = 0; i < (num_cards << MM_SHIFT); i++) - invalidate_device (mk_kdev(MAJOR_NR,i), 1); - blk_size [MAJOR_NR] = NULL; /* diff --git a/drivers/block/xd.c b/drivers/block/xd.c index bca8cd457e0e..a1166a4e1394 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -122,7 +122,7 @@ static unsigned int xd_bases[] __initdata = }; static struct hd_struct xd_struct[XD_MAXDRIVES << 6]; -static int xd_sizes[XD_MAXDRIVES << 6], xd_access[XD_MAXDRIVES]; +static int xd_sizes[XD_MAXDRIVES << 6]; static spinlock_t xd_lock = SPIN_LOCK_UNLOCKED; @@ -140,12 +140,9 @@ static struct gendisk xd_gendisk = { static struct block_device_operations xd_fops = { owner: THIS_MODULE, open: xd_open, - release: xd_release, ioctl: xd_ioctl, }; static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int); -static DECLARE_WAIT_QUEUE_HEAD(xd_wait_open); -static u_char xd_valid[XD_MAXDRIVES] = { 0,0 }; static u_char xd_drives, xd_irq = 5, xd_dma = 3, xd_maxsectors; static u_char xd_override __initdata = 0, xd_type __initdata = 0; static u_short xd_iobase = 0x320; @@ -244,14 +241,11 @@ static void __init xd_geninit (void) /* xd_maxsectors depends on controller - so set after detection */ blk_queue_max_sectors(BLK_DEFAULT_QUEUE(MAJOR_NR), xd_maxsectors); - for (i = 0; i < xd_drives; i++) { - xd_valid[i] = 1; + for (i = 0; i < xd_drives; i++) register_disk(&xd_gendisk, mk_kdev(MAJOR_NR,i<<6), 1<<6, &xd_fops, xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors); - } - xd_gendisk.nr_real = xd_drives; } @@ -259,17 +253,9 @@ static void __init xd_geninit (void) static int xd_open (struct inode *inode,struct file *file) { int dev = DEVICE_NR(inode->i_rdev); - - if (dev < xd_drives) { - while (!xd_valid[dev]) - sleep_on(&xd_wait_open); - - xd_access[dev]++; - - return (0); - } - - return -ENXIO; + if (dev >= xd_drives) + return -ENXIO; + return 0; } /* do_xd_request: handle an incoming request */ @@ -329,7 +315,7 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) g.heads = xd_info[dev].heads; g.sectors = xd_info[dev].sectors; g.cylinders = xd_info[dev].cylinders; - g.start = get_start_sect(inode->i_rdev); + g.start = get_start_sect(inode->i_bdev); return copy_to_user(geometry, &g, sizeof g) ? -EFAULT : 0; } case HDIO_SET_DMA: @@ -351,50 +337,28 @@ static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) return -EACCES; return xd_reread_partitions(inode->i_rdev); - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKFLSBUF: - case BLKROSET: - case BLKROGET: - case BLKPG: - return blk_ioctl(inode->i_bdev, cmd, arg); - default: return -EINVAL; } } -/* xd_release: release the device */ -static int xd_release (struct inode *inode, struct file *file) -{ - int target = DEVICE_NR(inode->i_rdev); - if (target < xd_drives) - xd_access[target]--; - return 0; -} - /* xd_reread_partitions: rereads the partition table from a drive */ static int xd_reread_partitions(kdev_t dev) { - int target; - int res; + int target = DEVICE_NR(dev); + kdev_t device = mk_kdev(MAJOR_NR, target << 6); + int res = dev_lock_part(device); - target = DEVICE_NR(dev); - - cli(); - xd_valid[target] = (xd_access[target] != 1); - sti(); - if (xd_valid[target]) - return -EBUSY; + if (res < 0) + return 0; - res = wipe_partitions(dev); + res = wipe_partitions(device); if (!res) - grok_partitions(dev, xd_info[target].heads + grok_partitions(device, xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors); - xd_valid[target] = 1; - wake_up(&xd_wait_open); + dev_unlock_part(device); return res; } diff --git a/drivers/block/xd.h b/drivers/block/xd.h index 7babb59b96d0..3df2d4e98410 100644 --- a/drivers/block/xd.h +++ b/drivers/block/xd.h @@ -113,7 +113,6 @@ static void xd_geninit (void); static int xd_open (struct inode *inode,struct file *file); static void do_xd_request (request_queue_t * q); static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg); -static int xd_release (struct inode *inode,struct file *file); static int xd_reread_partitions (kdev_t dev); static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count); static void xd_recalibrate (u_char drive); diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 494aa03dc273..7b6dbbee9d95 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -1732,11 +1732,6 @@ int cdrom_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, because they fill up the sys log when CD players poll the drive. */ switch (cmd) { - case BLKROSET: - case BLKROGET: - case BLKFLSBUF: - case BLKSSZGET: - return blk_ioctl(ip->i_bdev, cmd, arg); case CDROMSUBCHNL: { struct cdrom_subchnl q; u_char requested, back; diff --git a/drivers/char/Config.in b/drivers/char/Config.in index ccce94f8fd26..a2489a9daf9b 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -8,25 +8,6 @@ bool 'Virtual terminal' CONFIG_VT if [ "$CONFIG_VT" = "y" ]; then bool ' Support for console on virtual terminal' CONFIG_VT_CONSOLE fi -tristate 'Standard/generic (8250/16550 and compatible UARTs) serial support' CONFIG_SERIAL -if [ "$CONFIG_SERIAL" = "y" ]; then - bool ' Support for console on serial port' CONFIG_SERIAL_CONSOLE - if [ "$CONFIG_ARCH_ACORN" = "y" ]; then - tristate ' Atomwide serial port support' CONFIG_ATOMWIDE_SERIAL - tristate ' Dual serial port support' CONFIG_DUALSP_SERIAL - fi -fi -if [ "$CONFIG_ACPI" = "y" -a "$CONFIG_IA64" = "y" ]; then - bool ' Support for serial ports defined by ACPI tables' CONFIG_SERIAL_ACPI -fi -dep_mbool 'Extended dumb serial driver options' CONFIG_SERIAL_EXTENDED $CONFIG_SERIAL -if [ "$CONFIG_SERIAL_EXTENDED" = "y" ]; then - bool ' Support more than 4 serial ports' CONFIG_SERIAL_MANY_PORTS - bool ' Support for sharing serial interrupts' CONFIG_SERIAL_SHARE_IRQ - bool ' Autodetect IRQ on standard ports (unsafe)' CONFIG_SERIAL_DETECT_IRQ - bool ' Support special multiport boards' CONFIG_SERIAL_MULTIPORT - bool ' Support the Bell Technologies HUB6 card' CONFIG_HUB6 -fi bool 'Non-standard serial port support' CONFIG_SERIAL_NONSTANDARD if [ "$CONFIG_SERIAL_NONSTANDARD" = "y" ]; then tristate ' Computone IntelliPort Plus serial support' CONFIG_COMPUTONE @@ -85,15 +66,9 @@ fi if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$CONFIG_ZORRO" = "y" ]; then tristate 'Commodore A2232 serial support (EXPERIMENTAL)' CONFIG_A2232 fi -if [ "$CONFIG_FOOTBRIDGE" = "y" ]; then - bool 'DC21285 serial port support' CONFIG_SERIAL_21285 - if [ "$CONFIG_SERIAL_21285" = "y" ]; then - if [ "$CONFIG_OBSOLETE" = "y" ]; then - bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD - fi - bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE - fi -fi + +source drivers/serial/Config.in + bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 07ed55ac10ad..650d9b6eb6de 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -13,20 +13,18 @@ obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. export-objs := busmouse.o console.o keyboard.o sysrq.o \ - misc.o pty.o random.o selection.o serial.o \ + misc.o pty.o random.o selection.o \ sonypi.o tty_io.o tty_ioctl.o generic_serial.o rtc.o \ ip2main.o KEYMAP =defkeymap.o KEYBD =pc_keyb.o CONSOLE =console.o -SERIAL =serial.o ifeq ($(ARCH),s390) KEYMAP = KEYBD = CONSOLE = - SERIAL = endif ifeq ($(ARCH),mips) @@ -39,7 +37,6 @@ ifeq ($(ARCH),s390x) KEYMAP = KEYBD = CONSOLE = - SERIAL = endif ifeq ($(ARCH),m68k) @@ -48,7 +45,6 @@ ifeq ($(ARCH),m68k) else KEYBD = endif - SERIAL = endif ifeq ($(ARCH),arm) @@ -96,15 +92,6 @@ endif ifeq ($(CONFIG_BAGET_MIPS),y) KEYBD = - SERIAL = -endif - -ifeq ($(CONFIG_NINO),y) - SERIAL = -endif - -ifneq ($(CONFIG_SUN_SERIAL),) - SERIAL = endif ifeq ($(CONFIG_QTRONIX_KEYBOARD),y) @@ -113,11 +100,7 @@ ifeq ($(CONFIG_QTRONIX_KEYBOARD),y) endif obj-$(CONFIG_VT) += vt.o vc_screen.o consolemap.o consolemap_deftbl.o $(CONSOLE) selection.o -obj-$(CONFIG_SERIAL) += $(SERIAL) -obj-$(CONFIG_SERIAL_ACPI) += acpi_serial.o -obj-$(CONFIG_SERIAL_21285) += serial_21285.o -obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o -obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o +#obj-$(CONFIG_SERIAL) += $(SERIAL) # Fix for decserial.o ifndef CONFIG_SUN_KEYBOARD obj-$(CONFIG_VT) += keyboard.o $(KEYMAP) $(KEYBD) diff --git a/drivers/char/acpi_serial.c b/drivers/char/acpi_serial.c deleted file mode 100644 index f0c7f188299f..000000000000 --- a/drivers/char/acpi_serial.c +++ /dev/null @@ -1,203 +0,0 @@ -/* - * linux/drivers/char/acpi_serial.c - * - * Copyright (C) 2000 Hewlett-Packard Co. - * Copyright (C) 2000 Khalid Aziz <khalid_aziz@hp.com> - * - * Detect and initialize the headless console serial port defined in - * SPCR table and debug serial port defined in DBGP table - * - */ -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/pm.h> -#include <linux/acpi.h> -#include <linux/init.h> -#include <linux/serial.h> -#include <asm/serial.h> -#include <asm/io.h> -#include <linux/acpi_serial.h> -/*#include <asm/acpi-ext.h>*/ - -#undef SERIAL_DEBUG_ACPI - -/* - * Query ACPI tables for a debug and a headless console serial - * port. If found, add them to rs_table[]. A pointer to either SPCR - * or DBGP table is passed as parameter. This function should be called - * before serial_console_init() is called to make sure the SPCR serial - * console will be available for use. IA-64 kernel calls this function - * from within acpi.c when it encounters SPCR or DBGP tables as it parses - * the ACPI 2.0 tables during bootup. - * - */ -void __init setup_serial_acpi(void *tablep) -{ - acpi_ser_t *acpi_ser_p; - struct serial_struct serial_req; - unsigned long iobase; - int global_sys_irq; - -#ifdef SERIAL_DEBUG_ACPI - printk("Entering setup_serial_acpi()\n"); -#endif - - /* Now get the table */ - if (tablep == NULL) { - return; - } - - acpi_ser_p = (acpi_ser_t *)tablep; - - /* - * Perform a sanity check on the table. Table should have a - * signature of "SPCR" or "DBGP" and it should be atleast 52 bytes - * long. - */ - if ((strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE, - ACPI_SIG_LEN) != 0) && - (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, - ACPI_SIG_LEN) != 0)) { - return; - } - if (acpi_ser_p->length < 52) { - return; - } - - iobase = (((u64) acpi_ser_p->base_addr.addrh) << 32) | acpi_ser_p->base_addr.addrl; - global_sys_irq = (acpi_ser_p->global_int[3] << 24) | - (acpi_ser_p->global_int[2] << 16) | - (acpi_ser_p->global_int[1] << 8) | - acpi_ser_p->global_int[0]; - -#ifdef SERIAL_DEBUG_ACPI - printk("setup_serial_acpi(): table pointer = 0x%p\n", acpi_ser_p); - printk(" sig = '%c%c%c%c'\n", - acpi_ser_p->signature[0], - acpi_ser_p->signature[1], - acpi_ser_p->signature[2], - acpi_ser_p->signature[3]); - printk(" length = %d\n", acpi_ser_p->length); - printk(" Rev = %d\n", acpi_ser_p->rev); - printk(" Interface type = %d\n", acpi_ser_p->intfc_type); - printk(" Base address = 0x%lX\n", iobase); - printk(" IRQ = %d\n", acpi_ser_p->irq); - printk(" Global System Int = %d\n", global_sys_irq); - printk(" Baud rate = "); - switch (acpi_ser_p->baud) { - case ACPI_SERIAL_BAUD_9600: - printk("9600\n"); - break; - - case ACPI_SERIAL_BAUD_19200: - printk("19200\n"); - break; - - case ACPI_SERIAL_BAUD_57600: - printk("57600\n"); - break; - - case ACPI_SERIAL_BAUD_115200: - printk("115200\n"); - break; - - default: - printk("Huh (%d)\n", acpi_ser_p->baud); - break; - - } - if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) { - printk(" PCI serial port:\n"); - printk(" Bus %d, Device %d, Vendor ID 0x%x, Dev ID 0x%x\n", - acpi_ser_p->pci_bus, acpi_ser_p->pci_dev, - acpi_ser_p->pci_vendor_id, acpi_ser_p->pci_dev_id); - } -#endif - - /* - * Now build a serial_req structure to update the entry in - * rs_table for the headless console port. - */ - switch (acpi_ser_p->intfc_type) { - case ACPI_SERIAL_INTFC_16550: - serial_req.type = PORT_16550; - serial_req.baud_base = BASE_BAUD; - break; - - case ACPI_SERIAL_INTFC_16450: - serial_req.type = PORT_16450; - serial_req.baud_base = BASE_BAUD; - break; - - default: - serial_req.type = PORT_UNKNOWN; - break; - } - if (strncmp(acpi_ser_p->signature, ACPI_SPCRT_SIGNATURE, - ACPI_SIG_LEN) == 0) { - serial_req.line = ACPI_SERIAL_CONSOLE_PORT; - } - else if (strncmp(acpi_ser_p->signature, ACPI_DBGPT_SIGNATURE, - ACPI_SIG_LEN) == 0) { - serial_req.line = ACPI_SERIAL_DEBUG_PORT; - } - /* - * Check if this is an I/O mapped address or a memory mapped address - */ - if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_MEM_SPACE) { - serial_req.port = 0; - serial_req.port_high = 0; - serial_req.iomem_base = (void *)ioremap(iobase, 64); - serial_req.io_type = SERIAL_IO_MEM; - } - else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_IO_SPACE) { - serial_req.port = (unsigned long) iobase & 0xffffffff; - serial_req.port_high = (unsigned long)(((u64)iobase) >> 32); - serial_req.iomem_base = NULL; - serial_req.io_type = SERIAL_IO_PORT; - } - else if (acpi_ser_p->base_addr.space_id == ACPI_SERIAL_PCICONF_SPACE) { - printk("WARNING: No support for PCI serial console\n"); - return; - } - - /* - * If the table does not have IRQ information, use 0 for IRQ. - * This will force rs_init() to probe for IRQ. - */ - if (acpi_ser_p->length < 53) { - serial_req.irq = 0; - } - else { - serial_req.flags = ASYNC_SKIP_TEST | ASYNC_BOOT_AUTOCONF | - ASYNC_AUTO_IRQ; - if (acpi_ser_p->int_type & - (ACPI_SERIAL_INT_APIC | ACPI_SERIAL_INT_SAPIC)) { - serial_req.irq = global_sys_irq; - } - else if (acpi_ser_p->int_type & ACPI_SERIAL_INT_PCAT) { - serial_req.irq = acpi_ser_p->irq; - } - else { - /* - * IRQ type not being set would mean UART will - * run in polling mode. Do not probe for IRQ in - * that case. - */ - serial_req.flags = ASYNC_SKIP_TEST|ASYNC_BOOT_AUTOCONF; - } - } - - serial_req.xmit_fifo_size = serial_req.custom_divisor = 0; - serial_req.close_delay = serial_req.hub6 = serial_req.closing_wait = 0; - serial_req.iomem_reg_shift = 0; - if (early_serial_setup(&serial_req) < 0) { - printk("early_serial_setup() for ACPI serial console port failed\n"); - return; - } - -#ifdef SERIAL_DEBUG_ACPI - printk("Leaving setup_serial_acpi()\n"); -#endif -} diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index d748d499da60..dc050fbf9baf 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -807,7 +807,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || I_PARMRK(tty)) { - cli(); + local_irq_disable(); // FIXME: is this safe? memset(tty->process_char_map, 0, 256/8); if (I_IGNCR(tty) || I_ICRNL(tty)) @@ -843,7 +843,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct termios * old) set_bit(SUSP_CHAR(tty), tty->process_char_map); } clear_bit(__DISABLED_CHAR, tty->process_char_map); - sti(); + local_irq_enable(); // FIXME: is this safe? tty->raw = 0; tty->real_raw = 0; } else { diff --git a/drivers/char/pcmcia/Config.in b/drivers/char/pcmcia/Config.in index 5905bd307d97..e44fa2a25ec8 100644 --- a/drivers/char/pcmcia/Config.in +++ b/drivers/char/pcmcia/Config.in @@ -5,7 +5,6 @@ mainmenu_option next_comment comment 'PCMCIA character devices' -dep_tristate 'PCMCIA serial device support' CONFIG_PCMCIA_SERIAL_CS $CONFIG_PCMCIA $CONFIG_SERIAL dep_tristate 'SyncLink PC Card support' CONFIG_SYNCLINK_CS $CONFIG_PCMCIA endmenu diff --git a/drivers/char/pcmcia/Makefile b/drivers/char/pcmcia/Makefile index 0b499b55814b..a1db3f706121 100644 --- a/drivers/char/pcmcia/Makefile +++ b/drivers/char/pcmcia/Makefile @@ -4,7 +4,6 @@ # Makefile for the Linux PCMCIA char device drivers. # -obj-$(CONFIG_PCMCIA_SERIAL_CS) += serial_cs.o obj-$(CONFIG_SYNCLINK_CS) += synclink_cs.o include $(TOPDIR)/Rules.make diff --git a/drivers/char/pcmcia/serial_cs.c b/drivers/char/pcmcia/serial_cs.c deleted file mode 100644 index 892f2c832a9e..000000000000 --- a/drivers/char/pcmcia/serial_cs.c +++ /dev/null @@ -1,667 +0,0 @@ -/*====================================================================== - - A driver for PCMCIA serial devices - - serial_cs.c 1.123 2000/08/24 18:46:38 - - The contents of this file are subject to the Mozilla Public - License Version 1.1 (the "License"); you may not use this file - except in compliance with the License. You may obtain a copy of - the License at http://www.mozilla.org/MPL/ - - Software distributed under the License is distributed on an "AS - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or - implied. See the License for the specific language governing - rights and limitations under the License. - - The initial developer of the original code is David A. Hinds - <dahinds@users.sourceforge.net>. Portions created by David A. Hinds - are Copyright (C) 1999 David A. Hinds. All Rights Reserved. - - Alternatively, the contents of this file may be used under the - terms of the GNU General Public License version 2 (the "GPL"), in which - case the provisions of the GPL are applicable instead of the - above. If you wish to allow the use of your version of this file - only under the terms of the GPL and not to allow others to use - your version of this file under the MPL, indicate your decision - by deleting the provisions above and replace them with the notice - and other provisions required by the GPL. If you do not delete - the provisions above, a recipient may use your version of this - file under either the MPL or the GPL. - -======================================================================*/ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/ptrace.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/tty.h> -#include <linux/serial.h> -#include <linux/major.h> -#include <asm/io.h> -#include <asm/system.h> - -#include <pcmcia/version.h> -#include <pcmcia/cs_types.h> -#include <pcmcia/cs.h> -#include <pcmcia/cistpl.h> -#include <pcmcia/ciscode.h> -#include <pcmcia/ds.h> -#include <pcmcia/cisreg.h> - -#ifdef PCMCIA_DEBUG -static int pc_debug = PCMCIA_DEBUG; -MODULE_PARM(pc_debug, "i"); -#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) -static char *version = -"serial_cs.c 1.123 2000/08/24 18:46:38 (David Hinds)"; -#else -#define DEBUG(n, args...) -#endif - -/*====================================================================*/ - -/* Parameters that can be set with 'insmod' */ - -/* Bit map of interrupts to choose from */ -static u_int irq_mask = 0xdeb8; -static int irq_list[4] = { -1 }; - -/* Enable the speaker? */ -static int do_sound = 1; - -MODULE_PARM(irq_mask, "i"); -MODULE_PARM(irq_list, "1-4i"); -MODULE_PARM(do_sound, "i"); - -/*====================================================================*/ - -/* Table of multi-port card ID's */ - -typedef struct { - u_short manfid; - u_short prodid; - int multi; /* 1 = multifunction, > 1 = # ports */ -} multi_id_t; - -static multi_id_t multi_id[] = { - { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 }, - { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 }, - { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 }, - { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 }, - { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 }, - { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 }, - { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 } -}; -#define MULTI_COUNT (sizeof(multi_id)/sizeof(multi_id_t)) - -typedef struct serial_info_t { - dev_link_t link; - int ndev; - int multi; - int slave; - int manfid; - dev_node_t node[4]; - int line[4]; -} serial_info_t; - -static void serial_config(dev_link_t *link); -static void serial_release(u_long arg); -static int serial_event(event_t event, int priority, - event_callback_args_t *args); - -static dev_info_t dev_info = "serial_cs"; - -static dev_link_t *serial_attach(void); -static void serial_detach(dev_link_t *); - -static dev_link_t *dev_list = NULL; - -/*====================================================================*/ - -static void cs_error(client_handle_t handle, int func, int ret) -{ - error_info_t err = { func, ret }; - CardServices(ReportError, handle, &err); -} - -/*====================================================================== - - serial_attach() creates an "instance" of the driver, allocating - local data structures for one device. The device is registered - with Card Services. - -======================================================================*/ - -static dev_link_t *serial_attach(void) -{ - serial_info_t *info; - client_reg_t client_reg; - dev_link_t *link; - int i, ret; - - DEBUG(0, "serial_attach()\n"); - - /* Create new serial device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) return NULL; - memset(info, 0, sizeof(*info)); - link = &info->link; link->priv = info; - - link->release.function = &serial_release; - link->release.data = (u_long)link; - link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; - link->io.NumPorts1 = 8; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; - if (irq_list[0] == -1) - link->irq.IRQInfo2 = irq_mask; - else - for (i = 0; i < 4; i++) - link->irq.IRQInfo2 |= 1 << irq_list[i]; - link->conf.Attributes = CONF_ENABLE_IRQ; - link->conf.Vcc = 50; - if (do_sound) { - link->conf.Attributes |= CONF_ENABLE_SPKR; - link->conf.Status = CCSR_AUDIO_ENA; - } - link->conf.IntType = INT_MEMORY_AND_IO; - - /* Register with Card Services */ - link->next = dev_list; - dev_list = link; - client_reg.dev_info = &dev_info; - client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; - client_reg.EventMask = - CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | - CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | - CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; - client_reg.event_handler = &serial_event; - client_reg.Version = 0x0210; - client_reg.event_callback_args.client_data = link; - ret = CardServices(RegisterClient, &link->handle, &client_reg); - if (ret != CS_SUCCESS) { - cs_error(link->handle, RegisterClient, ret); - serial_detach(link); - return NULL; - } - - return link; -} /* serial_attach */ - -/*====================================================================== - - This deletes a driver "instance". The device is de-registered - with Card Services. If it has been released, all local data - structures are freed. Otherwise, the structures will be freed - when the device is released. - -======================================================================*/ - -static void serial_detach(dev_link_t *link) -{ - serial_info_t *info = link->priv; - dev_link_t **linkp; - int ret; - - DEBUG(0, "serial_detach(0x%p)\n", link); - - /* Locate device structure */ - for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) - if (*linkp == link) break; - if (*linkp == NULL) - return; - - del_timer(&link->release); - if (link->state & DEV_CONFIG) - serial_release((u_long)link); - - if (link->handle) { - ret = CardServices(DeregisterClient, link->handle); - if (ret != CS_SUCCESS) - cs_error(link->handle, DeregisterClient, ret); - } - - /* Unlink device structure, free bits */ - *linkp = link->next; - kfree(info); - -} /* serial_detach */ - -/*====================================================================*/ - -static int setup_serial(serial_info_t *info, ioaddr_t port, int irq) -{ - struct serial_struct serial; - int line; - - memset(&serial, 0, sizeof(serial)); - serial.port = port; - serial.irq = irq; - serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ; - line = register_serial(&serial); - if (line < 0) { - printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx," - " irq %d failed\n", (u_long)serial.port, serial.irq); - return -1; - } - - info->line[info->ndev] = line; - sprintf(info->node[info->ndev].dev_name, "ttyS%d", line); - info->node[info->ndev].major = TTY_MAJOR; - info->node[info->ndev].minor = 0x40+line; - if (info->ndev > 0) - info->node[info->ndev-1].next = &info->node[info->ndev]; - info->ndev++; - - return 0; -} - -/*====================================================================*/ - -static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple, - cisparse_t *parse) -{ - int i; - i = CardServices(fn, handle, tuple); - if (i != CS_SUCCESS) return CS_NO_MORE_ITEMS; - i = CardServices(GetTupleData, handle, tuple); - if (i != CS_SUCCESS) return i; - return CardServices(ParseTuple, handle, tuple, parse); -} - -#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) -#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) - -/*====================================================================*/ - -static int simple_config(dev_link_t *link) -{ - static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; - client_handle_t handle = link->handle; - serial_info_t *info = link->priv; - tuple_t tuple; - u_char buf[256]; - cisparse_t parse; - cistpl_cftable_entry_t *cf = &parse.cftable_entry; - config_info_t config; - int i, j, try; - - /* If the card is already configured, look up the port and irq */ - i = CardServices(GetConfigurationInfo, handle, &config); - if ((i == CS_SUCCESS) && - (config.Attributes & CONF_VALID_CLIENT)) { - ioaddr_t port = 0; - if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) { - port = config.BasePort2; - info->slave = 1; - } else if ((info->manfid == MANFID_OSITECH) && - (config.NumPorts1 == 0x40)) { - port = config.BasePort1 + 0x28; - info->slave = 1; - } - if (info->slave) - return setup_serial(info, port, config.AssignedIRQ); - } - link->conf.Vcc = config.Vcc; - - /* First pass: look for a config entry that looks normal. */ - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleOffset = 0; tuple.TupleDataMax = 255; - tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - /* Two tries: without IO aliases, then with aliases */ - for (try = 0; try < 2; try++) { - i = first_tuple(handle, &tuple, &parse); - while (i != CS_NO_MORE_ITEMS) { - if (i != CS_SUCCESS) goto next_entry; - if (cf->vpp1.present & (1<<CISTPL_POWER_VNOM)) - link->conf.Vpp1 = link->conf.Vpp2 = - cf->vpp1.param[CISTPL_POWER_VNOM]/10000; - if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && - (cf->io.win[0].base != 0)) { - link->conf.ConfigIndex = cf->index; - link->io.BasePort1 = cf->io.win[0].base; - link->io.IOAddrLines = (try == 0) ? - 16 : cf->io.flags & CISTPL_IO_LINES_MASK; - i = CardServices(RequestIO, link->handle, &link->io); - if (i == CS_SUCCESS) goto found_port; - } - next_entry: - i = next_tuple(handle, &tuple, &parse); - } - } - - /* Second pass: try to find an entry that isn't picky about - its base address, then try to grab any standard serial port - address, and finally try to get any free port. */ - i = first_tuple(handle, &tuple, &parse); - while (i != CS_NO_MORE_ITEMS) { - if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && - ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { - link->conf.ConfigIndex = cf->index; - for (j = 0; j < 5; j++) { - link->io.BasePort1 = base[j]; - link->io.IOAddrLines = base[j] ? 16 : 3; - i = CardServices(RequestIO, link->handle, - &link->io); - if (i == CS_SUCCESS) goto found_port; - } - } - i = next_tuple(handle, &tuple, &parse); - } - -found_port: - if (i != CS_SUCCESS) { - printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); - cs_error(link->handle, RequestIO, i); - return -1; - } - - i = CardServices(RequestIRQ, link->handle, &link->irq); - if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIRQ, i); - link->irq.AssignedIRQ = 0; - } - if (info->multi && (info->manfid == MANFID_3COM)) - link->conf.ConfigIndex &= ~(0x08); - i = CardServices(RequestConfiguration, link->handle, &link->conf); - if (i != CS_SUCCESS) { - cs_error(link->handle, RequestConfiguration, i); - return -1; - } - - return setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); -} - -static int multi_config(dev_link_t *link) -{ - client_handle_t handle = link->handle; - serial_info_t *info = link->priv; - tuple_t tuple; - u_char buf[256]; - cisparse_t parse; - cistpl_cftable_entry_t *cf = &parse.cftable_entry; - int i, base2 = 0; - - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleOffset = 0; tuple.TupleDataMax = 255; - tuple.Attributes = 0; - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - - /* First, look for a generic full-sized window */ - link->io.NumPorts1 = info->multi * 8; - i = first_tuple(handle, &tuple, &parse); - while (i != CS_NO_MORE_ITEMS) { - /* The quad port cards have bad CIS's, so just look for a - window larger than 8 ports and assume it will be right */ - if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && - (cf->io.win[0].len > 8)) { - link->conf.ConfigIndex = cf->index; - link->io.BasePort1 = cf->io.win[0].base; - link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; - i = CardServices(RequestIO, link->handle, &link->io); - base2 = link->io.BasePort1 + 8; - if (i == CS_SUCCESS) break; - } - i = next_tuple(handle, &tuple, &parse); - } - - /* If that didn't work, look for two windows */ - if (i != CS_SUCCESS) { - link->io.NumPorts1 = link->io.NumPorts2 = 8; - info->multi = 2; - i = first_tuple(handle, &tuple, &parse); - while (i != CS_NO_MORE_ITEMS) { - if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) { - link->conf.ConfigIndex = cf->index; - link->io.BasePort1 = cf->io.win[0].base; - link->io.BasePort2 = cf->io.win[1].base; - link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK; - i = CardServices(RequestIO, link->handle, &link->io); - base2 = link->io.BasePort2; - if (i == CS_SUCCESS) break; - } - i = next_tuple(handle, &tuple, &parse); - } - } - - if (i != CS_SUCCESS) { - cs_error(link->handle, RequestIO, i); - return -1; - } - - i = CardServices(RequestIRQ, link->handle, &link->irq); - if (i != CS_SUCCESS) { - printk(KERN_NOTICE "serial_cs: no usable port range found, giving up\n"); - cs_error(link->handle, RequestIRQ, i); - link->irq.AssignedIRQ = 0; - } - /* Socket Dual IO: this enables irq's for second port */ - if (info->multi && (info->manfid == MANFID_SOCKET)) { - link->conf.Present |= PRESENT_EXT_STATUS; - link->conf.ExtStatus = ESR_REQ_ATTN_ENA; - } - i = CardServices(RequestConfiguration, link->handle, &link->conf); - if (i != CS_SUCCESS) { - cs_error(link->handle, RequestConfiguration, i); - return -1; - } - - setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); - /* The Nokia cards are not really multiport cards */ - if (info->manfid == MANFID_NOKIA) - return 0; - for (i = 0; i < info->multi-1; i++) - setup_serial(info, base2+(8*i), link->irq.AssignedIRQ); - - return 0; -} - -/*====================================================================== - - serial_config() is scheduled to run after a CARD_INSERTION event - is received, to configure the PCMCIA socket, and to make the - serial device available to the system. - -======================================================================*/ - -#define CS_CHECK(fn, args...) \ -while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed - -void serial_config(dev_link_t *link) -{ - client_handle_t handle = link->handle; - serial_info_t *info = link->priv; - tuple_t tuple; - u_short buf[128]; - cisparse_t parse; - cistpl_cftable_entry_t *cf = &parse.cftable_entry; - int i, last_ret, last_fn; - - DEBUG(0, "serial_config(0x%p)\n", link); - - tuple.TupleData = (cisdata_t *)buf; - tuple.TupleOffset = 0; tuple.TupleDataMax = 255; - tuple.Attributes = 0; - /* Get configuration register information */ - tuple.DesiredTuple = CISTPL_CONFIG; - last_ret = first_tuple(handle, &tuple, &parse); - if (last_ret != CS_SUCCESS) { - last_fn = ParseTuple; - goto cs_failed; - } - link->conf.ConfigBase = parse.config.base; - link->conf.Present = parse.config.rmask[0]; - - /* Configure card */ - link->state |= DEV_CONFIG; - - /* Is this a compliant multifunction card? */ - tuple.DesiredTuple = CISTPL_LONGLINK_MFC; - tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; - info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS); - - /* Is this a multiport card? */ - tuple.DesiredTuple = CISTPL_MANFID; - if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { - info->manfid = le16_to_cpu(buf[0]); - for (i = 0; i < MULTI_COUNT; i++) - if ((info->manfid == multi_id[i].manfid) && - (le16_to_cpu(buf[1]) == multi_id[i].prodid)) - break; - if (i < MULTI_COUNT) - info->multi = multi_id[i].multi; - } - - /* Another check for dual-serial cards: look for either serial or - multifunction cards that ask for appropriate IO port ranges */ - tuple.DesiredTuple = CISTPL_FUNCID; - if ((info->multi == 0) && - ((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) || - (parse.funcid.func == CISTPL_FUNCID_MULTI) || - (parse.funcid.func == CISTPL_FUNCID_SERIAL))) { - tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; - if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { - if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) - info->multi = cf->io.win[0].len >> 3; - if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && - (cf->io.win[1].len == 8)) - info->multi = 2; - } - } - - if (info->multi > 1) - multi_config(link); - else - simple_config(link); - - if (info->ndev == 0) - goto failed; - - if (info->manfid == MANFID_IBM) { - conf_reg_t reg = { 0, CS_READ, 0x800, 0 }; - CS_CHECK(AccessConfigurationRegister, link->handle, ®); - reg.Action = CS_WRITE; - reg.Value = reg.Value | 1; - CS_CHECK(AccessConfigurationRegister, link->handle, ®); - } - - link->dev = &info->node[0]; - link->state &= ~DEV_CONFIG_PENDING; - return; - -cs_failed: - cs_error(link->handle, last_fn, last_ret); -failed: - serial_release((u_long)link); - -} /* serial_config */ - -/*====================================================================== - - After a card is removed, serial_release() will unregister the net - device, and release the PCMCIA configuration. - -======================================================================*/ - -void serial_release(u_long arg) -{ - dev_link_t *link = (dev_link_t *)arg; - serial_info_t *info = link->priv; - int i; - - DEBUG(0, "serial_release(0x%p)\n", link); - - for (i = 0; i < info->ndev; i++) { - unregister_serial(info->line[i]); - } - link->dev = NULL; - - if (!info->slave) { - CardServices(ReleaseConfiguration, link->handle); - CardServices(ReleaseIO, link->handle, &link->io); - CardServices(ReleaseIRQ, link->handle, &link->irq); - } - - link->state &= ~DEV_CONFIG; - -} /* serial_release */ - -/*====================================================================== - - The card status event handler. Mostly, this schedules other - stuff to run after an event is received. A CARD_REMOVAL event - also sets some flags to discourage the serial drivers from - talking to the ports. - -======================================================================*/ - -static int serial_event(event_t event, int priority, - event_callback_args_t *args) -{ - dev_link_t *link = args->client_data; - serial_info_t *info = link->priv; - - DEBUG(1, "serial_event(0x%06x)\n", event); - - switch (event) { - case CS_EVENT_CARD_REMOVAL: - link->state &= ~DEV_PRESENT; - if (link->state & DEV_CONFIG) - mod_timer(&link->release, jiffies + HZ/20); - break; - case CS_EVENT_CARD_INSERTION: - link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; - serial_config(link); - break; - case CS_EVENT_PM_SUSPEND: - link->state |= DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_RESET_PHYSICAL: - if ((link->state & DEV_CONFIG) && !info->slave) - CardServices(ReleaseConfiguration, link->handle); - break; - case CS_EVENT_PM_RESUME: - link->state &= ~DEV_SUSPEND; - /* Fall through... */ - case CS_EVENT_CARD_RESET: - if (DEV_OK(link) && !info->slave) - CardServices(RequestConfiguration, link->handle, &link->conf); - break; - } - return 0; -} /* serial_event */ - -/*====================================================================*/ - -static int __init init_serial_cs(void) -{ - servinfo_t serv; - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "serial_cs: Card Services release " - "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &serial_attach, &serial_detach); - return 0; -} - -static void __exit exit_serial_cs(void) -{ - DEBUG(0, "serial_cs: unloading\n"); - unregister_pccard_driver(&dev_info); - while (dev_list != NULL) - serial_detach(dev_list); -} - -module_init(init_serial_cs); -module_exit(exit_serial_cs); - -MODULE_LICENSE("GPL"); diff --git a/drivers/char/serial.c b/drivers/char/serial.c deleted file mode 100644 index c3cd00f3caea..000000000000 --- a/drivers/char/serial.c +++ /dev/null @@ -1,6003 +0,0 @@ -/* - * linux/drivers/char/serial.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, - * 1998, 1999 Theodore Ts'o - * - * Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now - * much more extensible to support other serial cards based on the - * 16450/16550A UART's. Added support for the AST FourPort and the - * Accent Async board. - * - * set_serial_info fixed to set the flags, custom divisor, and uart - * type fields. Fix suggested by Michael K. Johnson 12/12/92. - * - * 11/95: TIOCMIWAIT, TIOCGICOUNT by Angelo Haritsis <ah@doc.ic.ac.uk> - * - * 03/96: Modularised by Angelo Haritsis <ah@doc.ic.ac.uk> - * - * rs_set_termios fixed to look also for changes of the input - * flags INPCK, BRKINT, PARMRK, IGNPAR and IGNBRK. - * Bernd Anhäupl 05/17/96. - * - * 1/97: Extended dumb serial ports are a config option now. - * Saves 4k. Michael A. Griffith <grif@acm.org> - * - * 8/97: Fix bug in rs_set_termios with RTS - * Stanislav V. Voronyi <stas@uanet.kharkov.ua> - * - * 3/98: Change the IRQ detection, use of probe_irq_o*(), - * suppress TIOCSERGWILD and TIOCSERSWILD - * Etienne Lorrain <etienne.lorrain@ibm.net> - * - * 4/98: Added changes to support the ARM architecture proposed by - * Russell King - * - * 5/99: Updated to include support for the XR16C850 and ST16C654 - * uarts. Stuart MacDonald <stuartm@connecttech.com> - * - * 8/99: Generalized PCI support added. Theodore Ts'o - * - * 3/00: Rid circular buffer of redundant xmit_cnt. Fix a - * few races on freeing buffers too. - * Alan Modra <alan@linuxcare.com> - * - * 5/00: Support for the RSA-DV II/S card added. - * Kiyokazu SUTO <suto@ks-and-ks.ne.jp> - * - * 6/00: Remove old-style timer, use timer_list - * Andrew Morton <andrewm@uow.edu.au> - * - * 7/00: Support Timedia/Sunix/Exsys PCI cards - * - * 7/00: fix some returns on failure not using MOD_DEC_USE_COUNT. - * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - * - * 10/00: add in optional software flow control for serial console. - * Kanoj Sarcar <kanoj@sgi.com> (Modified by Theodore Ts'o) - * - */ - -static char *serial_version = "5.05c"; -static char *serial_revdate = "2001-07-08"; - -/* - * Serial driver configuration section. Here are the various options: - * - * CONFIG_HUB6 - * Enables support for the venerable Bell Technologies - * HUB6 card. - * - * CONFIG_SERIAL_MANY_PORTS - * Enables support for ports beyond the standard, stupid - * COM 1/2/3/4. - * - * CONFIG_SERIAL_MULTIPORT - * Enables support for special multiport board support. - * - * CONFIG_SERIAL_SHARE_IRQ - * Enables support for multiple serial ports on one IRQ - * - * CONFIG_SERIAL_DETECT_IRQ - * Enable the autodetection of IRQ on standart ports - * - * SERIAL_PARANOIA_CHECK - * Check the magic number for the async_structure where - * ever possible. - * - * CONFIG_SERIAL_ACPI - * Enable support for serial console port and serial - * debug port as defined by the SPCR and DBGP tables in - * ACPI 2.0. - */ - -#include <linux/config.h> -#include <linux/version.h> - -#undef SERIAL_PARANOIA_CHECK -#define CONFIG_SERIAL_NOPAUSE_IO -#define SERIAL_DO_RESTART - -#if 0 -/* These defines are normally controlled by the autoconf.h */ -#define CONFIG_SERIAL_MANY_PORTS -#define CONFIG_SERIAL_SHARE_IRQ -#define CONFIG_SERIAL_DETECT_IRQ -#define CONFIG_SERIAL_MULTIPORT -#define CONFIG_HUB6 -#endif - -#ifdef CONFIG_PCI -#define ENABLE_SERIAL_PCI -#ifndef CONFIG_SERIAL_SHARE_IRQ -#define CONFIG_SERIAL_SHARE_IRQ -#endif -#ifndef CONFIG_SERIAL_MANY_PORTS -#define CONFIG_SERIAL_MANY_PORTS -#endif -#endif - -#ifdef CONFIG_SERIAL_ACPI -#define ENABLE_SERIAL_ACPI -#endif - - -/* Set of debugging defines */ - -#undef SERIAL_DEBUG_INTR -#undef SERIAL_DEBUG_OPEN -#undef SERIAL_DEBUG_FLOW -#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT -#undef SERIAL_DEBUG_PCI -#undef SERIAL_DEBUG_AUTOCONF - -/* Sanity checks */ - -#ifdef CONFIG_SERIAL_MULTIPORT -#ifndef CONFIG_SERIAL_SHARE_IRQ -#define CONFIG_SERIAL_SHARE_IRQ -#endif -#endif - -#ifdef CONFIG_HUB6 -#ifndef CONFIG_SERIAL_MANY_PORTS -#define CONFIG_SERIAL_MANY_PORTS -#endif -#ifndef CONFIG_SERIAL_SHARE_IRQ -#define CONFIG_SERIAL_SHARE_IRQ -#endif -#endif - -#ifdef MODULE -#undef CONFIG_SERIAL_CONSOLE -#endif - -#define CONFIG_SERIAL_RSA - -#define RS_STROBE_TIME (10*HZ) -#define RS_ISR_PASS_LIMIT 256 - -#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486)) -#define SERIAL_INLINE -#endif - -/* - * End of serial driver configuration section. - */ - -#include <linux/module.h> - -#include <linux/types.h> -#ifdef LOCAL_HEADERS -#include "serial_local.h" -#else -#include <linux/serial.h> -#include <linux/serialP.h> -#include <linux/serial_reg.h> -#include <asm/serial.h> -#define LOCAL_VERSTRING "" -#endif - -#include <linux/errno.h> -#include <linux/signal.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/ptrace.h> -#include <linux/ioport.h> -#include <linux/mm.h> -#include <linux/slab.h> -#if (LINUX_VERSION_CODE >= 131343) -#include <linux/init.h> -#endif -#if (LINUX_VERSION_CODE >= 131336) -#include <asm/uaccess.h> -#endif -#include <linux/delay.h> -#ifdef CONFIG_SERIAL_CONSOLE -#include <linux/console.h> -#endif -#ifdef ENABLE_SERIAL_PCI -#include <linux/pci.h> -#endif - -#include <linux/isapnp.h> -#ifdef __ISAPNP__ -#ifndef ENABLE_SERIAL_PNP -#define ENABLE_SERIAL_PNP -#endif -#endif - -#ifdef CONFIG_MAGIC_SYSRQ -#include <linux/sysrq.h> -#endif - -/* - * All of the compatibilty code so we can compile serial.c against - * older kernels is hidden in serial_compat.h - */ -#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */ -#include "serial_compat.h" -#endif - -#include <asm/system.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/bitops.h> - -#ifdef CONFIG_MAC_SERIAL -#define SERIAL_DEV_OFFSET 2 -#else -#define SERIAL_DEV_OFFSET 0 -#endif - -#ifdef SERIAL_INLINE -#define _INLINE_ inline -#else -#define _INLINE_ -#endif - -static char *serial_name = "Serial driver"; - -static DECLARE_TASK_QUEUE(tq_serial); - -static struct tty_driver serial_driver, callout_driver; -static int serial_refcount; - -static struct timer_list serial_timer; - -/* serial subtype definitions */ -#ifndef SERIAL_TYPE_NORMAL -#define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 -#endif - -/* number of characters left in xmit buffer before we ask for more */ -#define WAKEUP_CHARS 256 - -/* - * IRQ_timeout - How long the timeout should be for each IRQ - * should be after the IRQ has been active. - */ - -static struct async_struct *IRQ_ports[NR_IRQS]; -#ifdef CONFIG_SERIAL_MULTIPORT -static struct rs_multiport_struct rs_multiport[NR_IRQS]; -#endif -static int IRQ_timeout[NR_IRQS]; -#ifdef CONFIG_SERIAL_CONSOLE -static struct console sercons; -static int lsr_break_flag; -#endif -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -static unsigned long break_pressed; /* break, really ... */ -#endif - -static unsigned detect_uart_irq (struct serial_state * state); -static void autoconfig(struct serial_state * state); -static void change_speed(struct async_struct *info, struct termios *old); -static void rs_wait_until_sent(struct tty_struct *tty, int timeout); - -/* - * Here we define the default xmit fifo size used for each type of - * UART - */ -static struct serial_uart_config uart_config[] = { - { "unknown", 1, 0 }, - { "8250", 1, 0 }, - { "16450", 1, 0 }, - { "16550", 1, 0 }, - { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, - { "cirrus", 1, 0 }, /* usurped by cyclades.c */ - { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, - { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | - UART_STARTECH }, - { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO}, - { "Startech", 1, 0}, /* usurped by cyclades.c */ - { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO}, - { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | - UART_STARTECH }, - { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | - UART_STARTECH }, - { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO }, - { 0, 0} -}; - -#if defined(CONFIG_SERIAL_RSA) && defined(MODULE) - -#define PORT_RSA_MAX 4 -static int probe_rsa[PORT_RSA_MAX]; -static int force_rsa[PORT_RSA_MAX]; - -MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); -MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); -MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); -MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA"); -#endif /* CONFIG_SERIAL_RSA */ - -static struct serial_state rs_table[RS_TABLE_SIZE] = { - SERIAL_PORT_DFNS /* Defined in serial.h */ -}; - -#define NR_PORTS (sizeof(rs_table)/sizeof(struct serial_state)) - -#if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)) -#define NR_PCI_BOARDS 8 - -static struct pci_board_inst serial_pci_board[NR_PCI_BOARDS]; - -#ifndef IS_PCI_REGION_IOPORT -#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \ - IORESOURCE_IO) -#endif -#ifndef IS_PCI_REGION_IOMEM -#define IS_PCI_REGION_IOMEM(dev, r) (pci_resource_flags((dev), (r)) & \ - IORESOURCE_MEM) -#endif -#ifndef PCI_IRQ_RESOURCE -#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start) -#endif -#ifndef pci_get_subvendor -#define pci_get_subvendor(dev) ((dev)->subsystem_vendor) -#define pci_get_subdevice(dev) ((dev)->subsystem_device) -#endif -#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */ - -#ifndef PREPARE_FUNC -#define PREPARE_FUNC(dev) (dev->prepare) -#define ACTIVATE_FUNC(dev) (dev->activate) -#define DEACTIVATE_FUNC(dev) (dev->deactivate) -#endif - -#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) - -static struct tty_struct *serial_table[NR_PORTS]; -static struct termios *serial_termios[NR_PORTS]; -static struct termios *serial_termios_locked[NR_PORTS]; - - -#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) -#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ - kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s) -#else -#define DBG_CNT(s) -#endif - -/* - * tmp_buf is used as a temporary buffer by serial_write. We need to - * lock it in case the copy_from_user blocks while swapping in a page, - * and some other program tries to do a serial write at the same time. - * Since the lock will only come under contention when the system is - * swapping and available memory is low, it makes sense to share one - * buffer across all the serial ports, since it significantly saves - * memory if large numbers of serial ports are open. - */ -static unsigned char *tmp_buf; -#ifdef DECLARE_MUTEX -static DECLARE_MUTEX(tmp_buf_sem); -#else -static struct semaphore tmp_buf_sem = MUTEX; -#endif - - -static inline int serial_paranoia_check(struct async_struct *info, - kdev_t device, const char *routine) -{ -#ifdef SERIAL_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for serial struct (%s) in %s\n"; - static const char *badinfo = - "Warning: null async_struct for (%s) in %s\n"; - - if (!info) { - printk(badinfo, kdevname(device), routine); - return 1; - } - if (info->magic != SERIAL_MAGIC) { - printk(badmagic, kdevname(device), routine); - return 1; - } -#endif - return 0; -} - -static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset) -{ - switch (info->io_type) { -#ifdef CONFIG_HUB6 - case SERIAL_IO_HUB6: - outb(info->hub6 - 1 + offset, info->port); - return inb(info->port+1); -#endif - case SERIAL_IO_MEM: - return readb((unsigned long) info->iomem_base + - (offset<<info->iomem_reg_shift)); -#ifdef CONFIG_SERIAL_GSC - case SERIAL_IO_GSC: - return gsc_readb(info->iomem_base + offset); -#endif - default: - return inb(info->port + offset); - } -} - -static _INLINE_ void serial_out(struct async_struct *info, int offset, - int value) -{ - switch (info->io_type) { -#ifdef CONFIG_HUB6 - case SERIAL_IO_HUB6: - outb(info->hub6 - 1 + offset, info->port); - outb(value, info->port+1); - break; -#endif - case SERIAL_IO_MEM: - writeb(value, (unsigned long) info->iomem_base + - (offset<<info->iomem_reg_shift)); - break; -#ifdef CONFIG_SERIAL_GSC - case SERIAL_IO_GSC: - gsc_writeb(value, info->iomem_base + offset); - break; -#endif - default: - outb(value, info->port+offset); - } -} - -/* - * We used to support using pause I/O for certain machines. We - * haven't supported this for a while, but just in case it's badly - * needed for certain old 386 machines, I've left these #define's - * in.... - */ -#define serial_inp(info, offset) serial_in(info, offset) -#define serial_outp(info, offset, value) serial_out(info, offset, value) - - -/* - * For the 16C950 - */ -void serial_icr_write(struct async_struct *info, int offset, int value) -{ - serial_out(info, UART_SCR, offset); - serial_out(info, UART_ICR, value); -} - -unsigned int serial_icr_read(struct async_struct *info, int offset) -{ - int value; - - serial_icr_write(info, UART_ACR, info->ACR | UART_ACR_ICRRD); - serial_out(info, UART_SCR, offset); - value = serial_in(info, UART_ICR); - serial_icr_write(info, UART_ACR, info->ACR); - return value; -} - -/* - * ------------------------------------------------------------ - * rs_stop() and rs_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable transmitter interrupts, as necessary. - * ------------------------------------------------------------ - */ -static void rs_stop(struct tty_struct *tty) -{ - struct async_struct *info = (struct async_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "rs_stop")) - return; - - save_flags(flags); cli(); - if (info->IER & UART_IER_THRI) { - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } - if (info->state->type == PORT_16C950) { - info->ACR |= UART_ACR_TXDIS; - serial_icr_write(info, UART_ACR, info->ACR); - } - restore_flags(flags); -} - -static void rs_start(struct tty_struct *tty) -{ - struct async_struct *info = (struct async_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "rs_start")) - return; - - save_flags(flags); cli(); - if (info->xmit.head != info->xmit.tail - && info->xmit.buf - && !(info->IER & UART_IER_THRI)) { - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } - if (info->state->type == PORT_16C950) { - info->ACR &= ~UART_ACR_TXDIS; - serial_icr_write(info, UART_ACR, info->ACR); - } - restore_flags(flags); -} - -/* - * ---------------------------------------------------------------------- - * - * Here starts the interrupt handling routines. All of the following - * subroutines are declared as inline and are folded into - * rs_interrupt(). They were separated out for readability's sake. - * - * Note: rs_interrupt() is a "fast" interrupt, which means that it - * runs with interrupts turned off. People who may want to modify - * rs_interrupt() should try to keep the interrupt handler as fast as - * possible. After you are done making modifications, it is not a bad - * idea to do: - * - * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c - * - * and look at the resulting assemble code in serial.s. - * - * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 - * ----------------------------------------------------------------------- - */ - -/* - * This routine is used by the interrupt handler to schedule - * processing in the software interrupt portion of the driver. - */ -static _INLINE_ void rs_sched_event(struct async_struct *info, - int event) -{ - info->event |= 1 << event; - queue_task(&info->tqueue, &tq_serial); - mark_bh(SERIAL_BH); -} - -static _INLINE_ void receive_chars(struct async_struct *info, - int *status, struct pt_regs * regs) -{ - struct tty_struct *tty = info->tty; - unsigned char ch; - struct async_icount *icount; - int max_count = 256; - - icount = &info->state->icount; - do { - if (tty->flip.count >= TTY_FLIPBUF_SIZE) { - tty->flip.tqueue.routine((void *) tty); - if (tty->flip.count >= TTY_FLIPBUF_SIZE) - return; // if TTY_DONT_FLIP is set - } - ch = serial_inp(info, UART_RX); - *tty->flip.char_buf_ptr = ch; - icount->rx++; - -#ifdef SERIAL_DEBUG_INTR - printk("DR%02x:%02x...", ch, *status); -#endif - *tty->flip.flag_buf_ptr = 0; - if (*status & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE)) { - /* - * For statistics only - */ - if (*status & UART_LSR_BI) { - *status &= ~(UART_LSR_FE | UART_LSR_PE); - icount->brk++; - /* - * We do the SysRQ and SAK checking - * here because otherwise the break - * may get masked by ignore_status_mask - * or read_status_mask. - */ -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - if (info->line == sercons.index) { - if (!break_pressed) { - break_pressed = jiffies; - goto ignore_char; - } - break_pressed = 0; - } -#endif - if (info->flags & ASYNC_SAK) - do_SAK(tty); - } else if (*status & UART_LSR_PE) - icount->parity++; - else if (*status & UART_LSR_FE) - icount->frame++; - if (*status & UART_LSR_OE) - icount->overrun++; - - /* - * Mask off conditions which should be ignored. - */ - *status &= info->read_status_mask; - -#ifdef CONFIG_SERIAL_CONSOLE - if (info->line == sercons.index) { - /* Recover the break flag from console xmit */ - *status |= lsr_break_flag; - lsr_break_flag = 0; - } -#endif - if (*status & (UART_LSR_BI)) { -#ifdef SERIAL_DEBUG_INTR - printk("handling break...."); -#endif - *tty->flip.flag_buf_ptr = TTY_BREAK; - } else if (*status & UART_LSR_PE) - *tty->flip.flag_buf_ptr = TTY_PARITY; - else if (*status & UART_LSR_FE) - *tty->flip.flag_buf_ptr = TTY_FRAME; - } -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - if (break_pressed && info->line == sercons.index) { - if (ch != 0 && - time_before(jiffies, break_pressed + HZ*5)) { - handle_sysrq(ch, regs, NULL); - break_pressed = 0; - goto ignore_char; - } - break_pressed = 0; - } -#endif - if ((*status & info->ignore_status_mask) == 0) { - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - tty->flip.count++; - } - if ((*status & UART_LSR_OE) && - (tty->flip.count < TTY_FLIPBUF_SIZE)) { - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character - */ - *tty->flip.flag_buf_ptr = TTY_OVERRUN; - tty->flip.count++; - tty->flip.flag_buf_ptr++; - tty->flip.char_buf_ptr++; - } -#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) - ignore_char: -#endif - *status = serial_inp(info, UART_LSR); - } while ((*status & UART_LSR_DR) && (max_count-- > 0)); -#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */ - tty_flip_buffer_push(tty); -#else - queue_task_irq_off(&tty->flip.tqueue, &tq_timer); -#endif -} - -static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done) -{ - int count; - - if (info->x_char) { - serial_outp(info, UART_TX, info->x_char); - info->state->icount.tx++; - info->x_char = 0; - if (intr_done) - *intr_done = 0; - return; - } - if (info->xmit.head == info->xmit.tail - || info->tty->stopped - || info->tty->hw_stopped) { - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - return; - } - - count = info->xmit_fifo_size; - do { - serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]); - info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1); - info->state->icount.tx++; - if (info->xmit.head == info->xmit.tail) - break; - } while (--count > 0); - - if (CIRC_CNT(info->xmit.head, - info->xmit.tail, - SERIAL_XMIT_SIZE) < WAKEUP_CHARS) - rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); - -#ifdef SERIAL_DEBUG_INTR - printk("THRE..."); -#endif - if (intr_done) - *intr_done = 0; - - if (info->xmit.head == info->xmit.tail) { - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } -} - -static _INLINE_ void check_modem_status(struct async_struct *info) -{ - int status; - struct async_icount *icount; - - status = serial_in(info, UART_MSR); - - if (status & UART_MSR_ANY_DELTA) { - icount = &info->state->icount; - /* update input line counters */ - if (status & UART_MSR_TERI) - icount->rng++; - if (status & UART_MSR_DDSR) - icount->dsr++; - if (status & UART_MSR_DDCD) { - icount->dcd++; -#ifdef CONFIG_HARD_PPS - if ((info->flags & ASYNC_HARDPPS_CD) && - (status & UART_MSR_DCD)) - hardpps(); -#endif - } - if (status & UART_MSR_DCTS) - icount->cts++; - wake_up_interruptible(&info->delta_msr_wait); - } - - if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { -#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) - printk("ttys%d CD now %s...", info->line, - (status & UART_MSR_DCD) ? "on" : "off"); -#endif - if (status & UART_MSR_DCD) - wake_up_interruptible(&info->open_wait); - else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) { -#ifdef SERIAL_DEBUG_OPEN - printk("doing serial hangup..."); -#endif - if (info->tty) - tty_hangup(info->tty); - } - } - if (info->flags & ASYNC_CTS_FLOW) { - if (info->tty->hw_stopped) { - if (status & UART_MSR_CTS) { -#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) - printk("CTS tx start..."); -#endif - info->tty->hw_stopped = 0; - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); - return; - } - } else { - if (!(status & UART_MSR_CTS)) { -#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW)) - printk("CTS tx stop..."); -#endif - info->tty->hw_stopped = 1; - info->IER &= ~UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } - } - } -} - -#ifdef CONFIG_SERIAL_SHARE_IRQ -/* - * This is the serial driver's generic interrupt routine - */ -static void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) -{ - int status; - struct async_struct * info; - int pass_counter = 0; - struct async_struct *end_mark = 0; -#ifdef CONFIG_SERIAL_MULTIPORT - int first_multi = 0; - struct rs_multiport_struct *multi; -#endif - -#ifdef SERIAL_DEBUG_INTR - printk("rs_interrupt(%d)...", irq); -#endif - - info = IRQ_ports[irq]; - if (!info) - return; - -#ifdef CONFIG_SERIAL_MULTIPORT - multi = &rs_multiport[irq]; - if (multi->port_monitor) - first_multi = inb(multi->port_monitor); -#endif - - do { - if (!info->tty || - (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) { - if (!end_mark) - end_mark = info; - goto next; - } -#ifdef SERIAL_DEBUG_INTR - printk("IIR = %x...", serial_in(info, UART_IIR)); -#endif - end_mark = 0; - - info->last_active = jiffies; - - status = serial_inp(info, UART_LSR); -#ifdef SERIAL_DEBUG_INTR - printk("status = %x...", status); -#endif - if (status & UART_LSR_DR) - receive_chars(info, &status, regs); - check_modem_status(info); - if (status & UART_LSR_THRE) - transmit_chars(info, 0); - - next: - info = info->next_port; - if (!info) { - info = IRQ_ports[irq]; - if (pass_counter++ > RS_ISR_PASS_LIMIT) { -#if 0 - printk("rs loop break\n"); -#endif - break; /* Prevent infinite loops */ - } - continue; - } - } while (end_mark != info); -#ifdef CONFIG_SERIAL_MULTIPORT - if (multi->port_monitor) - printk("rs port monitor (normal) irq %d: 0x%x, 0x%x\n", - info->state->irq, first_multi, - inb(multi->port_monitor)); -#endif -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} -#endif /* #ifdef CONFIG_SERIAL_SHARE_IRQ */ - - -/* - * This is the serial driver's interrupt routine for a single port - */ -static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs) -{ - int status; - int pass_counter = 0; - struct async_struct * info; -#ifdef CONFIG_SERIAL_MULTIPORT - int first_multi = 0; - struct rs_multiport_struct *multi; -#endif - -#ifdef SERIAL_DEBUG_INTR - printk("rs_interrupt_single(%d)...", irq); -#endif - - info = IRQ_ports[irq]; - if (!info || !info->tty) - return; - -#ifdef CONFIG_SERIAL_MULTIPORT - multi = &rs_multiport[irq]; - if (multi->port_monitor) - first_multi = inb(multi->port_monitor); -#endif - - do { - status = serial_inp(info, UART_LSR); -#ifdef SERIAL_DEBUG_INTR - printk("status = %x...", status); -#endif - if (status & UART_LSR_DR) - receive_chars(info, &status, regs); - check_modem_status(info); - if (status & UART_LSR_THRE) - transmit_chars(info, 0); - if (pass_counter++ > RS_ISR_PASS_LIMIT) { -#if 0 - printk("rs_single loop break.\n"); -#endif - break; - } -#ifdef SERIAL_DEBUG_INTR - printk("IIR = %x...", serial_in(info, UART_IIR)); -#endif - } while (!(serial_in(info, UART_IIR) & UART_IIR_NO_INT)); - info->last_active = jiffies; -#ifdef CONFIG_SERIAL_MULTIPORT - if (multi->port_monitor) - printk("rs port monitor (single) irq %d: 0x%x, 0x%x\n", - info->state->irq, first_multi, - inb(multi->port_monitor)); -#endif -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} - -#ifdef CONFIG_SERIAL_MULTIPORT -/* - * This is the serial driver's for multiport boards - */ -static void rs_interrupt_multi(int irq, void *dev_id, struct pt_regs * regs) -{ - int status; - struct async_struct * info; - int pass_counter = 0; - int first_multi= 0; - struct rs_multiport_struct *multi; - -#ifdef SERIAL_DEBUG_INTR - printk("rs_interrupt_multi(%d)...", irq); -#endif - - info = IRQ_ports[irq]; - if (!info) - return; - multi = &rs_multiport[irq]; - if (!multi->port1) { - /* Should never happen */ - printk("rs_interrupt_multi: NULL port1!\n"); - return; - } - if (multi->port_monitor) - first_multi = inb(multi->port_monitor); - - while (1) { - if (!info->tty || - (serial_in(info, UART_IIR) & UART_IIR_NO_INT)) - goto next; - - info->last_active = jiffies; - - status = serial_inp(info, UART_LSR); -#ifdef SERIAL_DEBUG_INTR - printk("status = %x...", status); -#endif - if (status & UART_LSR_DR) - receive_chars(info, &status, regs); - check_modem_status(info); - if (status & UART_LSR_THRE) - transmit_chars(info, 0); - - next: - info = info->next_port; - if (info) - continue; - - info = IRQ_ports[irq]; - /* - * The user was a bonehead, and misconfigured their - * multiport info. Rather than lock up the kernel - * in an infinite loop, if we loop too many times, - * print a message and break out of the loop. - */ - if (pass_counter++ > RS_ISR_PASS_LIMIT) { - printk("Misconfigured multiport serial info " - "for irq %d. Breaking out irq loop\n", irq); - break; - } - if (multi->port_monitor) - printk("rs port monitor irq %d: 0x%x, 0x%x\n", - info->state->irq, first_multi, - inb(multi->port_monitor)); - if ((inb(multi->port1) & multi->mask1) != multi->match1) - continue; - if (!multi->port2) - break; - if ((inb(multi->port2) & multi->mask2) != multi->match2) - continue; - if (!multi->port3) - break; - if ((inb(multi->port3) & multi->mask3) != multi->match3) - continue; - if (!multi->port4) - break; - if ((inb(multi->port4) & multi->mask4) != multi->match4) - continue; - break; - } -#ifdef SERIAL_DEBUG_INTR - printk("end.\n"); -#endif -} -#endif - -/* - * ------------------------------------------------------------------- - * Here ends the serial interrupt routines. - * ------------------------------------------------------------------- - */ - -/* - * This routine is used to handle the "bottom half" processing for the - * serial driver, known also the "software interrupt" processing. - * This processing is done at the kernel interrupt level, after the - * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This - * is where time-consuming activities which can not be done in the - * interrupt driver proper are done; the interrupt driver schedules - * them using rs_sched_event(), and they get done here. - */ -static void do_serial_bh(void) -{ - run_task_queue(&tq_serial); -} - -static void do_softint(void *private_) -{ - struct async_struct *info = (struct async_struct *) private_; - struct tty_struct *tty; - - tty = info->tty; - if (!tty) - return; - - if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - wake_up_interruptible(&tty->write_wait); -#ifdef SERIAL_HAVE_POLL_WAIT - wake_up_interruptible(&tty->poll_wait); -#endif - } -} - -/* - * This subroutine is called when the RS_TIMER goes off. It is used - * by the serial driver to handle ports that do not have an interrupt - * (irq=0). This doesn't work very well for 16450's, but gives barely - * passable results for a 16550A. (Although at the expense of much - * CPU overhead). - */ -static void rs_timer(unsigned long dummy) -{ - static unsigned long last_strobe; - struct async_struct *info; - unsigned int i; - unsigned long flags; - - if ((jiffies - last_strobe) >= RS_STROBE_TIME) { - for (i=0; i < NR_IRQS; i++) { - info = IRQ_ports[i]; - if (!info) - continue; - save_flags(flags); cli(); -#ifdef CONFIG_SERIAL_SHARE_IRQ - if (info->next_port) { - do { - serial_out(info, UART_IER, 0); - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - info = info->next_port; - } while (info); -#ifdef CONFIG_SERIAL_MULTIPORT - if (rs_multiport[i].port1) - rs_interrupt_multi(i, NULL, NULL); - else -#endif - rs_interrupt(i, NULL, NULL); - } else -#endif /* CONFIG_SERIAL_SHARE_IRQ */ - rs_interrupt_single(i, NULL, NULL); - restore_flags(flags); - } - } - last_strobe = jiffies; - mod_timer(&serial_timer, jiffies + RS_STROBE_TIME); - - if (IRQ_ports[0]) { - save_flags(flags); cli(); -#ifdef CONFIG_SERIAL_SHARE_IRQ - rs_interrupt(0, NULL, NULL); -#else - rs_interrupt_single(0, NULL, NULL); -#endif - restore_flags(flags); - - mod_timer(&serial_timer, jiffies + IRQ_timeout[0]); - } -} - -/* - * --------------------------------------------------------------- - * Low level utility subroutines for the serial driver: routines to - * figure out the appropriate timeout for an interrupt chain, routines - * to initialize and startup a serial port, and routines to shutdown a - * serial port. Useful stuff like that. - * --------------------------------------------------------------- - */ - -/* - * This routine figures out the correct timeout for a particular IRQ. - * It uses the smallest timeout of all of the serial ports in a - * particular interrupt chain. Now only used for IRQ 0.... - */ -static void figure_IRQ_timeout(int irq) -{ - struct async_struct *info; - int timeout = 60*HZ; /* 60 seconds === a long time :-) */ - - info = IRQ_ports[irq]; - if (!info) { - IRQ_timeout[irq] = 60*HZ; - return; - } - while (info) { - if (info->timeout < timeout) - timeout = info->timeout; - info = info->next_port; - } - if (!irq) - timeout = timeout / 2; - IRQ_timeout[irq] = (timeout > 3) ? timeout-2 : 1; -} - -#ifdef CONFIG_SERIAL_RSA -/* Attempts to turn on the RSA FIFO. Returns zero on failure */ -static int enable_rsa(struct async_struct *info) -{ - unsigned char mode; - int result; - unsigned long flags; - - save_flags(flags); cli(); - mode = serial_inp(info, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - - if (!result) { - serial_outp(info, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); - mode = serial_inp(info, UART_RSA_MSR); - result = mode & UART_RSA_MSR_FIFO; - } - - restore_flags(flags); - return result; -} - -/* Attempts to turn off the RSA FIFO. Returns zero on failure */ -static int disable_rsa(struct async_struct *info) -{ - unsigned char mode; - int result; - unsigned long flags; - - save_flags(flags); cli(); - mode = serial_inp(info, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - - if (!result) { - serial_outp(info, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); - mode = serial_inp(info, UART_RSA_MSR); - result = !(mode & UART_RSA_MSR_FIFO); - } - - restore_flags(flags); - return result; -} -#endif /* CONFIG_SERIAL_RSA */ - -static int startup(struct async_struct * info) -{ - unsigned long flags; - int retval=0; - void (*handler)(int, void *, struct pt_regs *); - struct serial_state *state= info->state; - unsigned long page; -#ifdef CONFIG_SERIAL_MANY_PORTS - unsigned short ICP; -#endif - - page = get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - - save_flags(flags); cli(); - - if (info->flags & ASYNC_INITIALIZED) { - free_page(page); - goto errout; - } - - if (!CONFIGURED_SERIAL_PORT(state) || !state->type) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - free_page(page); - goto errout; - } - if (info->xmit.buf) - free_page(page); - else - info->xmit.buf = (unsigned char *) page; - -#ifdef SERIAL_DEBUG_OPEN - printk("starting up ttys%d (irq %d)...", info->line, state->irq); -#endif - - if (uart_config[state->type].flags & UART_STARTECH) { - /* Wake up UART */ - serial_outp(info, UART_LCR, 0xBF); - serial_outp(info, UART_EFR, UART_EFR_ECB); - /* - * Turn off LCR == 0xBF so we actually set the IER - * register on the XR16C850 - */ - serial_outp(info, UART_LCR, 0); - serial_outp(info, UART_IER, 0); - /* - * Now reset LCR so we can turn off the ECB bit - */ - serial_outp(info, UART_LCR, 0xBF); - serial_outp(info, UART_EFR, 0); - /* - * For a XR16C850, we need to set the trigger levels - */ - if (state->type == PORT_16850) { - serial_outp(info, UART_FCTR, UART_FCTR_TRGD | - UART_FCTR_RX); - serial_outp(info, UART_TRG, UART_TRG_96); - serial_outp(info, UART_FCTR, UART_FCTR_TRGD | - UART_FCTR_TX); - serial_outp(info, UART_TRG, UART_TRG_96); - } - serial_outp(info, UART_LCR, 0); - } - - if (state->type == PORT_16750) { - /* Wake up UART */ - serial_outp(info, UART_IER, 0); - } - - if (state->type == PORT_16C950) { - /* Wake up and initialize UART */ - info->ACR = 0; - serial_outp(info, UART_LCR, 0xBF); - serial_outp(info, UART_EFR, UART_EFR_ECB); - serial_outp(info, UART_IER, 0); - serial_outp(info, UART_LCR, 0); - serial_icr_write(info, UART_CSR, 0); /* Reset the UART */ - serial_outp(info, UART_LCR, 0xBF); - serial_outp(info, UART_EFR, UART_EFR_ECB); - serial_outp(info, UART_LCR, 0); - } - -#ifdef CONFIG_SERIAL_RSA - /* - * If this is an RSA port, see if we can kick it up to the - * higher speed clock. - */ - if (state->type == PORT_RSA) { - if (state->baud_base != SERIAL_RSA_BAUD_BASE && - enable_rsa(info)) - state->baud_base = SERIAL_RSA_BAUD_BASE; - if (state->baud_base == SERIAL_RSA_BAUD_BASE) - serial_outp(info, UART_RSA_FRR, 0); - } -#endif - - /* - * Clear the FIFO buffers and disable them - * (they will be reenabled in change_speed()) - */ - if (uart_config[state->type].flags & UART_CLEAR_FIFO) { - serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT)); - serial_outp(info, UART_FCR, 0); - } - - /* - * Clear the interrupt registers. - */ - (void) serial_inp(info, UART_LSR); - (void) serial_inp(info, UART_RX); - (void) serial_inp(info, UART_IIR); - (void) serial_inp(info, UART_MSR); - - /* - * At this point there's no way the LSR could still be 0xFF; - * if it is, then bail out, because there's likely no UART - * here. - */ - if (!(info->flags & ASYNC_BUGGY_UART) && - (serial_inp(info, UART_LSR) == 0xff)) { - printk("ttyS%d: LSR safety check engaged!\n", state->line); - if (capable(CAP_SYS_ADMIN)) { - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - } else - retval = -ENODEV; - goto errout; - } - - /* - * Allocate the IRQ if necessary - */ - if (state->irq && (!IRQ_ports[state->irq] || - !IRQ_ports[state->irq]->next_port)) { - if (IRQ_ports[state->irq]) { -#ifdef CONFIG_SERIAL_SHARE_IRQ - free_irq(state->irq, &IRQ_ports[state->irq]); -#ifdef CONFIG_SERIAL_MULTIPORT - if (rs_multiport[state->irq].port1) - handler = rs_interrupt_multi; - else -#endif - handler = rs_interrupt; -#else - retval = -EBUSY; - goto errout; -#endif /* CONFIG_SERIAL_SHARE_IRQ */ - } else - handler = rs_interrupt_single; - - retval = request_irq(state->irq, handler, SA_SHIRQ, - "serial", &IRQ_ports[state->irq]); - if (retval) { - if (capable(CAP_SYS_ADMIN)) { - if (info->tty) - set_bit(TTY_IO_ERROR, - &info->tty->flags); - retval = 0; - } - goto errout; - } - } - - /* - * Insert serial port into IRQ chain. - */ - info->prev_port = 0; - info->next_port = IRQ_ports[state->irq]; - if (info->next_port) - info->next_port->prev_port = info; - IRQ_ports[state->irq] = info; - figure_IRQ_timeout(state->irq); - - /* - * Now, initialize the UART - */ - serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ - - info->MCR = 0; - if (info->tty->termios->c_cflag & CBAUD) - info->MCR = UART_MCR_DTR | UART_MCR_RTS; -#ifdef CONFIG_SERIAL_MANY_PORTS - if (info->flags & ASYNC_FOURPORT) { - if (state->irq == 0) - info->MCR |= UART_MCR_OUT1; - } else -#endif - { - if (state->irq != 0) - info->MCR |= UART_MCR_OUT2; - } - info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ - serial_outp(info, UART_MCR, info->MCR); - - /* - * Finally, enable interrupts - */ - info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; - serial_outp(info, UART_IER, info->IER); /* enable interrupts */ - -#ifdef CONFIG_SERIAL_MANY_PORTS - if (info->flags & ASYNC_FOURPORT) { - /* Enable interrupts on the AST Fourport board */ - ICP = (info->port & 0xFE0) | 0x01F; - outb_p(0x80, ICP); - (void) inb_p(ICP); - } -#endif - - /* - * And clear the interrupt registers again for luck. - */ - (void)serial_inp(info, UART_LSR); - (void)serial_inp(info, UART_RX); - (void)serial_inp(info, UART_IIR); - (void)serial_inp(info, UART_MSR); - - if (info->tty) - clear_bit(TTY_IO_ERROR, &info->tty->flags); - info->xmit.head = info->xmit.tail = 0; - - /* - * Set up serial timers... - */ - mod_timer(&serial_timer, jiffies + 2*HZ/100); - - /* - * Set up the tty->alt_speed kludge - */ -#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ - if (info->tty) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - info->tty->alt_speed = 57600; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - info->tty->alt_speed = 115200; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - info->tty->alt_speed = 230400; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - info->tty->alt_speed = 460800; - } -#endif - - /* - * and set the speed of the serial port - */ - change_speed(info, 0); - - info->flags |= ASYNC_INITIALIZED; - restore_flags(flags); - return 0; - -errout: - restore_flags(flags); - return retval; -} - -/* - * This routine will shutdown a serial port; interrupts are disabled, and - * DTR is dropped if the hangup on close termio flag is on. - */ -static void shutdown(struct async_struct * info) -{ - unsigned long flags; - struct serial_state *state; - int retval; - - if (!(info->flags & ASYNC_INITIALIZED)) - return; - - state = info->state; - -#ifdef SERIAL_DEBUG_OPEN - printk("Shutting down serial port %d (irq %d)....", info->line, - state->irq); -#endif - - save_flags(flags); cli(); /* Disable interrupts */ - - /* - * clear delta_msr_wait queue to avoid mem leaks: we may free the irq - * here so the queue might never be waken up - */ - wake_up_interruptible(&info->delta_msr_wait); - - /* - * First unlink the serial port from the IRQ chain... - */ - if (info->next_port) - info->next_port->prev_port = info->prev_port; - if (info->prev_port) - info->prev_port->next_port = info->next_port; - else - IRQ_ports[state->irq] = info->next_port; - figure_IRQ_timeout(state->irq); - - /* - * Free the IRQ, if necessary - */ - if (state->irq && (!IRQ_ports[state->irq] || - !IRQ_ports[state->irq]->next_port)) { - if (IRQ_ports[state->irq]) { - free_irq(state->irq, &IRQ_ports[state->irq]); - retval = request_irq(state->irq, rs_interrupt_single, - SA_SHIRQ, "serial", - &IRQ_ports[state->irq]); - - if (retval) - printk("serial shutdown: request_irq: error %d" - " Couldn't reacquire IRQ.\n", retval); - } else - free_irq(state->irq, &IRQ_ports[state->irq]); - } - - if (info->xmit.buf) { - unsigned long pg = (unsigned long) info->xmit.buf; - info->xmit.buf = 0; - free_page(pg); - } - - info->IER = 0; - serial_outp(info, UART_IER, 0x00); /* disable all intrs */ -#ifdef CONFIG_SERIAL_MANY_PORTS - if (info->flags & ASYNC_FOURPORT) { - /* reset interrupts on the AST Fourport board */ - (void) inb((info->port & 0xFE0) | 0x01F); - info->MCR |= UART_MCR_OUT1; - } else -#endif - info->MCR &= ~UART_MCR_OUT2; - info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ - - /* disable break condition */ - serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC); - - if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) - info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); - serial_outp(info, UART_MCR, info->MCR); - - /* disable FIFO's */ - serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT)); - serial_outp(info, UART_FCR, 0); - -#ifdef CONFIG_SERIAL_RSA - /* - * Reset the RSA board back to 115kbps compat mode. - */ - if ((state->type == PORT_RSA) && - (state->baud_base == SERIAL_RSA_BAUD_BASE && - disable_rsa(info))) - state->baud_base = SERIAL_RSA_BAUD_BASE_LO; -#endif - - - (void)serial_in(info, UART_RX); /* read data port to reset things */ - - if (info->tty) - set_bit(TTY_IO_ERROR, &info->tty->flags); - - if (uart_config[info->state->type].flags & UART_STARTECH) { - /* Arrange to enter sleep mode */ - serial_outp(info, UART_LCR, 0xBF); - serial_outp(info, UART_EFR, UART_EFR_ECB); - serial_outp(info, UART_LCR, 0); - serial_outp(info, UART_IER, UART_IERX_SLEEP); - serial_outp(info, UART_LCR, 0xBF); - serial_outp(info, UART_EFR, 0); - serial_outp(info, UART_LCR, 0); - } - if (info->state->type == PORT_16750) { - /* Arrange to enter sleep mode */ - serial_outp(info, UART_IER, UART_IERX_SLEEP); - } - info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); -} - -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ -static int baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, - 600, 1200, 1800, 2400, 4800, 9600, 19200, - 38400, 57600, 115200, 230400, 460800, 0 }; - -static int tty_get_baud_rate(struct tty_struct *tty) -{ - struct async_struct * info = (struct async_struct *)tty->driver_data; - unsigned int cflag, i; - - cflag = tty->termios->c_cflag; - - i = cflag & CBAUD; - if (i & CBAUDEX) { - i &= ~CBAUDEX; - if (i < 1 || i > 2) - tty->termios->c_cflag &= ~CBAUDEX; - else - i += 15; - } - if (i == 15) { - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - i += 1; - if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - i += 2; - } - return baud_table[i]; -} -#endif - -/* - * This routine is called to set the UART divisor registers to match - * the specified baud rate for a serial port. - */ -static void change_speed(struct async_struct *info, - struct termios *old_termios) -{ - int quot = 0, baud_base, baud; - unsigned cflag, cval, fcr = 0; - int bits; - unsigned long flags; - - if (!info->tty || !info->tty->termios) - return; - cflag = info->tty->termios->c_cflag; - if (!CONFIGURED_SERIAL_PORT(info)) - return; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS5: cval = 0x00; bits = 7; break; - case CS6: cval = 0x01; bits = 8; break; - case CS7: cval = 0x02; bits = 9; break; - case CS8: cval = 0x03; bits = 10; break; - /* Never happens, but GCC is too dumb to figure it out */ - default: cval = 0x00; bits = 7; break; - } - if (cflag & CSTOPB) { - cval |= 0x04; - bits++; - } - if (cflag & PARENB) { - cval |= UART_LCR_PARITY; - bits++; - } - if (!(cflag & PARODD)) - cval |= UART_LCR_EPAR; -#ifdef CMSPAR - if (cflag & CMSPAR) - cval |= UART_LCR_SPAR; -#endif - - /* Determine divisor based on baud rate */ - baud = tty_get_baud_rate(info->tty); - if (!baud) - baud = 9600; /* B0 transition handled in rs_set_termios */ -#ifdef CONFIG_SERIAL_RSA - if ((info->state->type == PORT_RSA) && - (info->state->baud_base != SERIAL_RSA_BAUD_BASE) && - enable_rsa(info)) - info->state->baud_base = SERIAL_RSA_BAUD_BASE; -#endif - baud_base = info->state->baud_base; - if (info->state->type == PORT_16C950) { - if (baud <= baud_base) - serial_icr_write(info, UART_TCR, 0); - else if (baud <= 2*baud_base) { - serial_icr_write(info, UART_TCR, 0x8); - baud_base = baud_base * 2; - } else if (baud <= 4*baud_base) { - serial_icr_write(info, UART_TCR, 0x4); - baud_base = baud_base * 4; - } else - serial_icr_write(info, UART_TCR, 0); - } - if (baud == 38400 && - ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) - quot = info->state->custom_divisor; - else { - if (baud == 134) - /* Special case since 134 is really 134.5 */ - quot = (2*baud_base / 269); - else if (baud) - quot = baud_base / baud; - } - /* If the quotient is zero refuse the change */ - if (!quot && old_termios) { - info->tty->termios->c_cflag &= ~CBAUD; - info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); - baud = tty_get_baud_rate(info->tty); - if (!baud) - baud = 9600; - if (baud == 38400 && - ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST)) - quot = info->state->custom_divisor; - else { - if (baud == 134) - /* Special case since 134 is really 134.5 */ - quot = (2*baud_base / 269); - else if (baud) - quot = baud_base / baud; - } - } - /* As a last resort, if the quotient is zero, default to 9600 bps */ - if (!quot) - quot = baud_base / 9600; - /* - * Work around a bug in the Oxford Semiconductor 952 rev B - * chip which causes it to seriously miscalculate baud rates - * when DLL is 0. - */ - if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) && - (info->state->revision == 0x5201)) - quot++; - - info->quot = quot; - info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base); - info->timeout += HZ/50; /* Add .02 seconds of slop */ - - /* Set up FIFO's */ - if (uart_config[info->state->type].flags & UART_USE_FIFO) { - if ((info->state->baud_base / quot) < 2400) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; -#ifdef CONFIG_SERIAL_RSA - else if (info->state->type == PORT_RSA) - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14; -#endif - else - fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; - } - if (info->state->type == PORT_16750) - fcr |= UART_FCR7_64BYTE; - - /* CTS flow control flag and modem status interrupts */ - info->IER &= ~UART_IER_MSI; - if (info->flags & ASYNC_HARDPPS_CD) - info->IER |= UART_IER_MSI; - if (cflag & CRTSCTS) { - info->flags |= ASYNC_CTS_FLOW; - info->IER |= UART_IER_MSI; - } else - info->flags &= ~ASYNC_CTS_FLOW; - if (cflag & CLOCAL) - info->flags &= ~ASYNC_CHECK_CD; - else { - info->flags |= ASYNC_CHECK_CD; - info->IER |= UART_IER_MSI; - } - serial_out(info, UART_IER, info->IER); - - /* - * Set up parity check flag - */ -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - - info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; - if (I_INPCK(info->tty)) - info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; - if (I_BRKINT(info->tty) || I_PARMRK(info->tty)) - info->read_status_mask |= UART_LSR_BI; - - /* - * Characters to ignore - */ - info->ignore_status_mask = 0; - if (I_IGNPAR(info->tty)) - info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; - if (I_IGNBRK(info->tty)) { - info->ignore_status_mask |= UART_LSR_BI; - /* - * If we're ignore parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (I_IGNPAR(info->tty)) - info->ignore_status_mask |= UART_LSR_OE; - } - /* - * !!! ignore all characters if CREAD is not set - */ - if ((cflag & CREAD) == 0) - info->ignore_status_mask |= UART_LSR_DR; - save_flags(flags); cli(); - if (uart_config[info->state->type].flags & UART_STARTECH) { - serial_outp(info, UART_LCR, 0xBF); - serial_outp(info, UART_EFR, - (cflag & CRTSCTS) ? UART_EFR_CTS : 0); - } - serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ - serial_outp(info, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_outp(info, UART_DLM, quot >> 8); /* MS of divisor */ - if (info->state->type == PORT_16750) - serial_outp(info, UART_FCR, fcr); /* set fcr */ - serial_outp(info, UART_LCR, cval); /* reset DLAB */ - info->LCR = cval; /* Save LCR */ - if (info->state->type != PORT_16750) { - if (fcr & UART_FCR_ENABLE_FIFO) { - /* emulated UARTs (Lucent Venus 167x) need two steps */ - serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); - } - serial_outp(info, UART_FCR, fcr); /* set fcr */ - } - restore_flags(flags); -} - -static void rs_put_char(struct tty_struct *tty, unsigned char ch) -{ - struct async_struct *info = (struct async_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "rs_put_char")) - return; - - if (!tty || !info->xmit.buf) - return; - - save_flags(flags); cli(); - if (CIRC_SPACE(info->xmit.head, - info->xmit.tail, - SERIAL_XMIT_SIZE) == 0) { - restore_flags(flags); - return; - } - - info->xmit.buf[info->xmit.head] = ch; - info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1); - restore_flags(flags); -} - -static void rs_flush_chars(struct tty_struct *tty) -{ - struct async_struct *info = (struct async_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) - return; - - if (info->xmit.head == info->xmit.tail - || tty->stopped - || tty->hw_stopped - || !info->xmit.buf) - return; - - save_flags(flags); cli(); - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - restore_flags(flags); -} - -static int rs_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) -{ - int c, ret = 0; - struct async_struct *info = (struct async_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "rs_write")) - return 0; - - if (!tty || !info->xmit.buf || !tmp_buf) - return 0; - - save_flags(flags); - if (from_user) { - down(&tmp_buf_sem); - while (1) { - int c1; - c = CIRC_SPACE_TO_END(info->xmit.head, - info->xmit.tail, - SERIAL_XMIT_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; - - c -= copy_from_user(tmp_buf, buf, c); - if (!c) { - if (!ret) - ret = -EFAULT; - break; - } - cli(); - c1 = CIRC_SPACE_TO_END(info->xmit.head, - info->xmit.tail, - SERIAL_XMIT_SIZE); - if (c1 < c) - c = c1; - memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c); - info->xmit.head = ((info->xmit.head + c) & - (SERIAL_XMIT_SIZE-1)); - restore_flags(flags); - buf += c; - count -= c; - ret += c; - } - up(&tmp_buf_sem); - } else { - cli(); - while (1) { - c = CIRC_SPACE_TO_END(info->xmit.head, - info->xmit.tail, - SERIAL_XMIT_SIZE); - if (count < c) - c = count; - if (c <= 0) { - break; - } - memcpy(info->xmit.buf + info->xmit.head, buf, c); - info->xmit.head = ((info->xmit.head + c) & - (SERIAL_XMIT_SIZE-1)); - buf += c; - count -= c; - ret += c; - } - restore_flags(flags); - } - if (info->xmit.head != info->xmit.tail - && !tty->stopped - && !tty->hw_stopped - && !(info->IER & UART_IER_THRI)) { - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } - return ret; -} - -static int rs_write_room(struct tty_struct *tty) -{ - struct async_struct *info = (struct async_struct *)tty->driver_data; - - if (serial_paranoia_check(info, tty->device, "rs_write_room")) - return 0; - return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -} - -static int rs_chars_in_buffer(struct tty_struct *tty) -{ - struct async_struct *info = (struct async_struct *)tty->driver_data; - - if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) - return 0; - return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE); -} - -static void rs_flush_buffer(struct tty_struct *tty) -{ - struct async_struct *info = (struct async_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) - return; - save_flags(flags); cli(); - info->xmit.head = info->xmit.tail = 0; - restore_flags(flags); - wake_up_interruptible(&tty->write_wait); -#ifdef SERIAL_HAVE_POLL_WAIT - wake_up_interruptible(&tty->poll_wait); -#endif - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); -} - -/* - * This function is used to send a high-priority XON/XOFF character to - * the device - */ -static void rs_send_xchar(struct tty_struct *tty, char ch) -{ - struct async_struct *info = (struct async_struct *)tty->driver_data; - - if (serial_paranoia_check(info, tty->device, "rs_send_char")) - return; - - info->x_char = ch; - if (ch) { - /* Make sure transmit interrupts are on */ - info->IER |= UART_IER_THRI; - serial_out(info, UART_IER, info->IER); - } -} - -/* - * ------------------------------------------------------------ - * rs_throttle() - * - * This routine is called by the upper-layer tty layer to signal that - * incoming characters should be throttled. - * ------------------------------------------------------------ - */ -static void rs_throttle(struct tty_struct * tty) -{ - struct async_struct *info = (struct async_struct *)tty->driver_data; - unsigned long flags; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->device, "rs_throttle")) - return; - - if (I_IXOFF(tty)) - rs_send_xchar(tty, STOP_CHAR(tty)); - - if (tty->termios->c_cflag & CRTSCTS) - info->MCR &= ~UART_MCR_RTS; - - save_flags(flags); cli(); - serial_out(info, UART_MCR, info->MCR); - restore_flags(flags); -} - -static void rs_unthrottle(struct tty_struct * tty) -{ - struct async_struct *info = (struct async_struct *)tty->driver_data; - unsigned long flags; -#ifdef SERIAL_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", tty_name(tty, buf), - tty->ldisc.chars_in_buffer(tty)); -#endif - - if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) - return; - - if (I_IXOFF(tty)) { - if (info->x_char) - info->x_char = 0; - else - rs_send_xchar(tty, START_CHAR(tty)); - } - if (tty->termios->c_cflag & CRTSCTS) - info->MCR |= UART_MCR_RTS; - save_flags(flags); cli(); - serial_out(info, UART_MCR, info->MCR); - restore_flags(flags); -} - -/* - * ------------------------------------------------------------ - * rs_ioctl() and friends - * ------------------------------------------------------------ - */ - -static int get_serial_info(struct async_struct * info, - struct serial_struct * retinfo) -{ - struct serial_struct tmp; - struct serial_state *state = info->state; - - if (!retinfo) - return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); - tmp.type = state->type; - tmp.line = state->line; - tmp.port = state->port; - if (HIGH_BITS_OFFSET) - tmp.port_high = state->port >> HIGH_BITS_OFFSET; - else - tmp.port_high = 0; - tmp.irq = state->irq; - tmp.flags = state->flags; - tmp.xmit_fifo_size = state->xmit_fifo_size; - tmp.baud_base = state->baud_base; - tmp.close_delay = state->close_delay; - tmp.closing_wait = state->closing_wait; - tmp.custom_divisor = state->custom_divisor; - tmp.hub6 = state->hub6; - tmp.io_type = state->io_type; - if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int set_serial_info(struct async_struct * info, - struct serial_struct * new_info) -{ - struct serial_struct new_serial; - struct serial_state old_state, *state; - unsigned int i,change_irq,change_port; - int retval = 0; - unsigned long new_port; - - if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) - return -EFAULT; - state = info->state; - old_state = *state; - - new_port = new_serial.port; - if (HIGH_BITS_OFFSET) - new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; - - change_irq = new_serial.irq != state->irq; - change_port = (new_port != ((int) state->port)) || - (new_serial.hub6 != state->hub6); - - if (!capable(CAP_SYS_ADMIN)) { - if (change_irq || change_port || - (new_serial.baud_base != state->baud_base) || - (new_serial.type != state->type) || - (new_serial.close_delay != state->close_delay) || - (new_serial.xmit_fifo_size != state->xmit_fifo_size) || - ((new_serial.flags & ~ASYNC_USR_MASK) != - (state->flags & ~ASYNC_USR_MASK))) - return -EPERM; - state->flags = ((state->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - info->flags = ((info->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - state->custom_divisor = new_serial.custom_divisor; - goto check_and_exit; - } - - new_serial.irq = irq_cannonicalize(new_serial.irq); - - if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || - (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) || - (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) || - (new_serial.type == PORT_STARTECH)) { - return -EINVAL; - } - - if ((new_serial.type != state->type) || - (new_serial.xmit_fifo_size <= 0)) - new_serial.xmit_fifo_size = - uart_config[new_serial.type].dfl_xmit_fifo_size; - - /* Make sure address is not already in use */ - if (new_serial.type) { - for (i = 0 ; i < NR_PORTS; i++) - if ((state != &rs_table[i]) && - (rs_table[i].port == new_port) && - rs_table[i].type) - return -EADDRINUSE; - } - - if ((change_port || change_irq) && (state->count > 1)) - return -EBUSY; - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - state->baud_base = new_serial.baud_base; - state->flags = ((state->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) | - (info->flags & ASYNC_INTERNAL_FLAGS)); - state->custom_divisor = new_serial.custom_divisor; - state->close_delay = new_serial.close_delay * HZ/100; - state->closing_wait = new_serial.closing_wait * HZ/100; -#if (LINUX_VERSION_CODE > 0x20100) - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -#endif - info->xmit_fifo_size = state->xmit_fifo_size = - new_serial.xmit_fifo_size; - - if ((state->type != PORT_UNKNOWN) && state->port) { -#ifdef CONFIG_SERIAL_RSA - if (old_state.type == PORT_RSA) - release_region(state->port + UART_RSA_BASE, 16); - else -#endif - release_region(state->port,8); - } - state->type = new_serial.type; - if (change_port || change_irq) { - /* - * We need to shutdown the serial port at the old - * port/irq combination. - */ - shutdown(info); - state->irq = new_serial.irq; - info->port = state->port = new_port; - info->hub6 = state->hub6 = new_serial.hub6; - if (info->hub6) - info->io_type = state->io_type = SERIAL_IO_HUB6; - else if (info->io_type == SERIAL_IO_HUB6) - info->io_type = state->io_type = SERIAL_IO_PORT; - } - if ((state->type != PORT_UNKNOWN) && state->port) { -#ifdef CONFIG_SERIAL_RSA - if (state->type == PORT_RSA) - request_region(state->port + UART_RSA_BASE, - 16, "serial_rsa(set)"); - else -#endif - request_region(state->port,8,"serial(set)"); - } - - -check_and_exit: - if (!state->port || !state->type) - return 0; - if (info->flags & ASYNC_INITIALIZED) { - if (((old_state.flags & ASYNC_SPD_MASK) != - (state->flags & ASYNC_SPD_MASK)) || - (old_state.custom_divisor != state->custom_divisor)) { -#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - info->tty->alt_speed = 57600; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - info->tty->alt_speed = 115200; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - info->tty->alt_speed = 230400; - if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - info->tty->alt_speed = 460800; -#endif - change_speed(info, 0); - } - } else - retval = startup(info); - return retval; -} - - -/* - * get_lsr_info - get line status register info - * - * Purpose: Let user call ioctl() to get info when the UART physically - * is emptied. On bus types like RS485, the transmitter must - * release the bus after transmitting. This must be done when - * the transmit shift register is empty, not be done when the - * transmit holding register is empty. This functionality - * allows an RS485 driver to be written in user space. - */ -static int get_lsr_info(struct async_struct * info, unsigned int *value) -{ - unsigned char status; - unsigned int result; - unsigned long flags; - - save_flags(flags); cli(); - status = serial_in(info, UART_LSR); - restore_flags(flags); - result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); - - /* - * If we're about to load something into the transmit - * register, we'll pretend the transmitter isn't empty to - * avoid a race condition (depending on when the transmit - * interrupt happens). - */ - if (info->x_char || - ((CIRC_CNT(info->xmit.head, info->xmit.tail, - SERIAL_XMIT_SIZE) > 0) && - !info->tty->stopped && !info->tty->hw_stopped)) - result &= ~TIOCSER_TEMT; - - if (copy_to_user(value, &result, sizeof(int))) - return -EFAULT; - return 0; -} - - -static int get_modem_info(struct async_struct * info, unsigned int *value) -{ - unsigned char control, status; - unsigned int result; - unsigned long flags; - - control = info->MCR; - save_flags(flags); cli(); - status = serial_in(info, UART_MSR); - restore_flags(flags); - result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) - | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) -#ifdef TIOCM_OUT1 - | ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0) - | ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0) -#endif - | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) - | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) - | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) - | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); - - if (copy_to_user(value, &result, sizeof(int))) - return -EFAULT; - return 0; -} - -static int set_modem_info(struct async_struct * info, unsigned int cmd, - unsigned int *value) -{ - unsigned int arg; - unsigned long flags; - - if (copy_from_user(&arg, value, sizeof(int))) - return -EFAULT; - - switch (cmd) { - case TIOCMBIS: - if (arg & TIOCM_RTS) - info->MCR |= UART_MCR_RTS; - if (arg & TIOCM_DTR) - info->MCR |= UART_MCR_DTR; -#ifdef TIOCM_OUT1 - if (arg & TIOCM_OUT1) - info->MCR |= UART_MCR_OUT1; - if (arg & TIOCM_OUT2) - info->MCR |= UART_MCR_OUT2; -#endif - if (arg & TIOCM_LOOP) - info->MCR |= UART_MCR_LOOP; - break; - case TIOCMBIC: - if (arg & TIOCM_RTS) - info->MCR &= ~UART_MCR_RTS; - if (arg & TIOCM_DTR) - info->MCR &= ~UART_MCR_DTR; -#ifdef TIOCM_OUT1 - if (arg & TIOCM_OUT1) - info->MCR &= ~UART_MCR_OUT1; - if (arg & TIOCM_OUT2) - info->MCR &= ~UART_MCR_OUT2; -#endif - if (arg & TIOCM_LOOP) - info->MCR &= ~UART_MCR_LOOP; - break; - case TIOCMSET: - info->MCR = ((info->MCR & ~(UART_MCR_RTS | -#ifdef TIOCM_OUT1 - UART_MCR_OUT1 | - UART_MCR_OUT2 | -#endif - UART_MCR_LOOP | - UART_MCR_DTR)) - | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) -#ifdef TIOCM_OUT1 - | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0) - | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0) -#endif - | ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0) - | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0)); - break; - default: - return -EINVAL; - } - save_flags(flags); cli(); - info->MCR |= ALPHA_KLUDGE_MCR; /* Don't ask */ - serial_out(info, UART_MCR, info->MCR); - restore_flags(flags); - return 0; -} - -static int do_autoconfig(struct async_struct * info) -{ - int irq, retval; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (info->state->count > 1) - return -EBUSY; - - shutdown(info); - - autoconfig(info->state); - if ((info->state->flags & ASYNC_AUTO_IRQ) && - (info->state->port != 0 || info->state->iomem_base != 0) && - (info->state->type != PORT_UNKNOWN)) { - irq = detect_uart_irq(info->state); - if (irq > 0) - info->state->irq = irq; - } - - retval = startup(info); - if (retval) - return retval; - return 0; -} - -/* - * rs_break() --- routine which turns the break handling on or off - */ -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ -static void send_break( struct async_struct * info, int duration) -{ - if (!CONFIGURED_SERIAL_PORT(info)) - return; - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + duration; - cli(); - info->LCR |= UART_LCR_SBC; - serial_out(info, UART_LCR, info->LCR); - schedule(); - info->LCR &= ~UART_LCR_SBC; - serial_out(info, UART_LCR, info->LCR); - sti(); -} -#else -static void rs_break(struct tty_struct *tty, int break_state) -{ - struct async_struct * info = (struct async_struct *)tty->driver_data; - unsigned long flags; - - if (serial_paranoia_check(info, tty->device, "rs_break")) - return; - - if (!CONFIGURED_SERIAL_PORT(info)) - return; - save_flags(flags); cli(); - if (break_state == -1) - info->LCR |= UART_LCR_SBC; - else - info->LCR &= ~UART_LCR_SBC; - serial_out(info, UART_LCR, info->LCR); - restore_flags(flags); -} -#endif - -#ifdef CONFIG_SERIAL_MULTIPORT -static int get_multiport_struct(struct async_struct * info, - struct serial_multiport_struct *retinfo) -{ - struct serial_multiport_struct ret; - struct rs_multiport_struct *multi; - - multi = &rs_multiport[info->state->irq]; - - ret.port_monitor = multi->port_monitor; - - ret.port1 = multi->port1; - ret.mask1 = multi->mask1; - ret.match1 = multi->match1; - - ret.port2 = multi->port2; - ret.mask2 = multi->mask2; - ret.match2 = multi->match2; - - ret.port3 = multi->port3; - ret.mask3 = multi->mask3; - ret.match3 = multi->match3; - - ret.port4 = multi->port4; - ret.mask4 = multi->mask4; - ret.match4 = multi->match4; - - ret.irq = info->state->irq; - - if (copy_to_user(retinfo,&ret,sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int set_multiport_struct(struct async_struct * info, - struct serial_multiport_struct *in_multi) -{ - struct serial_multiport_struct new_multi; - struct rs_multiport_struct *multi; - struct serial_state *state; - int was_multi, now_multi; - int retval; - void (*handler)(int, void *, struct pt_regs *); - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - state = info->state; - - if (copy_from_user(&new_multi, in_multi, - sizeof(struct serial_multiport_struct))) - return -EFAULT; - - if (new_multi.irq != state->irq || state->irq == 0 || - !IRQ_ports[state->irq]) - return -EINVAL; - - multi = &rs_multiport[state->irq]; - was_multi = (multi->port1 != 0); - - multi->port_monitor = new_multi.port_monitor; - - if (multi->port1) - release_region(multi->port1,1); - multi->port1 = new_multi.port1; - multi->mask1 = new_multi.mask1; - multi->match1 = new_multi.match1; - if (multi->port1) - request_region(multi->port1,1,"serial(multiport1)"); - - if (multi->port2) - release_region(multi->port2,1); - multi->port2 = new_multi.port2; - multi->mask2 = new_multi.mask2; - multi->match2 = new_multi.match2; - if (multi->port2) - request_region(multi->port2,1,"serial(multiport2)"); - - if (multi->port3) - release_region(multi->port3,1); - multi->port3 = new_multi.port3; - multi->mask3 = new_multi.mask3; - multi->match3 = new_multi.match3; - if (multi->port3) - request_region(multi->port3,1,"serial(multiport3)"); - - if (multi->port4) - release_region(multi->port4,1); - multi->port4 = new_multi.port4; - multi->mask4 = new_multi.mask4; - multi->match4 = new_multi.match4; - if (multi->port4) - request_region(multi->port4,1,"serial(multiport4)"); - - now_multi = (multi->port1 != 0); - - if (IRQ_ports[state->irq]->next_port && - (was_multi != now_multi)) { - free_irq(state->irq, &IRQ_ports[state->irq]); - if (now_multi) - handler = rs_interrupt_multi; - else - handler = rs_interrupt; - - retval = request_irq(state->irq, handler, SA_SHIRQ, - "serial", &IRQ_ports[state->irq]); - if (retval) { - printk("Couldn't reallocate serial interrupt " - "driver!!\n"); - } - } - return 0; -} -#endif - -static int rs_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - struct async_struct * info = (struct async_struct *)tty->driver_data; - struct async_icount cprev, cnow; /* kernel counter temps */ - struct serial_icounter_struct icount; - unsigned long flags; -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ - int retval, tmp; -#endif - - if (serial_paranoia_check(info, tty->device, "rs_ioctl")) - return -ENODEV; - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && - (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - - switch (cmd) { -#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */ - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - if (!arg) { - send_break(info, HZ/4); /* 1/4 second */ - if (signal_pending(current)) - return -EINTR; - } - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change(tty); - if (retval) - return retval; - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - send_break(info, arg ? arg*(HZ/10) : HZ/4); - if (signal_pending(current)) - return -EINTR; - return 0; - case TIOCGSOFTCAR: - tmp = C_CLOCAL(tty) ? 1 : 0; - if (copy_to_user((void *)arg, &tmp, sizeof(int))) - return -EFAULT; - return 0; - case TIOCSSOFTCAR: - if (copy_from_user(&tmp, (void *)arg, sizeof(int))) - return -EFAULT; - - tty->termios->c_cflag = - ((tty->termios->c_cflag & ~CLOCAL) | - (tmp ? CLOCAL : 0)); - return 0; -#endif - case TIOCMGET: - return get_modem_info(info, (unsigned int *) arg); - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - return set_modem_info(info, cmd, (unsigned int *) arg); - case TIOCGSERIAL: - return get_serial_info(info, - (struct serial_struct *) arg); - case TIOCSSERIAL: - return set_serial_info(info, - (struct serial_struct *) arg); - case TIOCSERCONFIG: - return do_autoconfig(info); - - case TIOCSERGETLSR: /* Get line status register */ - return get_lsr_info(info, (unsigned int *) arg); - - case TIOCSERGSTRUCT: - if (copy_to_user((struct async_struct *) arg, - info, sizeof(struct async_struct))) - return -EFAULT; - return 0; - -#ifdef CONFIG_SERIAL_MULTIPORT - case TIOCSERGETMULTI: - return get_multiport_struct(info, - (struct serial_multiport_struct *) arg); - case TIOCSERSETMULTI: - return set_multiport_struct(info, - (struct serial_multiport_struct *) arg); -#endif - - /* - * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change - * - mask passed in arg for lines of interest - * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) - * Caller should use TIOCGICOUNT to see which one it was - */ - case TIOCMIWAIT: - save_flags(flags); cli(); - /* note the counters on entry */ - cprev = info->state->icount; - restore_flags(flags); - /* Force modem status interrupts on */ - info->IER |= UART_IER_MSI; - serial_out(info, UART_IER, info->IER); - while (1) { - interruptible_sleep_on(&info->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - save_flags(flags); cli(); - cnow = info->state->icount; /* atomic copy */ - restore_flags(flags); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ - - /* - * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) - * Return: write counters to the user passed counter struct - * NB: both 1->0 and 0->1 transitions are counted except for - * RI where only 0->1 is counted. - */ - case TIOCGICOUNT: - save_flags(flags); cli(); - cnow = info->state->icount; - restore_flags(flags); - icount.cts = cnow.cts; - icount.dsr = cnow.dsr; - icount.rng = cnow.rng; - icount.dcd = cnow.dcd; - icount.rx = cnow.rx; - icount.tx = cnow.tx; - icount.frame = cnow.frame; - icount.overrun = cnow.overrun; - icount.parity = cnow.parity; - icount.brk = cnow.brk; - icount.buf_overrun = cnow.buf_overrun; - - if (copy_to_user((void *)arg, &icount, sizeof(icount))) - return -EFAULT; - return 0; - case TIOCSERGWILD: - case TIOCSERSWILD: - /* "setserial -W" is called in Debian boot */ - printk ("TIOCSER?WILD ioctl obsolete, ignored.\n"); - return 0; - - default: - return -ENOIOCTLCMD; - } - return 0; -} - -static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) -{ - struct async_struct *info = (struct async_struct *)tty->driver_data; - unsigned long flags; - unsigned int cflag = tty->termios->c_cflag; - - if ( (cflag == old_termios->c_cflag) - && ( RELEVANT_IFLAG(tty->termios->c_iflag) - == RELEVANT_IFLAG(old_termios->c_iflag))) - return; - - change_speed(info, old_termios); - - /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && - !(cflag & CBAUD)) { - info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); - save_flags(flags); cli(); - serial_out(info, UART_MCR, info->MCR); - restore_flags(flags); - } - - /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - (cflag & CBAUD)) { - info->MCR |= UART_MCR_DTR; - if (!(tty->termios->c_cflag & CRTSCTS) || - !test_bit(TTY_THROTTLED, &tty->flags)) { - info->MCR |= UART_MCR_RTS; - } - save_flags(flags); cli(); - serial_out(info, UART_MCR, info->MCR); - restore_flags(flags); - } - - /* Handle turning off CRTSCTS */ - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - rs_start(tty); - } - -#if 0 - /* - * No need to wake up processes in open wait, since they - * sample the CLOCAL flag once, and don't recheck it. - * XXX It's not clear whether the current behavior is correct - * or not. Hence, this may change..... - */ - if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->open_wait); -#endif -} - -/* - * ------------------------------------------------------------ - * rs_close() - * - * This routine is called when the serial port gets closed. First, we - * wait for the last remaining data to be sent. Then, we unlink its - * async structure from the interrupt chain if necessary, and we free - * that IRQ if nothing is left in the chain. - * ------------------------------------------------------------ - */ -static void rs_close(struct tty_struct *tty, struct file * filp) -{ - struct async_struct * info = (struct async_struct *)tty->driver_data; - struct serial_state *state; - unsigned long flags; - - if (!info || serial_paranoia_check(info, tty->device, "rs_close")) - return; - - state = info->state; - - save_flags(flags); cli(); - - if (tty_hung_up_p(filp)) { - DBG_CNT("before DEC-hung"); - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_close ttys%d, count = %d\n", info->line, state->count); -#endif - if ((tty->count == 1) && (state->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. state->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("rs_close: bad serial port count; tty->count is 1, " - "state->count is %d\n", state->count); - state->count = 1; - } - if (--state->count < 0) { - printk("rs_close: bad serial port count for ttys%d: %d\n", - info->line, state->count); - state->count = 0; - } - if (state->count) { - DBG_CNT("before DEC-2"); - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - info->flags |= ASYNC_CLOSING; - restore_flags(flags); - /* - * Save the termios structure, since this port may have - * separate termios for callout and dialin. - */ - if (info->flags & ASYNC_NORMAL_ACTIVE) - info->state->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->state->callout_termios = *tty->termios; - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, info->closing_wait); - /* - * At this point we stop accepting input. To do this, we - * disable the receive line status interrupts, and tell the - * interrupt driver to stop checking the data ready bit in the - * line status register. - */ - info->IER &= ~UART_IER_RLSI; - info->read_status_mask &= ~UART_LSR_DR; - if (info->flags & ASYNC_INITIALIZED) { - serial_out(info, UART_IER, info->IER); - /* - * Before we drop DTR, make sure the UART transmitter - * has completely drained; this is especially - * important if there is a transmit FIFO! - */ - rs_wait_until_sent(tty, info->timeout); - } - shutdown(info); - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(tty); - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - tty->closing = 0; - info->event = 0; - info->tty = 0; - if (info->blocked_open) { - if (info->close_delay) { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(info->close_delay); - } - wake_up_interruptible(&info->open_wait); - } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); - wake_up_interruptible(&info->close_wait); - MOD_DEC_USE_COUNT; -} - -/* - * rs_wait_until_sent() --- wait until the transmitter is empty - */ -static void rs_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct async_struct * info = (struct async_struct *)tty->driver_data; - unsigned long orig_jiffies, char_time; - int lsr; - - if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent")) - return; - - if (info->state->type == PORT_UNKNOWN) - return; - - if (info->xmit_fifo_size == 0) - return; /* Just in case.... */ - - orig_jiffies = jiffies; - /* - * Set the check interval to be 1/5 of the estimated time to - * send a single character, and make it at least 1. The check - * interval should also be less than the timeout. - * - * Note: we have to use pretty tight timings here to satisfy - * the NIST-PCTS. - */ - char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; - char_time = char_time / 5; - if (char_time == 0) - char_time = 1; - if (timeout && timeout < char_time) - char_time = timeout; - /* - * If the transmitter hasn't cleared in twice the approximate - * amount of time to send the entire FIFO, it probably won't - * ever clear. This assumes the UART isn't doing flow - * control, which is currently the case. Hence, if it ever - * takes longer than info->timeout, this is probably due to a - * UART bug of some kind. So, we clamp the timeout parameter at - * 2*info->timeout. - */ - if (!timeout || timeout > 2*info->timeout) - timeout = 2*info->timeout; -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); - printk("jiff=%lu...", jiffies); -#endif - while (!((lsr = serial_inp(info, UART_LSR)) & UART_LSR_TEMT)) { -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...", lsr, jiffies); -#endif - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(char_time); - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } -#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT - printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies); -#endif -} - -/* - * rs_hangup() --- called by tty_hangup() when a hangup is signaled. - */ -static void rs_hangup(struct tty_struct *tty) -{ - struct async_struct * info = (struct async_struct *)tty->driver_data; - struct serial_state *state = info->state; - - if (serial_paranoia_check(info, tty->device, "rs_hangup")) - return; - - state = info->state; - - rs_flush_buffer(tty); - if (info->flags & ASYNC_CLOSING) - return; - shutdown(info); - info->event = 0; - state->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); - info->tty = 0; - wake_up_interruptible(&info->open_wait); -} - -/* - * ------------------------------------------------------------ - * rs_open() and friends - * ------------------------------------------------------------ - */ -static int block_til_ready(struct tty_struct *tty, struct file * filp, - struct async_struct *info) -{ - DECLARE_WAITQUEUE(wait, current); - struct serial_state *state = info->state; - int retval; - int do_clocal = 0, extra_count = 0; - unsigned long flags; - - /* - * If the device is in the middle of being closed, then block - * until it's done, and then try again. - */ - if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); -#ifdef SERIAL_DO_RESTART - return ((info->flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); -#else - return -EAGAIN; -#endif - } - - /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; - } - - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (state->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, state->count is dropped by one, so that - * rs_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. - */ - retval = 0; - add_wait_queue(&info->open_wait, &wait); -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready before block: ttys%d, count = %d\n", - state->line, state->count); -#endif - save_flags(flags); cli(); - if (!tty_hung_up_p(filp)) { - extra_count = 1; - state->count--; - } - restore_flags(flags); - info->blocked_open++; - while (1) { - save_flags(flags); cli(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) - serial_out(info, UART_MCR, - serial_inp(info, UART_MCR) | - (UART_MCR_DTR | UART_MCR_RTS)); - restore_flags(flags); - set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(info->flags & ASYNC_INITIALIZED)) { -#ifdef SERIAL_DO_RESTART - if (info->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && - (do_clocal || (serial_in(info, UART_MSR) & - UART_MSR_DCD))) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready blocking: ttys%d, count = %d\n", - info->line, state->count); -#endif - schedule(); - } - set_current_state(TASK_RUNNING); - remove_wait_queue(&info->open_wait, &wait); - if (extra_count) - state->count++; - info->blocked_open--; -#ifdef SERIAL_DEBUG_OPEN - printk("block_til_ready after blocking: ttys%d, count = %d\n", - info->line, state->count); -#endif - if (retval) - return retval; - info->flags |= ASYNC_NORMAL_ACTIVE; - return 0; -} - -static int get_async_struct(int line, struct async_struct **ret_info) -{ - struct async_struct *info; - struct serial_state *sstate; - - sstate = rs_table + line; - sstate->count++; - info = sstate->info; - - /* - * If the async_struct is already allocated, do the fastpath. - */ - if (info) - goto out; - - info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); - if (!info) { - sstate->count--; - return -ENOMEM; - } - - memset(info, 0, sizeof(struct async_struct)); - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - init_waitqueue_head(&info->delta_msr_wait); - info->magic = SERIAL_MAGIC; - info->port = sstate->port; - info->hub6 = sstate->hub6; - info->flags = sstate->flags; - info->xmit_fifo_size = sstate->xmit_fifo_size; - info->state = sstate; - info->line = line; - info->iomem_base = sstate->iomem_base; - info->iomem_reg_shift = sstate->iomem_reg_shift; - info->io_type = sstate->io_type; - info->tqueue.routine = do_softint; - info->tqueue.data = info; - - if (sstate->info) { - kfree(info); - info = sstate->info; - } else { - sstate->info = info; - } - -out: - /* - * If this is the first open, copy over some timeouts. - */ - if (sstate->count == 1) { - info->closing_wait = sstate->closing_wait; - } - *ret_info = info; - return 0; -} - -/* - * This routine is called whenever a serial port is opened. It - * enables interrupts for a serial port, linking in its async structure into - * the IRQ chain. It also performs the serial-specific - * initialization for the tty structure. - */ -static int rs_open(struct tty_struct *tty, struct file * filp) -{ - struct async_struct *info; - int retval, line; - unsigned long page; - - MOD_INC_USE_COUNT; - line = minor(tty->device) - tty->driver.minor_start; - if ((line < 0) || (line >= NR_PORTS)) { - MOD_DEC_USE_COUNT; - return -ENODEV; - } - retval = get_async_struct(line, &info); - if (retval) { - MOD_DEC_USE_COUNT; - return retval; - } - tty->driver_data = info; - info->tty = tty; - if (serial_paranoia_check(info, tty->device, "rs_open")) { - MOD_DEC_USE_COUNT; - return -ENODEV; - } - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, - info->state->count); -#endif -#if (LINUX_VERSION_CODE > 0x20100) - info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; -#endif - - /* - * This relies on lock_kernel() stuff so wants tidying for 2.5 - */ - if (!tmp_buf) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) { - MOD_DEC_USE_COUNT; - return -ENOMEM; - } - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; - } - - /* - * If the port is the middle of closing, bail out now - */ - if (tty_hung_up_p(filp) || - (info->flags & ASYNC_CLOSING)) { - if (info->flags & ASYNC_CLOSING) - interruptible_sleep_on(&info->close_wait); - MOD_DEC_USE_COUNT; -#ifdef SERIAL_DO_RESTART - return ((info->flags & ASYNC_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); -#else - return -EAGAIN; -#endif - } - - /* - * Start up serial port - */ - retval = startup(info); - if (retval) { - MOD_DEC_USE_COUNT; - return retval; - } - - retval = block_til_ready(tty, filp, info); - if (retval) { -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open returning after block_til_ready with %d\n", - retval); -#endif - MOD_DEC_USE_COUNT; - return retval; - } - - if ((info->state->count == 1) && - (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver.subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->state->normal_termios; - else - *tty->termios = info->state->callout_termios; - change_speed(info, 0); - } -#ifdef CONFIG_SERIAL_CONSOLE - if (sercons.cflag && sercons.index == line) { - tty->termios->c_cflag = sercons.cflag; - sercons.cflag = 0; - change_speed(info, 0); - } -#endif - info->session = current->session; - info->pgrp = current->pgrp; - -#ifdef SERIAL_DEBUG_OPEN - printk("rs_open ttys%d successful...", info->line); -#endif - return 0; -} - -/* - * /proc fs routines.... - */ - -static inline int line_info(char *buf, struct serial_state *state) -{ - struct async_struct *info = state->info, scr_info; - char stat_buf[30], control, status; - int ret; - unsigned long flags; - - ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d", - state->line, uart_config[state->type].name, - state->port, state->irq); - - if (!state->port || (state->type == PORT_UNKNOWN)) { - ret += sprintf(buf+ret, "\n"); - return ret; - } - - /* - * Figure out the current RS-232 lines - */ - if (!info) { - info = &scr_info; /* This is just for serial_{in,out} */ - - info->magic = SERIAL_MAGIC; - info->port = state->port; - info->flags = state->flags; - info->hub6 = state->hub6; - info->io_type = state->io_type; - info->iomem_base = state->iomem_base; - info->iomem_reg_shift = state->iomem_reg_shift; - info->quot = 0; - info->tty = 0; - } - save_flags(flags); cli(); - status = serial_in(info, UART_MSR); - control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR); - restore_flags(flags); - - stat_buf[0] = 0; - stat_buf[1] = 0; - if (control & UART_MCR_RTS) - strcat(stat_buf, "|RTS"); - if (status & UART_MSR_CTS) - strcat(stat_buf, "|CTS"); - if (control & UART_MCR_DTR) - strcat(stat_buf, "|DTR"); - if (status & UART_MSR_DSR) - strcat(stat_buf, "|DSR"); - if (status & UART_MSR_DCD) - strcat(stat_buf, "|CD"); - if (status & UART_MSR_RI) - strcat(stat_buf, "|RI"); - - if (info->quot) { - ret += sprintf(buf+ret, " baud:%d", - state->baud_base / info->quot); - } - - ret += sprintf(buf+ret, " tx:%d rx:%d", - state->icount.tx, state->icount.rx); - - if (state->icount.frame) - ret += sprintf(buf+ret, " fe:%d", state->icount.frame); - - if (state->icount.parity) - ret += sprintf(buf+ret, " pe:%d", state->icount.parity); - - if (state->icount.brk) - ret += sprintf(buf+ret, " brk:%d", state->icount.brk); - - if (state->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); - - /* - * Last thing is the RS-232 status lines - */ - ret += sprintf(buf+ret, " %s\n", stat_buf+1); - return ret; -} - -int rs_read_proc(char *page, char **start, off_t off, int count, - int *eof, void *data) -{ - int i, len = 0, l; - off_t begin = 0; - - len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s\n", - serial_version, LOCAL_VERSTRING, serial_revdate); - for (i = 0; i < NR_PORTS && len < 4000; i++) { - l = line_info(page + len, &rs_table[i]); - len += l; - if (len+begin > off+count) - goto done; - if (len+begin < off) { - begin += len; - len = 0; - } - } - *eof = 1; -done: - if (off >= len+begin) - return 0; - *start = page + (off-begin); - return ((count < begin+len-off) ? count : begin+len-off); -} - -/* - * --------------------------------------------------------------------- - * rs_init() and friends - * - * rs_init() is called at boot-time to initialize the serial driver. - * --------------------------------------------------------------------- - */ - -/* - * This routine prints out the appropriate serial driver version - * number, and identifies which options were configured into this - * driver. - */ -static char serial_options[] __initdata = -#ifdef CONFIG_HUB6 - " HUB-6" -#define SERIAL_OPT -#endif -#ifdef CONFIG_SERIAL_MANY_PORTS - " MANY_PORTS" -#define SERIAL_OPT -#endif -#ifdef CONFIG_SERIAL_MULTIPORT - " MULTIPORT" -#define SERIAL_OPT -#endif -#ifdef CONFIG_SERIAL_SHARE_IRQ - " SHARE_IRQ" -#define SERIAL_OPT -#endif -#ifdef CONFIG_SERIAL_DETECT_IRQ - " DETECT_IRQ" -#define SERIAL_OPT -#endif -#ifdef ENABLE_SERIAL_PCI - " SERIAL_PCI" -#define SERIAL_OPT -#endif -#ifdef ENABLE_SERIAL_PNP - " ISAPNP" -#define SERIAL_OPT -#endif -#ifdef ENABLE_SERIAL_ACPI - " SERIAL_ACPI" -#define SERIAL_OPT -#endif -#ifdef SERIAL_OPT - " enabled\n"; -#else - " no serial options enabled\n"; -#endif -#undef SERIAL_OPT - -static _INLINE_ void show_serial_version(void) -{ - printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name, - serial_version, LOCAL_VERSTRING, serial_revdate, - serial_options); -} - -/* - * This routine detect the IRQ of a serial port by clearing OUT2 when - * no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at - * each time, as long as no other device permanently request the IRQ. - * If no IRQ is detected, or multiple IRQ appear, this function returns 0. - * The variable "state" and the field "state->port" should not be null. - */ -static unsigned detect_uart_irq (struct serial_state * state) -{ - int irq; - unsigned long irqs; - unsigned char save_mcr, save_ier; - struct async_struct scr_info; /* serial_{in,out} because HUB6 */ - -#ifdef CONFIG_SERIAL_MANY_PORTS - unsigned char save_ICP=0; /* no warning */ - unsigned short ICP=0; - - if (state->flags & ASYNC_FOURPORT) { - ICP = (state->port & 0xFE0) | 0x01F; - save_ICP = inb_p(ICP); - outb_p(0x80, ICP); - (void) inb_p(ICP); - } -#endif - scr_info.magic = SERIAL_MAGIC; - scr_info.state = state; - scr_info.port = state->port; - scr_info.flags = state->flags; -#ifdef CONFIG_HUB6 - scr_info.hub6 = state->hub6; -#endif - scr_info.io_type = state->io_type; - scr_info.iomem_base = state->iomem_base; - scr_info.iomem_reg_shift = state->iomem_reg_shift; - - /* forget possible initially masked and pending IRQ */ - probe_irq_off(probe_irq_on()); - save_mcr = serial_inp(&scr_info, UART_MCR); - save_ier = serial_inp(&scr_info, UART_IER); - serial_outp(&scr_info, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); - - irqs = probe_irq_on(); - serial_outp(&scr_info, UART_MCR, 0); - udelay (10); - if (state->flags & ASYNC_FOURPORT) { - serial_outp(&scr_info, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS); - } else { - serial_outp(&scr_info, UART_MCR, - UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); - } - serial_outp(&scr_info, UART_IER, 0x0f); /* enable all intrs */ - (void)serial_inp(&scr_info, UART_LSR); - (void)serial_inp(&scr_info, UART_RX); - (void)serial_inp(&scr_info, UART_IIR); - (void)serial_inp(&scr_info, UART_MSR); - serial_outp(&scr_info, UART_TX, 0xFF); - udelay (20); - irq = probe_irq_off(irqs); - - serial_outp(&scr_info, UART_MCR, save_mcr); - serial_outp(&scr_info, UART_IER, save_ier); -#ifdef CONFIG_SERIAL_MANY_PORTS - if (state->flags & ASYNC_FOURPORT) - outb_p(save_ICP, ICP); -#endif - return (irq > 0)? irq : 0; -} - -/* - * This is a quickie test to see how big the FIFO is. - * It doesn't work at all the time, more's the pity. - */ -static int size_fifo(struct async_struct *info) -{ - unsigned char old_fcr, old_mcr, old_dll, old_dlm; - int count; - - old_fcr = serial_inp(info, UART_FCR); - old_mcr = serial_inp(info, UART_MCR); - serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); - serial_outp(info, UART_MCR, UART_MCR_LOOP); - serial_outp(info, UART_LCR, UART_LCR_DLAB); - old_dll = serial_inp(info, UART_DLL); - old_dlm = serial_inp(info, UART_DLM); - serial_outp(info, UART_DLL, 0x01); - serial_outp(info, UART_DLM, 0x00); - serial_outp(info, UART_LCR, 0x03); - for (count = 0; count < 256; count++) - serial_outp(info, UART_TX, count); - mdelay(20); - for (count = 0; (serial_inp(info, UART_LSR) & UART_LSR_DR) && - (count < 256); count++) - serial_inp(info, UART_RX); - serial_outp(info, UART_FCR, old_fcr); - serial_outp(info, UART_MCR, old_mcr); - serial_outp(info, UART_LCR, UART_LCR_DLAB); - serial_outp(info, UART_DLL, old_dll); - serial_outp(info, UART_DLM, old_dlm); - - return count; -} - -/* - * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. - * When this function is called we know it is at least a StarTech - * 16650 V2, but it might be one of several StarTech UARTs, or one of - * its clones. (We treat the broken original StarTech 16650 V1 as a - * 16550, and why not? Startech doesn't seem to even acknowledge its - * existence.) - * - * What evil have men's minds wrought... - */ -static void autoconfig_startech_uarts(struct async_struct *info, - struct serial_state *state, - unsigned long flags) -{ - unsigned char scratch, scratch2, scratch3, scratch4; - - /* - * First we check to see if it's an Oxford Semiconductor UART. - * - * If we have to do this here because some non-National - * Semiconductor clone chips lock up if you try writing to the - * LSR register (which serial_icr_read does) - */ - if (state->type == PORT_16550A) { - /* - * EFR [4] must be set else this test fails - * - * This shouldn't be necessary, but Mike Hudson - * (Exoray@isys.ca) claims that it's needed for 952 - * dual UART's (which are not recommended for new designs). - */ - info->ACR = 0; - serial_out(info, UART_LCR, 0xBF); - serial_out(info, UART_EFR, 0x10); - serial_out(info, UART_LCR, 0x00); - /* Check for Oxford Semiconductor 16C950 */ - scratch = serial_icr_read(info, UART_ID1); - scratch2 = serial_icr_read(info, UART_ID2); - scratch3 = serial_icr_read(info, UART_ID3); - - if (scratch == 0x16 && scratch2 == 0xC9 && - (scratch3 == 0x50 || scratch3 == 0x52 || - scratch3 == 0x54)) { - state->type = PORT_16C950; - state->revision = serial_icr_read(info, UART_REV) | - (scratch3 << 8); - return; - } - } - - /* - * We check for a XR16C850 by setting DLL and DLM to 0, and - * then reading back DLL and DLM. If DLM reads back 0x10, - * then the UART is a XR16C850 and the DLL contains the chip - * revision. If DLM reads back 0x14, then the UART is a - * XR16C854. - * - */ - - /* Save the DLL and DLM */ - - serial_outp(info, UART_LCR, UART_LCR_DLAB); - scratch3 = serial_inp(info, UART_DLL); - scratch4 = serial_inp(info, UART_DLM); - - serial_outp(info, UART_DLL, 0); - serial_outp(info, UART_DLM, 0); - scratch2 = serial_inp(info, UART_DLL); - scratch = serial_inp(info, UART_DLM); - serial_outp(info, UART_LCR, 0); - - if (scratch == 0x10 || scratch == 0x14) { - if (scratch == 0x10) - state->revision = scratch2; - state->type = PORT_16850; - return; - } - - /* Restore the DLL and DLM */ - - serial_outp(info, UART_LCR, UART_LCR_DLAB); - serial_outp(info, UART_DLL, scratch3); - serial_outp(info, UART_DLM, scratch4); - serial_outp(info, UART_LCR, 0); - /* - * We distinguish between the '654 and the '650 by counting - * how many bytes are in the FIFO. I'm using this for now, - * since that's the technique that was sent to me in the - * serial driver update, but I'm not convinced this works. - * I've had problems doing this in the past. -TYT - */ - if (size_fifo(info) == 64) - state->type = PORT_16654; - else - state->type = PORT_16650V2; -} - -/* - * This routine is called by rs_init() to initialize a specific serial - * port. It determines what type of UART chip this serial port is - * using: 8250, 16450, 16550, 16550A. The important question is - * whether or not this UART is a 16550A or not, since this will - * determine whether or not we can use its FIFO features or not. - */ -static void autoconfig(struct serial_state * state) -{ - unsigned char status1, status2, scratch, scratch2, scratch3; - unsigned char save_lcr, save_mcr; - struct async_struct *info, scr_info; - unsigned long flags; - - state->type = PORT_UNKNOWN; - -#ifdef SERIAL_DEBUG_AUTOCONF - printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line, - state->port, (unsigned) state->iomem_base); -#endif - - if (!CONFIGURED_SERIAL_PORT(state)) - return; - - info = &scr_info; /* This is just for serial_{in,out} */ - - info->magic = SERIAL_MAGIC; - info->state = state; - info->port = state->port; - info->flags = state->flags; -#ifdef CONFIG_HUB6 - info->hub6 = state->hub6; -#endif - info->io_type = state->io_type; - info->iomem_base = state->iomem_base; - info->iomem_reg_shift = state->iomem_reg_shift; - - save_flags(flags); cli(); - - if (!(state->flags & ASYNC_BUGGY_UART) && - !state->iomem_base) { - /* - * Do a simple existence test first; if we fail this, - * there's no point trying anything else. - * - * 0x80 is used as a nonsense port to prevent against - * false positives due to ISA bus float. The - * assumption is that 0x80 is a non-existent port; - * which should be safe since include/asm/io.h also - * makes this assumption. - */ - scratch = serial_inp(info, UART_IER); - serial_outp(info, UART_IER, 0); -#ifdef __i386__ - outb(0xff, 0x080); -#endif - scratch2 = serial_inp(info, UART_IER); - serial_outp(info, UART_IER, 0x0F); -#ifdef __i386__ - outb(0, 0x080); -#endif - scratch3 = serial_inp(info, UART_IER); - serial_outp(info, UART_IER, scratch); - if (scratch2 || scratch3 != 0x0F) { -#ifdef SERIAL_DEBUG_AUTOCONF - printk("serial: ttyS%d: simple autoconfig failed " - "(%02x, %02x)\n", state->line, - scratch2, scratch3); -#endif - restore_flags(flags); - return; /* We failed; there's nothing here */ - } - } - - save_mcr = serial_in(info, UART_MCR); - save_lcr = serial_in(info, UART_LCR); - - /* - * Check to see if a UART is really there. Certain broken - * internal modems based on the Rockwell chipset fail this - * test, because they apparently don't implement the loopback - * test mode. So this test is skipped on the COM 1 through - * COM 4 ports. This *should* be safe, since no board - * manufacturer would be stupid enough to design a board - * that conflicts with COM 1-4 --- we hope! - */ - if (!(state->flags & ASYNC_SKIP_TEST)) { - serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A); - status1 = serial_inp(info, UART_MSR) & 0xF0; - serial_outp(info, UART_MCR, save_mcr); - if (status1 != 0x90) { -#ifdef SERIAL_DEBUG_AUTOCONF - printk("serial: ttyS%d: no UART loopback failed\n", - state->line); -#endif - restore_flags(flags); - return; - } - } - serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */ - serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */ - serial_outp(info, UART_LCR, 0); - serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); - scratch = serial_in(info, UART_IIR) >> 6; - switch (scratch) { - case 0: - state->type = PORT_16450; - break; - case 1: - state->type = PORT_UNKNOWN; - break; - case 2: - state->type = PORT_16550; - break; - case 3: - state->type = PORT_16550A; - break; - } - if (state->type == PORT_16550A) { - /* Check for Startech UART's */ - serial_outp(info, UART_LCR, UART_LCR_DLAB); - if (serial_in(info, UART_EFR) == 0) { - state->type = PORT_16650; - } else { - serial_outp(info, UART_LCR, 0xBF); - if (serial_in(info, UART_EFR) == 0) - autoconfig_startech_uarts(info, state, flags); - } - } - if (state->type == PORT_16550A) { - /* Check for TI 16750 */ - serial_outp(info, UART_LCR, save_lcr | UART_LCR_DLAB); - serial_outp(info, UART_FCR, - UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - scratch = serial_in(info, UART_IIR) >> 5; - if (scratch == 7) { - /* - * If this is a 16750, and not a cheap UART - * clone, then it should only go into 64 byte - * mode if the UART_FCR7_64BYTE bit was set - * while UART_LCR_DLAB was latched. - */ - serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); - serial_outp(info, UART_LCR, 0); - serial_outp(info, UART_FCR, - UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); - scratch = serial_in(info, UART_IIR) >> 5; - if (scratch == 6) - state->type = PORT_16750; - } - serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); - } -#if defined(CONFIG_SERIAL_RSA) && defined(MODULE) - if (state->type == PORT_16550A) { - int i; - - for (i = 0 ; i < PORT_RSA_MAX ; ++i) { - if (!probe_rsa[i] && !force_rsa[i]) - break; - if (((probe_rsa[i] != state->port) || - check_region(state->port + UART_RSA_BASE, 16)) && - (force_rsa[i] != state->port)) - continue; - if (!enable_rsa(info)) - continue; - state->type = PORT_RSA; - state->baud_base = SERIAL_RSA_BAUD_BASE; - break; - } - } -#endif - serial_outp(info, UART_LCR, save_lcr); - if (state->type == PORT_16450) { - scratch = serial_in(info, UART_SCR); - serial_outp(info, UART_SCR, 0xa5); - status1 = serial_in(info, UART_SCR); - serial_outp(info, UART_SCR, 0x5a); - status2 = serial_in(info, UART_SCR); - serial_outp(info, UART_SCR, scratch); - - if ((status1 != 0xa5) || (status2 != 0x5a)) - state->type = PORT_8250; - } - state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size; - - if (state->type == PORT_UNKNOWN) { - restore_flags(flags); - return; - } - - if (info->port) { -#ifdef CONFIG_SERIAL_RSA - if (state->type == PORT_RSA) - request_region(info->port + UART_RSA_BASE, 16, - "serial_rsa(auto)"); - else -#endif - request_region(info->port,8,"serial(auto)"); - } - - /* - * Reset the UART. - */ -#ifdef CONFIG_SERIAL_RSA - if (state->type == PORT_RSA) - serial_outp(info, UART_RSA_FRR, 0); -#endif - serial_outp(info, UART_MCR, save_mcr); - serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | - UART_FCR_CLEAR_XMIT)); - serial_outp(info, UART_FCR, 0); - (void)serial_in(info, UART_RX); - serial_outp(info, UART_IER, 0); - - restore_flags(flags); -} - -int register_serial(struct serial_struct *req); -void unregister_serial(int line); - -#if (LINUX_VERSION_CODE > 0x20100) -EXPORT_SYMBOL(register_serial); -EXPORT_SYMBOL(unregister_serial); -#else -static struct symbol_table serial_syms = { -#include <linux/symtab_begin.h> - X(register_serial), - X(unregister_serial), -#include <linux/symtab_end.h> -}; -#endif - - -#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) - -static void __devinit printk_pnp_dev_id(unsigned short vendor, - unsigned short device) -{ - printk("%c%c%c%x%x%x%x", - 'A' + ((vendor >> 2) & 0x3f) - 1, - 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, - 'A' + ((vendor >> 8) & 0x1f) - 1, - (device >> 4) & 0x0f, - device & 0x0f, - (device >> 12) & 0x0f, - (device >> 8) & 0x0f); -} - -static _INLINE_ int get_pci_port(struct pci_dev *dev, - struct pci_board *board, - struct serial_struct *req, - int idx) -{ - unsigned long port; - int base_idx; - int max_port; - int offset; - - base_idx = SPCI_FL_GET_BASE(board->flags); - if (board->flags & SPCI_FL_BASE_TABLE) - base_idx += idx; - - if (board->flags & SPCI_FL_REGION_SZ_CAP) { - max_port = pci_resource_len(dev, base_idx) / 8; - if (idx >= max_port) - return 1; - } - - offset = board->first_uart_offset; - - /* Timedia/SUNIX uses a mixture of BARs and offsets */ - /* Ugh, this is ugly as all hell --- TYT */ - if(dev->vendor == PCI_VENDOR_ID_TIMEDIA ) /* 0x1409 */ - switch(idx) { - case 0: base_idx=0; - break; - case 1: base_idx=0; offset=8; - break; - case 2: base_idx=1; - break; - case 3: base_idx=1; offset=8; - break; - case 4: /* BAR 2*/ - case 5: /* BAR 3 */ - case 6: /* BAR 4*/ - case 7: base_idx=idx-2; /* BAR 5*/ - } - - /* Some Titan cards are also a little weird */ - if (dev->vendor == PCI_VENDOR_ID_TITAN && - (dev->device == PCI_DEVICE_ID_TITAN_400L || - dev->device == PCI_DEVICE_ID_TITAN_800L)) { - switch (idx) { - case 0: base_idx = 1; - break; - case 1: base_idx = 2; - break; - default: - base_idx = 4; - offset = 8 * (idx - 2); - } - - } - - port = pci_resource_start(dev, base_idx) + offset; - - if ((board->flags & SPCI_FL_BASE_TABLE) == 0) - port += idx * (board->uart_offset ? board->uart_offset : 8); - - if (IS_PCI_REGION_IOPORT(dev, base_idx)) { - req->port = port; - if (HIGH_BITS_OFFSET) - req->port_high = port >> HIGH_BITS_OFFSET; - else - req->port_high = 0; - return 0; - } - req->io_type = SERIAL_IO_MEM; - req->iomem_base = ioremap(port, board->uart_offset); - req->iomem_reg_shift = board->reg_shift; - req->port = 0; - return 0; -} - -static _INLINE_ int get_pci_irq(struct pci_dev *dev, - struct pci_board *board, - int idx) -{ - int base_idx; - - if ((board->flags & SPCI_FL_IRQRESOURCE) == 0) - return dev->irq; - - base_idx = SPCI_FL_GET_IRQBASE(board->flags); - if (board->flags & SPCI_FL_IRQ_TABLE) - base_idx += idx; - - return PCI_IRQ_RESOURCE(dev, base_idx); -} - -/* - * Common enabler code shared by both PCI and ISAPNP probes - */ -static void __devinit start_pci_pnp_board(struct pci_dev *dev, - struct pci_board *board) -{ - int k, line; - struct serial_struct serial_req; - int base_baud; - - if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) { - printk("serial: PNP device '"); - printk_pnp_dev_id(dev->vendor, dev->device); - printk("' prepare failed\n"); - return; - } - - if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) { - printk("serial: PNP device '"); - printk_pnp_dev_id(dev->vendor, dev->device); - printk("' activate failed\n"); - return; - } - - /* - * Run the initialization function, if any - */ - if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0)) - return; - - /* - * Register the serial board in the array if we need to - * shutdown the board on a module unload or card removal - */ - if (DEACTIVATE_FUNC(dev) || board->init_fn) { - for (k=0; k < NR_PCI_BOARDS; k++) - if (serial_pci_board[k].dev == 0) - break; - if (k >= NR_PCI_BOARDS) - return; - serial_pci_board[k].board = *board; - serial_pci_board[k].dev = dev; - } - - base_baud = board->base_baud; - if (!base_baud) - base_baud = BASE_BAUD; - memset(&serial_req, 0, sizeof(serial_req)); - - for (k=0; k < board->num_ports; k++) { - serial_req.irq = get_pci_irq(dev, board, k); - if (get_pci_port(dev, board, &serial_req, k)) - break; - serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; -#ifdef SERIAL_DEBUG_PCI - printk("Setup PCI/PNP port: port %x, irq %d, type %d\n", - serial_req.port, serial_req.irq, serial_req.io_type); -#endif - line = register_serial(&serial_req); - if (line < 0) - break; - rs_table[line].baud_base = base_baud; - rs_table[line].dev = dev; - } -} -#endif /* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */ - -#ifdef ENABLE_SERIAL_PCI -/* - * Some PCI serial cards using the PLX 9050 PCI interface chip require - * that the card interrupt be explicitly enabled or disabled. This - * seems to be mainly needed on card using the PLX which also use I/O - * mapped memory. - */ -static int __devinit -pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable) -{ - u8 data, *p, irq_config; - int pci_config; - - irq_config = 0x41; - pci_config = PCI_COMMAND_MEMORY; - if (dev->vendor == PCI_VENDOR_ID_PANACOM) - irq_config = 0x43; - if ((dev->vendor == PCI_VENDOR_ID_PLX) && - (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) { - /* - * As the megawolf cards have the int pins active - * high, and have 2 UART chips, both ints must be - * enabled on the 9050. Also, the UARTS are set in - * 16450 mode by default, so we have to enable the - * 16C950 'enhanced' mode so that we can use the deep - * FIFOs - */ - irq_config = 0x5b; - pci_config = PCI_COMMAND_MEMORY | PCI_COMMAND_IO; - } - - pci_read_config_byte(dev, PCI_COMMAND, &data); - - if (enable) - pci_write_config_byte(dev, PCI_COMMAND, - data | pci_config); - - /* enable/disable interrupts */ - p = ioremap(pci_resource_start(dev, 0), 0x80); - writel(enable ? irq_config : 0x00, (unsigned long)p + 0x4c); - iounmap(p); - - if (!enable) - pci_write_config_byte(dev, PCI_COMMAND, - data & ~pci_config); - return 0; -} - - -/* - * SIIG serial cards have an PCI interface chip which also controls - * the UART clocking frequency. Each UART can be clocked independently - * (except cards equiped with 4 UARTs) and initial clocking settings - * are stored in the EEPROM chip. It can cause problems because this - * version of serial driver doesn't support differently clocked UART's - * on single PCI card. To prevent this, initialization functions set - * high frequency clocking for all UART's on given card. It is safe (I - * hope) because it doesn't touch EEPROM settings to prevent conflicts - * with other OSes (like M$ DOS). - * - * SIIG support added by Andrey Panin <pazke@mail.tp.ru>, 10/1999 - * - * There is two family of SIIG serial cards with different PCI - * interface chip and different configuration methods: - * - 10x cards have control registers in IO and/or memory space; - * - 20x cards have control registers in standard PCI configuration space. - */ - -#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc) -#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8) - -static int __devinit -pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable) -{ - u16 data, *p; - - if (!enable) return 0; - - p = ioremap(pci_resource_start(dev, 0), 0x80); - - switch (dev->device & 0xfff8) { - case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */ - data = 0xffdf; - break; - case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */ - data = 0xf7ff; - break; - default: /* 1S1P, 4S */ - data = 0xfffb; - break; - } - - writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28); - iounmap(p); - return 0; -} - -#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc) -#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc) - -static int __devinit -pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable) -{ - u8 data; - - if (!enable) return 0; - - /* Change clock frequency for the first UART. */ - pci_read_config_byte(dev, 0x6f, &data); - pci_write_config_byte(dev, 0x6f, data & 0xef); - - /* If this card has 2 UART, we have to do the same with second UART. */ - if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) || - ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) { - pci_read_config_byte(dev, 0x73, &data); - pci_write_config_byte(dev, 0x73, data & 0xef); - } - return 0; -} - -/* Added for EKF Intel i960 serial boards */ -static int __devinit -pci_inteli960ni_fn(struct pci_dev *dev, - struct pci_board *board, - int enable) -{ - unsigned long oldval; - - if (!(pci_get_subdevice(dev) & 0x1000)) - return(-1); - - if (!enable) /* is there something to deinit? */ - return(0); - -#ifdef SERIAL_DEBUG_PCI - printk(KERN_DEBUG " Subsystem ID %lx (intel 960)\n", - (unsigned long) board->subdevice); -#endif - /* is firmware started? */ - pci_read_config_dword(dev, 0x44, (void*) &oldval); - if (oldval == 0x00001000L) { /* RESET value */ - printk(KERN_DEBUG "Local i960 firmware missing"); - return(-1); - } - return(0); -} - -/* - * Timedia has an explosion of boards, and to avoid the PCI table from - * growing *huge*, we use this function to collapse some 70 entries - * in the PCI table into one, for sanity's and compactness's sake. - */ -static unsigned short timedia_single_port[] = { - 0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0 }; -static unsigned short timedia_dual_port[] = { - 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085, - 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, - 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, - 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079, - 0xD079, 0 }; -static unsigned short timedia_quad_port[] = { - 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, - 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, - 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056, - 0xB157, 0 }; -static unsigned short timedia_eight_port[] = { - 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, - 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 }; -static struct timedia_struct { - int num; - unsigned short *ids; -} timedia_data[] = { - { 1, timedia_single_port }, - { 2, timedia_dual_port }, - { 4, timedia_quad_port }, - { 8, timedia_eight_port }, - { 0, 0 } -}; - -static int __devinit -pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable) -{ - int i, j; - unsigned short *ids; - - if (!enable) - return 0; - - for (i=0; timedia_data[i].num; i++) { - ids = timedia_data[i].ids; - for (j=0; ids[j]; j++) { - if (pci_get_subdevice(dev) == ids[j]) { - board->num_ports = timedia_data[i].num; - return 0; - } - } - } - return 0; -} - -static int __devinit -pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable) -{ - __set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); - return 0; -} - -/* - * This is the configuration table for all of the PCI serial boards - * which we support. It is directly indexed by the pci_board_num_t enum - * value, which is encoded in the pci_device_id PCI probe table's - * driver_data member. - */ -enum pci_board_num_t { - pbn_b0_1_115200, - pbn_default = 0, - - pbn_b0_2_115200, - pbn_b0_4_115200, - - pbn_b0_1_921600, - pbn_b0_2_921600, - pbn_b0_4_921600, - - pbn_b0_bt_1_115200, - pbn_b0_bt_2_115200, - pbn_b0_bt_1_460800, - pbn_b0_bt_2_460800, - - pbn_b1_1_115200, - pbn_b1_2_115200, - pbn_b1_4_115200, - pbn_b1_8_115200, - - pbn_b1_2_921600, - pbn_b1_4_921600, - pbn_b1_8_921600, - - pbn_b1_2_1382400, - pbn_b1_4_1382400, - pbn_b1_8_1382400, - - pbn_b2_8_115200, - pbn_b2_4_460800, - pbn_b2_8_460800, - pbn_b2_16_460800, - pbn_b2_4_921600, - pbn_b2_8_921600, - - pbn_b2_bt_1_115200, - pbn_b2_bt_2_115200, - pbn_b2_bt_4_115200, - pbn_b2_bt_2_921600, - - pbn_panacom, - pbn_panacom2, - pbn_panacom4, - pbn_plx_romulus, - pbn_oxsemi, - pbn_timedia, - pbn_intel_i960, - pbn_sgi_ioc3, -#ifdef CONFIG_DDB5074 - pbn_nec_nile4, -#endif -#if 0 - pbn_dci_pccom8, -#endif - pbn_xircom_combo, - - pbn_siig10x_0, - pbn_siig10x_1, - pbn_siig10x_2, - pbn_siig10x_4, - pbn_siig20x_0, - pbn_siig20x_2, - pbn_siig20x_4, - - pbn_computone_4, - pbn_computone_6, - pbn_computone_8, -}; - -static struct pci_board pci_boards[] __devinitdata = { - /* - * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, - * Offset to get to next UART's registers, - * Register shift to use for memory-mapped I/O, - * Initialization function, first UART offset - */ - - /* Generic serial board, pbn_b0_1_115200, pbn_default */ - { SPCI_FL_BASE0, 1, 115200 }, /* pbn_b0_1_115200, - pbn_default */ - - { SPCI_FL_BASE0, 2, 115200 }, /* pbn_b0_2_115200 */ - { SPCI_FL_BASE0, 4, 115200 }, /* pbn_b0_4_115200 */ - - { SPCI_FL_BASE0, 1, 921600 }, /* pbn_b0_1_921600 */ - { SPCI_FL_BASE0, 2, 921600 }, /* pbn_b0_2_921600 */ - { SPCI_FL_BASE0, 4, 921600 }, /* pbn_b0_4_921600 */ - - { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */ - { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */ - { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */ - { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */ - - { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */ - { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */ - { SPCI_FL_BASE1, 4, 115200 }, /* pbn_b1_4_115200 */ - { SPCI_FL_BASE1, 8, 115200 }, /* pbn_b1_8_115200 */ - - { SPCI_FL_BASE1, 2, 921600 }, /* pbn_b1_2_921600 */ - { SPCI_FL_BASE1, 4, 921600 }, /* pbn_b1_4_921600 */ - { SPCI_FL_BASE1, 8, 921600 }, /* pbn_b1_8_921600 */ - - { SPCI_FL_BASE1, 2, 1382400 }, /* pbn_b1_2_1382400 */ - { SPCI_FL_BASE1, 4, 1382400 }, /* pbn_b1_4_1382400 */ - { SPCI_FL_BASE1, 8, 1382400 }, /* pbn_b1_8_1382400 */ - - { SPCI_FL_BASE2, 8, 115200 }, /* pbn_b2_8_115200 */ - { SPCI_FL_BASE2, 4, 460800 }, /* pbn_b2_4_460800 */ - { SPCI_FL_BASE2, 8, 460800 }, /* pbn_b2_8_460800 */ - { SPCI_FL_BASE2, 16, 460800 }, /* pbn_b2_16_460800 */ - { SPCI_FL_BASE2, 4, 921600 }, /* pbn_b2_4_921600 */ - { SPCI_FL_BASE2, 8, 921600 }, /* pbn_b2_8_921600 */ - - { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b2_bt_1_115200 */ - { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b2_bt_2_115200 */ - { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, /* pbn_b2_bt_4_115200 */ - { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b2_bt_2_921600 */ - - { SPCI_FL_BASE2, 2, 921600, /* IOMEM */ /* pbn_panacom */ - 0x400, 7, pci_plx9050_fn }, - { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_panacom2 */ - 0x400, 7, pci_plx9050_fn }, - { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_panacom4 */ - 0x400, 7, pci_plx9050_fn }, - { SPCI_FL_BASE2, 4, 921600, /* pbn_plx_romulus */ - 0x20, 2, pci_plx9050_fn, 0x03 }, - /* This board uses the size of PCI Base region 0 to - * signal now many ports are available */ - { SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */ - { SPCI_FL_BASE_TABLE, 1, 921600, /* pbn_timedia */ - 0, 0, pci_timedia_fn }, - /* EKF addition for i960 Boards form EKF with serial port */ - { SPCI_FL_BASE0, 32, 921600, /* max 256 ports */ /* pbn_intel_i960 */ - 8<<2, 2, pci_inteli960ni_fn, 0x10000}, - { SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE, /* pbn_sgi_ioc3 */ - 1, 458333, 0, 0, 0, 0x20178 }, -#ifdef CONFIG_DDB5074 - /* - * NEC Vrc-5074 (Nile 4) builtin UART. - * Conditionally compiled in since this is a motherboard device. - */ - { SPCI_FL_BASE0, 1, 520833, /* pbn_nec_nile4 */ - 64, 3, NULL, 0x300 }, -#endif -#if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */ /* pbn_dci_pccom8 */ - { SPCI_FL_BASE3, 8, 115200, 8 }, -#endif - { SPCI_FL_BASE0, 1, 115200, /* pbn_xircom_combo */ - 0, 0, pci_xircom_fn }, - - { SPCI_FL_BASE2, 1, 460800, /* pbn_siig10x_0 */ - 0, 0, pci_siig10x_fn }, - { SPCI_FL_BASE2, 1, 921600, /* pbn_siig10x_1 */ - 0, 0, pci_siig10x_fn }, - { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siig10x_2 */ - 0, 0, pci_siig10x_fn }, - { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siig10x_4 */ - 0, 0, pci_siig10x_fn }, - { SPCI_FL_BASE0, 1, 921600, /* pbn_siix20x_0 */ - 0, 0, pci_siig20x_fn }, - { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siix20x_2 */ - 0, 0, pci_siig20x_fn }, - { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siix20x_4 */ - 0, 0, pci_siig20x_fn }, - - { SPCI_FL_BASE0, 4, 921600, /* IOMEM */ /* pbn_computone_4 */ - 0x40, 2, NULL, 0x200 }, - { SPCI_FL_BASE0, 6, 921600, /* IOMEM */ /* pbn_computone_6 */ - 0x40, 2, NULL, 0x200 }, - { SPCI_FL_BASE0, 8, 921600, /* IOMEM */ /* pbn_computone_8 */ - 0x40, 2, NULL, 0x200 }, -}; - -/* - * Given a complete unknown PCI device, try to use some heuristics to - * guess what the configuration might be, based on the pitiful PCI - * serial specs. Returns 0 on success, 1 on failure. - */ -static int __devinit serial_pci_guess_board(struct pci_dev *dev, - struct pci_board *board) -{ - int num_iomem = 0, num_port = 0, first_port = -1; - int i; - - /* - * If it is not a communications device or the programming - * interface is greater than 6, give up. - * - * (Should we try to make guesses for multiport serial devices - * later?) - */ - if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) && - ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || - (dev->class & 0xff) > 6) - return 1; - - for (i=0; i < 6; i++) { - if (IS_PCI_REGION_IOPORT(dev, i)) { - num_port++; - if (first_port == -1) - first_port = i; - } - if (IS_PCI_REGION_IOMEM(dev, i)) - num_iomem++; - } - - /* - * If there is 1 or 0 iomem regions, and exactly one port, use - * it. - */ - if (num_iomem <= 1 && num_port == 1) { - board->flags = first_port; - return 0; - } - return 1; -} - -static int __devinit serial_init_one(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - struct pci_board *board, tmp; - int rc; - - board = &pci_boards[ent->driver_data]; - - rc = pci_enable_device(dev); - if (rc) return rc; - - if (ent->driver_data == pbn_default && - serial_pci_guess_board(dev, board)) - return -ENODEV; - else if (serial_pci_guess_board(dev, &tmp) == 0) { - printk(KERN_INFO "Redundant entry in serial pci_table. " - "Please send the output of\n" - "lspci -vv, this message (%04x,%04x,%04x,%04x)\n" - "and the manufacturer and name of " - "serial board or modem board\n" - "to serial-pci-info@lists.sourceforge.net.\n", - dev->vendor, dev->device, - pci_get_subvendor(dev), pci_get_subdevice(dev)); - } - - start_pci_pnp_board(dev, board); - - return 0; -} - -static void __devexit serial_remove_one(struct pci_dev *dev) -{ - int i; - - /* - * Iterate through all of the ports finding those that belong - * to this PCI device. - */ - for(i = 0; i < NR_PORTS; i++) { - if (rs_table[i].dev != dev) - continue; - unregister_serial(i); - rs_table[i].dev = 0; - } - /* - * Now execute any board-specific shutdown procedure - */ - for (i=0; i < NR_PCI_BOARDS; i++) { - struct pci_board_inst *brd = &serial_pci_board[i]; - - if (serial_pci_board[i].dev != dev) - continue; - if (brd->board.init_fn) - (brd->board.init_fn)(brd->dev, &brd->board, 0); - if (DEACTIVATE_FUNC(brd->dev)) - (DEACTIVATE_FUNC(brd->dev))(brd->dev); - serial_pci_board[i].dev = 0; - } -} - - -static struct pci_device_id serial_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, - pbn_b1_8_1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0, - pbn_b1_4_1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0, - pbn_b1_2_1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, - pbn_b1_8_1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0, - pbn_b1_4_1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0, - pbn_b1_2_1382400 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0, - pbn_b1_8_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0, - pbn_b1_8_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0, - pbn_b1_4_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0, - pbn_b1_4_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0, - pbn_b1_2_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0, - pbn_b1_8_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0, - pbn_b1_8_921600 }, - { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, - PCI_SUBVENDOR_ID_CONNECT_TECH, - PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0, - pbn_b1_4_921600 }, - - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_1_115200 }, - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_115200 }, - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_4_115200 }, - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_115200 }, - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_4_115200 }, - { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_8_115200 }, - - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_115200 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_921600 }, - /* VScom SPCOM800, from sl@s.pl */ - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_8_921600 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_4_921600 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_KEYSPAN, - PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0, - pbn_panacom }, - { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_panacom4 }, - { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_panacom2 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, - pbn_b2_4_460800 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, - pbn_b2_8_460800 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, - pbn_b2_16_460800 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, - pbn_b2_16_460800 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_CHASE_PCIRAS, - PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, - pbn_b2_4_460800 }, - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, - PCI_SUBVENDOR_ID_CHASE_PCIRAS, - PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, - pbn_b2_8_460800 }, - /* Megawolf Romulus PCI Serial Card, from Mike Hudson */ - /* (Exoray@isys.ca) */ - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS, - 0x10b5, 0x106a, 0, 0, - pbn_plx_romulus }, - { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_4_115200 }, - { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_2_115200 }, - { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_8_115200 }, - { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_8_115200 }, - { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0, - pbn_b0_4_921600 }, - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_4_115200 }, - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_2_115200 }, - - /* Digitan DS560-558, from jimd@esoft.com */ - { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b1_1_115200 }, - - /* 3Com US Robotics 56k Voice Internal PCI model 5610 */ - { PCI_VENDOR_ID_USR, 0x1008, - PCI_ANY_ID, PCI_ANY_ID, }, - - /* Titan Electronic cards */ - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_1_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_2_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_4_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_4_921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE1, 1, 921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 }, - /* The 400L and 800L have a custom hack in get_pci_port */ - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE_TABLE, 4, 921600 }, - { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L, - PCI_ANY_ID, PCI_ANY_ID, - SPCI_FL_BASE_TABLE, 8, 921600 }, - - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_1 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_1 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_1 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_4 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_4 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig10x_4 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_0 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_2 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_4 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_4 }, - { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_siig20x_4 }, - - /* Computone devices submitted by Doug McNash dmcnash@computone.com */ - { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, - PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4, - 0, 0, pbn_computone_4 }, - { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, - PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8, - 0, 0, pbn_computone_8 }, - { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, - PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6, - 0, 0, pbn_computone_6 }, - - { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi }, - { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, - PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia }, - - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_2_460800 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_1_115200 }, - { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b0_bt_1_460800 }, - - /* RAStel 2 port modem, gerg@moreton.com.au */ - { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_b2_bt_2_115200 }, - - /* EKF addition for i960 Boards form EKF with serial port */ - { PCI_VENDOR_ID_INTEL, 0x1960, - 0xE4BF, PCI_ANY_ID, 0, 0, - pbn_intel_i960 }, - - /* Xircom Cardbus/Ethernet combos */ - { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_xircom_combo }, - - /* - * Untested PCI modems, sent in from various folks... - */ - - /* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */ - { PCI_VENDOR_ID_ROCKWELL, 0x1004, - 0x1048, 0x1500, 0, 0, - pbn_b1_1_115200 }, - - { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, - 0xFF00, 0, 0, 0, - pbn_sgi_ioc3 }, - -#ifdef CONFIG_DDB5074 - /* - * NEC Vrc-5074 (Nile 4) builtin UART. - * Conditionally compiled in since this is a motherboard device. - */ - { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_nec_nile4 }, -#endif - -#if 0 /* PCI_DEVICE_ID_DCI_PCCOM8 ? */ - { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_dci_pccom8 }, -#endif - - { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_SERIAL << 8, 0xffff00, }, - { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, - PCI_CLASS_COMMUNICATION_MODEM << 8, 0xffff00, }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, serial_pci_tbl); - -static struct pci_driver serial_pci_driver = { - name: "serial", - probe: serial_init_one, - remove: __devexit_p(serial_remove_one), - id_table: serial_pci_tbl, -}; - - -/* - * Query PCI space for known serial boards - * If found, add them to the PCI device space in rs_table[] - * - * Accept a maximum of eight boards - * - */ -static void __devinit probe_serial_pci(void) -{ -#ifdef SERIAL_DEBUG_PCI - printk(KERN_DEBUG "Entered probe_serial_pci()\n"); -#endif - - /* Register call PCI serial devices. Null out - * the driver name upon failure, as a signal - * not to attempt to unregister the driver later - */ - if (pci_module_init (&serial_pci_driver) != 0) - serial_pci_driver.name = ""; - -#ifdef SERIAL_DEBUG_PCI - printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n"); -#endif - return; -} - -#endif /* ENABLE_SERIAL_PCI */ - -#ifdef ENABLE_SERIAL_PNP - -struct pnp_board { - unsigned short vendor; - unsigned short device; -}; - -static struct pnp_board pnp_devices[] __devinitdata = { - /* Archtek America Corp. */ - /* Archtek SmartLink Modem 3334BT Plug & Play */ - { ISAPNP_VENDOR('A', 'A', 'C'), ISAPNP_DEVICE(0x000F) }, - /* Anchor Datacomm BV */ - /* SXPro 144 External Data Fax Modem Plug & Play */ - { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0001) }, - /* SXPro 288 External Data Fax Modem Plug & Play */ - { ISAPNP_VENDOR('A', 'D', 'C'), ISAPNP_DEVICE(0x0002) }, - /* Rockwell 56K ACF II Fax+Data+Voice Modem */ - { ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021) }, - /* AZT3005 PnP SOUND DEVICE */ - { ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001) }, - /* Best Data Products Inc. Smart One 336F PnP Modem */ - { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) }, - /* Boca Research */ - /* Boca Complete Ofc Communicator 14.4 Data-FAX */ - { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) }, - /* Boca Research 33,600 ACF Modem */ - { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400) }, - /* Boca 33.6 Kbps Internal FD34FSVD */ - { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x3400) }, - /* Boca 33.6 Kbps Internal FD34FSVD */ - { ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x0A49) }, - /* Best Data Products Inc. Smart One 336F PnP Modem */ - { ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336) }, - /* Computer Peripherals Inc */ - /* EuroViVa CommCenter-33.6 SP PnP */ - { ISAPNP_VENDOR('C', 'P', 'I'), ISAPNP_DEVICE(0x4050) }, - /* Creative Labs */ - /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */ - { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3001) }, - /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */ - { ISAPNP_VENDOR('C', 'T', 'L'), ISAPNP_DEVICE(0x3011) }, - /* Creative */ - /* Creative Modem Blaster Flash56 DI5601-1 */ - { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032) }, - /* Creative Modem Blaster V.90 DI5660 */ - { ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001) }, - /* FUJITSU */ - /* Fujitsu 33600 PnP-I2 R Plug & Play */ - { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0202) }, - /* Fujitsu FMV-FX431 Plug & Play */ - { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0205) }, - /* Fujitsu 33600 PnP-I4 R Plug & Play */ - { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0206) }, - /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */ - { ISAPNP_VENDOR('F', 'U', 'J'), ISAPNP_DEVICE(0x0209) }, - /* Archtek America Corp. */ - /* Archtek SmartLink Modem 3334BT Plug & Play */ - { ISAPNP_VENDOR('G', 'V', 'C'), ISAPNP_DEVICE(0x000F) }, - /* Hayes */ - /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x0001) }, - /* Hayes Optima 336 V.34 + FAX + Voice PnP */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000C) }, - /* Hayes Optima 336B V.34 + FAX + Voice PnP */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x000D) }, - /* Hayes Accura 56K Ext Fax Modem PnP */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5670) }, - /* Hayes Accura 56K Ext Fax Modem PnP */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5674) }, - /* Hayes Accura 56K Fax Modem PnP */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0x5675) }, - /* Hayes 288, V.34 + FAX */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF000) }, - /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */ - { ISAPNP_VENDOR('H', 'A', 'Y'), ISAPNP_DEVICE(0xF001) }, - /* IBM */ - /* IBM Thinkpad 701 Internal Modem Voice */ - { ISAPNP_VENDOR('I', 'B', 'M'), ISAPNP_DEVICE(0x0033) }, - /* Intertex */ - /* Intertex 28k8 33k6 Voice EXT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC801) }, - /* Intertex 33k6 56k Voice EXT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xC901) }, - /* Intertex 28k8 33k6 Voice SP EXT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD801) }, - /* Intertex 33k6 56k Voice SP EXT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xD901) }, - /* Intertex 28k8 33k6 Voice SP INT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF401) }, - /* Intertex 28k8 33k6 Voice SP EXT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF801) }, - /* Intertex 33k6 56k Voice SP EXT PnP */ - { ISAPNP_VENDOR('I', 'X', 'D'), ISAPNP_DEVICE(0xF901) }, - /* Kortex International */ - /* KORTEX 28800 Externe PnP */ - { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0x4522) }, - /* KXPro 33.6 Vocal ASVD PnP */ - { ISAPNP_VENDOR('K', 'O', 'R'), ISAPNP_DEVICE(0xF661) }, - /* Lasat */ - /* LASAT Internet 33600 PnP */ - { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4040) }, - /* Lasat Safire 560 PnP */ - { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x4540) }, - /* Lasat Safire 336 PnP */ - { ISAPNP_VENDOR('L', 'A', 'S'), ISAPNP_DEVICE(0x5440) }, - /* Microcom, Inc. */ - /* Microcom TravelPorte FAST V.34 Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x281) }, - /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0336) }, - /* Microcom DeskPorte FAST EP 28.8 Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0339) }, - /* Microcom DeskPorte 28.8P Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0342) }, - /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0500) }, - /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0501) }, - /* Microcom DeskPorte 28.8S Internal Plug & Play */ - { ISAPNP_VENDOR('M', 'N', 'P'), ISAPNP_DEVICE(0x0502) }, - /* Motorola */ - /* Motorola BitSURFR Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1105) }, - /* Motorola TA210 Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1111) }, - /* Motorola HMTA 200 (ISDN) Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1114) }, - /* Motorola BitSURFR Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1115) }, - /* Motorola Lifestyle 28.8 Internal */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1190) }, - /* Motorola V.3400 Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1501) }, - /* Motorola Lifestyle 28.8 V.34 Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1502) }, - /* Motorola Power 28.8 V.34 Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1505) }, - /* Motorola ModemSURFR External 28.8 Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1509) }, - /* Motorola Premier 33.6 Desktop Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150A) }, - /* Motorola VoiceSURFR 56K External PnP */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x150F) }, - /* Motorola ModemSURFR 56K External PnP */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1510) }, - /* Motorola ModemSURFR 56K Internal PnP */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1550) }, - /* Motorola ModemSURFR Internal 28.8 Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1560) }, - /* Motorola Premier 33.6 Internal Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x1580) }, - /* Motorola OnlineSURFR 28.8 Internal Plug & Play */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15B0) }, - /* Motorola VoiceSURFR 56K Internal PnP */ - { ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0) }, - /* Com 1 */ - /* Deskline K56 Phone System PnP */ - { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00A1) }, - /* PC Rider K56 Phone System PnP */ - { ISAPNP_VENDOR('M', 'V', 'X'), ISAPNP_DEVICE(0x00F2) }, - /* Pace 56 Voice Internal Plug & Play Modem */ - { ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430) }, - /* Generic */ - /* Generic standard PC COM port */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500) }, - /* Generic 16550A-compatible COM port */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501) }, - /* Compaq 14400 Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000) }, - /* Compaq 2400/9600 Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001) }, - /* Dial-Up Networking Serial Cable between 2 PCs */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC031) }, - /* Dial-Up Networking Parallel Cable between 2 PCs */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC032) }, - /* Standard 9600 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC100) }, - /* Standard 14400 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC101) }, - /* Standard 28800 bps Modem*/ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC102) }, - /* Standard Modem*/ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC103) }, - /* Standard 9600 bps Modem*/ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC104) }, - /* Standard 14400 bps Modem*/ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC105) }, - /* Standard 28800 bps Modem*/ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC106) }, - /* Standard Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC107) }, - /* Standard 9600 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC108) }, - /* Standard 14400 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC109) }, - /* Standard 28800 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10A) }, - /* Standard Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10B) }, - /* Standard 9600 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10C) }, - /* Standard 14400 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10D) }, - /* Standard 28800 bps Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10E) }, - /* Standard Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC10F) }, - /* Standard PCMCIA Card Modem */ - { ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x2000) }, - /* Rockwell */ - /* Modular Technology */ - /* Rockwell 33.6 DPF Internal PnP */ - /* Modular Technology 33.6 Internal PnP */ - { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0030) }, - /* Kortex International */ - /* KORTEX 14400 Externe PnP */ - { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x0100) }, - /* Viking Components, Inc */ - /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */ - { ISAPNP_VENDOR('R', 'O', 'K'), ISAPNP_DEVICE(0x4920) }, - /* Rockwell */ - /* British Telecom */ - /* Modular Technology */ - /* Rockwell 33.6 DPF External PnP */ - /* BT Prologue 33.6 External PnP */ - /* Modular Technology 33.6 External PnP */ - { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x00A0) }, - /* Viking 56K FAX INT */ - { ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262) }, - /* SupraExpress 28.8 Data/Fax PnP modem */ - { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310) }, - /* SupraExpress 33.6 Data/Fax PnP modem */ - { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1421) }, - /* SupraExpress 33.6 Data/Fax PnP modem */ - { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1590) }, - /* SupraExpress 33.6 Data/Fax PnP modem */ - { ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1760) }, - /* Phoebe Micro */ - /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */ - { ISAPNP_VENDOR('T', 'E', 'X'), ISAPNP_DEVICE(0x0011) }, - /* Archtek America Corp. */ - /* Archtek SmartLink Modem 3334BT Plug & Play */ - { ISAPNP_VENDOR('U', 'A', 'C'), ISAPNP_DEVICE(0x000F) }, - /* 3Com Corp. */ - /* Gateway Telepath IIvi 33.6 */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0000) }, - /* Sportster Vi 14.4 PnP FAX Voicemail */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0004) }, - /* U.S. Robotics 33.6K Voice INT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006) }, - /* U.S. Robotics 33.6K Voice EXT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0007) }, - /* U.S. Robotics 33.6K Voice INT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2002) }, - /* U.S. Robotics 56K Voice INT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2070) }, - /* U.S. Robotics 56K Voice EXT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x2080) }, - /* U.S. Robotics 56K FAX INT */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031) }, - /* U.S. Robotics 56K Voice INT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3070) }, - /* U.S. Robotics 56K Voice EXT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3080) }, - /* U.S. Robotics 56K Voice INT PnP */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3090) }, - /* U.S. Robotics 56K Message */ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9100) }, - /* U.S. Robotics 56K FAX EXT PnP*/ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9160) }, - /* U.S. Robotics 56K FAX INT PnP*/ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9170) }, - /* U.S. Robotics 56K Voice EXT PnP*/ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9180) }, - /* U.S. Robotics 56K Voice INT PnP*/ - { ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x9190) }, - { 0, } -}; - -static void inline avoid_irq_share(struct pci_dev *dev) -{ - int i; - unsigned long map = 0x1FF8; - struct serial_state *state = rs_table; - struct isapnp_irq *irq; - struct isapnp_resources *res = dev->sysdata; - - for (i = 0; i < NR_PORTS; i++) { - if (state->type != PORT_UNKNOWN) - clear_bit(state->irq, &map); - state++; - } - - for ( ; res; res = res->alt) - for(irq = res->irq; irq; irq = irq->next) - irq->map = map; -} - -static char *modem_names[] __devinitdata = { - "MODEM", "Modem", "modem", "FAX", "Fax", "fax", - "56K", "56k", "K56", "33.6", "28.8", "14.4", - "33,600", "28,800", "14,400", "33.600", "28.800", "14.400", - "33600", "28800", "14400", "V.90", "V.34", "V.32", 0 -}; - -static int __devinit check_name(char *name) -{ - char **tmp = modem_names; - - while (*tmp) { - if (strstr(name, *tmp)) - return 1; - tmp++; - } - return 0; -} - -static int inline check_compatible_id(struct pci_dev *dev) -{ - int i; - for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++) - if ((dev->vendor_compatible[i] == - ISAPNP_VENDOR('P', 'N', 'P')) && - (swab16(dev->device_compatible[i]) >= 0xc000) && - (swab16(dev->device_compatible[i]) <= 0xdfff)) - return 0; - return 1; -} - -/* - * Given a complete unknown ISA PnP device, try to use some heuristics to - * detect modems. Currently use such heuristic set: - * - dev->name or dev->bus->name must contain "modem" substring; - * - device must have only one IO region (8 byte long) with base adress - * 0x2e8, 0x3e8, 0x2f8 or 0x3f8. - * - * Such detection looks very ugly, but can detect at least some of numerous - * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[] - * table. - */ -static int _INLINE_ serial_pnp_guess_board(struct pci_dev *dev, - struct pci_board *board) -{ - struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata; - struct isapnp_resources *resa; - - if (!(check_name(dev->name) || check_name(dev->bus->name)) && - !(check_compatible_id(dev))) - return 1; - - if (!res || res->next) - return 1; - - for (resa = res->alt; resa; resa = resa->alt) { - struct isapnp_port *port; - for (port = res->port; port; port = port->next) - if ((port->size == 8) && - ((port->min == 0x2f8) || - (port->min == 0x3f8) || - (port->min == 0x2e8) || - (port->min == 0x3e8))) - return 0; - } - - return 1; -} - -static void __devinit probe_serial_pnp(void) -{ - struct pci_dev *dev = NULL; - struct pnp_board *pnp_board; - struct pci_board board; - -#ifdef SERIAL_DEBUG_PNP - printk("Entered probe_serial_pnp()\n"); -#endif - if (!isapnp_present()) { -#ifdef SERIAL_DEBUG_PNP - printk("Leaving probe_serial_pnp() (no isapnp)\n"); -#endif - return; - } - - isapnp_for_each_dev(dev) { - if (dev->active) - continue; - - memset(&board, 0, sizeof(board)); - board.flags = SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT; - board.num_ports = 1; - board.base_baud = 115200; - - for (pnp_board = pnp_devices; pnp_board->vendor; pnp_board++) - if ((dev->vendor == pnp_board->vendor) && - (dev->device == pnp_board->device)) - break; - - if (pnp_board->vendor) { - /* Special case that's more efficient to hardcode */ - if ((pnp_board->vendor == ISAPNP_VENDOR('A', 'K', 'Y') && - pnp_board->device == ISAPNP_DEVICE(0x1021))) - board.flags |= SPCI_FL_NO_SHIRQ; - } else { - if (serial_pnp_guess_board(dev, &board)) - continue; - } - - if (board.flags & SPCI_FL_NO_SHIRQ) - avoid_irq_share(dev); - start_pci_pnp_board(dev, &board); - } - -#ifdef SERIAL_DEBUG_PNP - printk("Leaving probe_serial_pnp() (probe finished)\n"); -#endif - return; -} - -#endif /* ENABLE_SERIAL_PNP */ - -/* - * The serial driver boot-time initialization code! - */ -static int __init rs_init(void) -{ - int i; - struct serial_state * state; - - init_bh(SERIAL_BH, do_serial_bh); - init_timer(&serial_timer); - serial_timer.function = rs_timer; - mod_timer(&serial_timer, jiffies + RS_STROBE_TIME); - - for (i = 0; i < NR_IRQS; i++) { - IRQ_ports[i] = 0; - IRQ_timeout[i] = 0; -#ifdef CONFIG_SERIAL_MULTIPORT - memset(&rs_multiport[i], 0, - sizeof(struct rs_multiport_struct)); -#endif - } -#ifdef CONFIG_SERIAL_CONSOLE - /* - * The interrupt of the serial console port - * can't be shared. - */ - if (sercons.flags & CON_CONSDEV) { - for(i = 0; i < NR_PORTS; i++) - if (i != sercons.index && - rs_table[i].irq == rs_table[sercons.index].irq) - rs_table[i].irq = 0; - } -#endif - show_serial_version(); - - /* Initialize the tty_driver structure */ - - memset(&serial_driver, 0, sizeof(struct tty_driver)); - serial_driver.magic = TTY_DRIVER_MAGIC; -#if (LINUX_VERSION_CODE > 0x20100) - serial_driver.driver_name = "serial"; -#endif -#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) - serial_driver.name = "tts/%d"; -#else - serial_driver.name = "ttyS"; -#endif - serial_driver.major = TTY_MAJOR; - serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; - serial_driver.num = NR_PORTS; - serial_driver.type = TTY_DRIVER_TYPE_SERIAL; - serial_driver.subtype = SERIAL_TYPE_NORMAL; - serial_driver.init_termios = tty_std_termios; - serial_driver.init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; - serial_driver.refcount = &serial_refcount; - serial_driver.table = serial_table; - serial_driver.termios = serial_termios; - serial_driver.termios_locked = serial_termios_locked; - - serial_driver.open = rs_open; - serial_driver.close = rs_close; - serial_driver.write = rs_write; - serial_driver.put_char = rs_put_char; - serial_driver.flush_chars = rs_flush_chars; - serial_driver.write_room = rs_write_room; - serial_driver.chars_in_buffer = rs_chars_in_buffer; - serial_driver.flush_buffer = rs_flush_buffer; - serial_driver.ioctl = rs_ioctl; - serial_driver.throttle = rs_throttle; - serial_driver.unthrottle = rs_unthrottle; - serial_driver.set_termios = rs_set_termios; - serial_driver.stop = rs_stop; - serial_driver.start = rs_start; - serial_driver.hangup = rs_hangup; -#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */ - serial_driver.break_ctl = rs_break; -#endif -#if (LINUX_VERSION_CODE >= 131343) - serial_driver.send_xchar = rs_send_xchar; - serial_driver.wait_until_sent = rs_wait_until_sent; - serial_driver.read_proc = rs_read_proc; -#endif - - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; -#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) - callout_driver.name = "cua/%d"; -#else - callout_driver.name = "cua"; -#endif - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; -#if (LINUX_VERSION_CODE >= 131343) - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; -#endif - - if (tty_register_driver(&serial_driver)) - panic("Couldn't register serial driver\n"); - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); - - for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { - state->magic = SSTATE_MAGIC; - state->line = i; - state->type = PORT_UNKNOWN; - state->custom_divisor = 0; - state->close_delay = 5*HZ/10; - state->closing_wait = 30*HZ; - state->callout_termios = callout_driver.init_termios; - state->normal_termios = serial_driver.init_termios; - state->icount.cts = state->icount.dsr = - state->icount.rng = state->icount.dcd = 0; - state->icount.rx = state->icount.tx = 0; - state->icount.frame = state->icount.parity = 0; - state->icount.overrun = state->icount.brk = 0; - state->irq = irq_cannonicalize(state->irq); - if (state->hub6) - state->io_type = SERIAL_IO_HUB6; - if (state->port && check_region(state->port,8)) - continue; -#ifdef CONFIG_MCA - if ((state->flags & ASYNC_BOOT_ONLYMCA) && !MCA_bus) - continue; -#endif - if (state->flags & ASYNC_BOOT_AUTOCONF) - autoconfig(state); - } - for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { - if (state->type == PORT_UNKNOWN) - continue; - if ( (state->flags & ASYNC_BOOT_AUTOCONF) - && (state->flags & ASYNC_AUTO_IRQ) - && (state->port != 0 || state->iomem_base != 0)) - state->irq = detect_uart_irq(state); - if (state->io_type == SERIAL_IO_MEM) { - printk(KERN_INFO"ttyS%02d%s at 0x%px (irq = %d) is a %s\n", - state->line + SERIAL_DEV_OFFSET, - (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", - state->iomem_base, state->irq, - uart_config[state->type].name); - } - else { - printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n", - state->line + SERIAL_DEV_OFFSET, - (state->flags & ASYNC_FOURPORT) ? " FourPort" : "", - state->port, state->irq, - uart_config[state->type].name); - } - tty_register_devfs(&serial_driver, 0, - serial_driver.minor_start + state->line); - tty_register_devfs(&callout_driver, 0, - callout_driver.minor_start + state->line); - } -#ifdef ENABLE_SERIAL_PCI - probe_serial_pci(); -#endif -#ifdef ENABLE_SERIAL_PNP - probe_serial_pnp(); -#endif - return 0; -} - -/* - * This is for use by architectures that know their serial console - * attributes only at run time. Not to be invoked after rs_init(). - */ -int __init early_serial_setup(struct serial_struct *req) -{ - int i = req->line; - - if (i >= NR_IRQS) - return(-ENOENT); - rs_table[i].magic = 0; - rs_table[i].baud_base = req->baud_base; - rs_table[i].port = req->port; - if (HIGH_BITS_OFFSET) - rs_table[i].port += (unsigned long) req->port_high << - HIGH_BITS_OFFSET; - rs_table[i].irq = req->irq; - rs_table[i].flags = req->flags; - rs_table[i].close_delay = req->close_delay; - rs_table[i].io_type = req->io_type; - rs_table[i].hub6 = req->hub6; - rs_table[i].iomem_base = req->iomem_base; - rs_table[i].iomem_reg_shift = req->iomem_reg_shift; - rs_table[i].type = req->type; - rs_table[i].xmit_fifo_size = req->xmit_fifo_size; - rs_table[i].custom_divisor = req->custom_divisor; - rs_table[i].closing_wait = req->closing_wait; - return(0); -} - -/* - * register_serial and unregister_serial allows for 16x50 serial ports to be - * configured at run-time, to support PCMCIA modems. - */ - -/** - * register_serial - configure a 16x50 serial port at runtime - * @req: request structure - * - * Configure the serial port specified by the request. If the - * port exists and is in use an error is returned. If the port - * is not currently in the table it is added. - * - * The port is then probed and if neccessary the IRQ is autodetected - * If this fails an error is returned. - * - * On success the port is ready to use and the line number is returned. - */ - -int register_serial(struct serial_struct *req) -{ - int i; - unsigned long flags; - struct serial_state *state; - struct async_struct *info; - unsigned long port; - - port = req->port; - if (HIGH_BITS_OFFSET) - port += (unsigned long) req->port_high << HIGH_BITS_OFFSET; - - save_flags(flags); cli(); - for (i = 0; i < NR_PORTS; i++) { - if ((rs_table[i].port == port) && - (rs_table[i].iomem_base == req->iomem_base)) - break; - } -#ifdef __i386__ - if (i == NR_PORTS) { - for (i = 4; i < NR_PORTS; i++) - if ((rs_table[i].type == PORT_UNKNOWN) && - (rs_table[i].count == 0)) - break; - } -#endif - if (i == NR_PORTS) { - for (i = 0; i < NR_PORTS; i++) - if ((rs_table[i].type == PORT_UNKNOWN) && - (rs_table[i].count == 0)) - break; - } - if (i == NR_PORTS) { - restore_flags(flags); - return -1; - } - state = &rs_table[i]; - if (rs_table[i].count) { - restore_flags(flags); - printk("Couldn't configure serial #%d (port=%ld,irq=%d): " - "device already open\n", i, port, req->irq); - return -1; - } - state->irq = req->irq; - state->port = port; - state->flags = req->flags; - state->io_type = req->io_type; - state->iomem_base = req->iomem_base; - state->iomem_reg_shift = req->iomem_reg_shift; - if (req->baud_base) - state->baud_base = req->baud_base; - if ((info = state->info) != NULL) { - info->port = port; - info->flags = req->flags; - info->io_type = req->io_type; - info->iomem_base = req->iomem_base; - info->iomem_reg_shift = req->iomem_reg_shift; - } - autoconfig(state); - if (state->type == PORT_UNKNOWN) { - restore_flags(flags); - printk("register_serial(): autoconfig failed\n"); - return -1; - } - restore_flags(flags); - - if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state)) - state->irq = detect_uart_irq(state); - - printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n", - state->line + SERIAL_DEV_OFFSET, - state->iomem_base ? "iomem" : "port", - state->iomem_base ? (unsigned long)state->iomem_base : - state->port, state->irq, uart_config[state->type].name); - tty_register_devfs(&serial_driver, 0, - serial_driver.minor_start + state->line); - tty_register_devfs(&callout_driver, 0, - callout_driver.minor_start + state->line); - return state->line + SERIAL_DEV_OFFSET; -} - -/** - * unregister_serial - deconfigure a 16x50 serial port - * @line: line to deconfigure - * - * The port specified is deconfigured and its resources are freed. Any - * user of the port is disconnected as if carrier was dropped. Line is - * the port number returned by register_serial(). - */ - -void unregister_serial(int line) -{ - unsigned long flags; - struct serial_state *state = &rs_table[line]; - - save_flags(flags); cli(); - if (state->info && state->info->tty) - tty_hangup(state->info->tty); - state->type = PORT_UNKNOWN; - printk(KERN_INFO "ttyS%02d unloaded\n", state->line); - /* These will be hidden, because they are devices that will no longer - * be available to the system. (ie, PCMCIA modems, once ejected) - */ - tty_unregister_devfs(&serial_driver, - serial_driver.minor_start + state->line); - tty_unregister_devfs(&callout_driver, - callout_driver.minor_start + state->line); - restore_flags(flags); -} - -static void __exit rs_fini(void) -{ - unsigned long flags; - int e1, e2; - int i; - struct async_struct *info; - - /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ - del_timer_sync(&serial_timer); - save_flags(flags); cli(); - remove_bh(SERIAL_BH); - if ((e1 = tty_unregister_driver(&serial_driver))) - printk("serial: failed to unregister serial driver (%d)\n", - e1); - if ((e2 = tty_unregister_driver(&callout_driver))) - printk("serial: failed to unregister callout driver (%d)\n", - e2); - restore_flags(flags); - - for (i = 0; i < NR_PORTS; i++) { - if ((info = rs_table[i].info)) { - rs_table[i].info = NULL; - kfree(info); - } - if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) { -#ifdef CONFIG_SERIAL_RSA - if (rs_table[i].type == PORT_RSA) - release_region(rs_table[i].port + - UART_RSA_BASE, 16); - else -#endif - release_region(rs_table[i].port, 8); - } -#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) - if (rs_table[i].iomem_base) - iounmap(rs_table[i].iomem_base); -#endif - } -#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) - for (i=0; i < NR_PCI_BOARDS; i++) { - struct pci_board_inst *brd = &serial_pci_board[i]; - - if (serial_pci_board[i].dev == 0) - continue; - if (brd->board.init_fn) - (brd->board.init_fn)(brd->dev, &brd->board, 0); - if (DEACTIVATE_FUNC(brd->dev)) - (DEACTIVATE_FUNC(brd->dev))(brd->dev); - } -#endif - if (tmp_buf) { - unsigned long pg = (unsigned long) tmp_buf; - tmp_buf = NULL; - free_page(pg); - } - -#ifdef ENABLE_SERIAL_PCI - if (serial_pci_driver.name[0]) - pci_unregister_driver (&serial_pci_driver); -#endif -} - -module_init(rs_init); -module_exit(rs_fini); -MODULE_DESCRIPTION("Standard/generic (dumb) serial driver"); -MODULE_AUTHOR("Theodore Ts'o <tytso@mit.edu>"); -MODULE_LICENSE("GPL"); - - -/* - * ------------------------------------------------------------ - * Serial console driver - * ------------------------------------------------------------ - */ -#ifdef CONFIG_SERIAL_CONSOLE - -#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) - -static struct async_struct async_sercons; - -/* - * Wait for transmitter & holding register to empty - */ -static inline void wait_for_xmitr(struct async_struct *info) -{ - unsigned int status, tmout = 1000000; - - do { - status = serial_in(info, UART_LSR); - - if (status & UART_LSR_BI) - lsr_break_flag = UART_LSR_BI; - - if (--tmout == 0) - break; - } while((status & BOTH_EMPTY) != BOTH_EMPTY); - - /* Wait for flow control if necessary */ - if (info->flags & ASYNC_CONS_FLOW) { - tmout = 1000000; - while (--tmout && - ((serial_in(info, UART_MSR) & UART_MSR_CTS) == 0)); - } -} - - -/* - * Print a string to the serial port trying not to disturb - * any possible real use of the port... - * - * The console must be locked when we get here. - */ -static void serial_console_write(struct console *co, const char *s, - unsigned count) -{ - static struct async_struct *info = &async_sercons; - int ier; - unsigned i; - - /* - * First save the IER then disable the interrupts - */ - ier = serial_in(info, UART_IER); - serial_out(info, UART_IER, 0x00); - - /* - * Now, do each character - */ - for (i = 0; i < count; i++, s++) { - wait_for_xmitr(info); - - /* - * Send the character out. - * If a LF, also do CR... - */ - serial_out(info, UART_TX, *s); - if (*s == 10) { - wait_for_xmitr(info); - serial_out(info, UART_TX, 13); - } - } - - /* - * Finally, Wait for transmitter & holding register to empty - * and restore the IER - */ - wait_for_xmitr(info); - serial_out(info, UART_IER, ier); -} - -static kdev_t serial_console_device(struct console *c) -{ - return mk_kdev(TTY_MAJOR, 64 + c->index); -} - -/* - * Setup initial baud/bits/parity/flow control. We do two things here: - * - construct a cflag setting for the first rs_open() - * - initialize the serial port - * Return non-zero if we didn't find a serial port. - */ -static int __init serial_console_setup(struct console *co, char *options) -{ - static struct async_struct *info; - struct serial_state *state; - unsigned cval; - int baud = 9600; - int bits = 8; - int parity = 'n'; - int doflow = 0; - int cflag = CREAD | HUPCL | CLOCAL; - int quot = 0; - char *s; - - if (options) { - baud = simple_strtoul(options, NULL, 10); - s = options; - while(*s >= '0' && *s <= '9') - s++; - if (*s) parity = *s++; - if (*s) bits = *s++ - '0'; - if (*s) doflow = (*s++ == 'r'); - } - - /* - * Now construct a cflag setting. - */ - switch(baud) { - case 1200: - cflag |= B1200; - break; - case 2400: - cflag |= B2400; - break; - case 4800: - cflag |= B4800; - break; - case 19200: - cflag |= B19200; - break; - case 38400: - cflag |= B38400; - break; - case 57600: - cflag |= B57600; - break; - case 115200: - cflag |= B115200; - break; - case 9600: - default: - cflag |= B9600; - /* - * Set this to a sane value to prevent a divide error - */ - baud = 9600; - break; - } - switch(bits) { - case 7: - cflag |= CS7; - break; - default: - case 8: - cflag |= CS8; - break; - } - switch(parity) { - case 'o': case 'O': - cflag |= PARODD; - break; - case 'e': case 'E': - cflag |= PARENB; - break; - } - co->cflag = cflag; - - /* - * Divisor, bytesize and parity - */ - state = rs_table + co->index; - if (doflow) - state->flags |= ASYNC_CONS_FLOW; - info = &async_sercons; - info->magic = SERIAL_MAGIC; - info->state = state; - info->port = state->port; - info->flags = state->flags; -#ifdef CONFIG_HUB6 - info->hub6 = state->hub6; -#endif - info->io_type = state->io_type; - info->iomem_base = state->iomem_base; - info->iomem_reg_shift = state->iomem_reg_shift; - quot = state->baud_base / baud; - cval = cflag & (CSIZE | CSTOPB); -#if defined(__powerpc__) || defined(__alpha__) - cval >>= 8; -#else /* !__powerpc__ && !__alpha__ */ - cval >>= 4; -#endif /* !__powerpc__ && !__alpha__ */ - if (cflag & PARENB) - cval |= UART_LCR_PARITY; - if (!(cflag & PARODD)) - cval |= UART_LCR_EPAR; - - /* - * Disable UART interrupts, set DTR and RTS high - * and set speed. - */ - serial_out(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ - serial_out(info, UART_DLL, quot & 0xff); /* LS of divisor */ - serial_out(info, UART_DLM, quot >> 8); /* MS of divisor */ - serial_out(info, UART_LCR, cval); /* reset DLAB */ - serial_out(info, UART_IER, 0); - serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); - - /* - * If we read 0xff from the LSR, there is no UART here. - */ - if (serial_in(info, UART_LSR) == 0xff) - return -1; - - return 0; -} - -static struct console sercons = { - name: "ttyS", - write: serial_console_write, - device: serial_console_device, - setup: serial_console_setup, - flags: CON_PRINTBUFFER, - index: -1, -}; - -/* - * Register console. - */ -void __init serial_console_init(void) -{ - register_console(&sercons); -} -#endif - -/* - Local variables: - compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -DEXPORT_SYMTAB -c serial.c" - End: -*/ diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 6789e5ecf6b5..f8ee5491cce2 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -150,8 +150,7 @@ extern void con3215_init(void); extern void tty3215_init(void); extern void tub3270_con_init(void); extern void tub3270_init(void); -extern void rs285_console_init(void); -extern void sa1100_rs_console_init(void); +extern void uart_console_init(void); extern void sgi_serial_console_init(void); extern void sci_console_init(void); extern void tx3912_console_init(void); @@ -456,11 +455,12 @@ void do_tty_hangup(void *data) } file_list_unlock(); - /* FIXME! What are the locking issues here? This may me overdoing things.. */ + /* FIXME! What are the locking issues here? This may me overdoing things.. + * this question is especially important now that we've removed the irqlock. */ { unsigned long flags; - save_flags(flags); cli(); + local_save_flags(flags); local_irq_disable(); // FIXME: is this safe? if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); if (tty->driver.flush_buffer) @@ -468,7 +468,7 @@ void do_tty_hangup(void *data) if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); - restore_flags(flags); + local_irq_restore(flags); // FIXME: is this safe? } wake_up_interruptible(&tty->write_wait); @@ -1900,7 +1900,7 @@ static void flush_to_ldisc(void *private_) fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; tty->flip.buf_num = 0; - save_flags(flags); cli(); + local_save_flags(flags); local_irq_disable(); // FIXME: is this safe? tty->flip.char_buf_ptr = tty->flip.char_buf; tty->flip.flag_buf_ptr = tty->flip.flag_buf; } else { @@ -1908,13 +1908,13 @@ static void flush_to_ldisc(void *private_) fp = tty->flip.flag_buf; tty->flip.buf_num = 1; - save_flags(flags); cli(); + local_save_flags(flags); local_irq_disable(); // FIXME: is this safe? tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE; tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE; } count = tty->flip.count; tty->flip.count = 0; - restore_flags(flags); + local_irq_restore(flags); // FIXME: is this safe? tty->ldisc.receive_buf(tty, cp, fp, count); } @@ -2220,18 +2220,12 @@ void __init console_init(void) #ifdef CONFIG_STDIO_CONSOLE stdio_console_init(); #endif -#ifdef CONFIG_SERIAL_21285_CONSOLE - rs285_console_init(); -#endif -#ifdef CONFIG_SERIAL_SA1100_CONSOLE - sa1100_rs_console_init(); +#ifdef CONFIG_SERIAL_CORE_CONSOLE + uart_console_init(); #endif #ifdef CONFIG_ARC_CONSOLE arc_console_init(); #endif -#ifdef CONFIG_SERIAL_AMBA_CONSOLE - ambauart_console_init(); -#endif #ifdef CONFIG_SERIAL_TX3912_CONSOLE tx3912_console_init(); #endif diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index 6fe1ef20e409..00aa3598c951 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -97,7 +97,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios int canon_change; struct termios old_termios = *tty->termios; - cli(); + local_irq_disable(); // FIXME: is this safe? *tty->termios = *new_termios; unset_locked_termios(tty->termios, &old_termios, tty->termios_locked); canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON; @@ -107,7 +107,7 @@ static void change_termios(struct tty_struct * tty, struct termios * new_termios tty->canon_data = 0; tty->erasing = 0; } - sti(); + local_irq_enable(); // FIXME: is this safe? if (canon_change && !L_ICANON(tty) && tty->read_cnt) /* Get characters left over from canonical mode. */ wake_up_interruptible(&tty->read_wait); diff --git a/drivers/char/vt.c b/drivers/char/vt.c index e59c0cef09e7..bee0db2bc758 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -113,8 +113,8 @@ _kd_mksound(unsigned int hz, unsigned int ticks) if (hz > 20 && hz < 32767) count = 1193180 / hz; - save_flags(flags); - cli(); + local_save_flags(flags); // FIXME: is this safe? + local_irq_disable(); del_timer(&sound_timer); if (count) { /* enable counter 2 */ @@ -131,7 +131,7 @@ _kd_mksound(unsigned int hz, unsigned int ticks) } } else kd_nosound(0); - restore_flags(flags); + local_irq_restore(flags); return; } diff --git a/drivers/ide/device.c b/drivers/ide/device.c index ca1c04f6f34c..aaec151c4d27 100644 --- a/drivers/ide/device.c +++ b/drivers/ide/device.c @@ -150,16 +150,16 @@ int ata_status_poll(struct ata_device *drive, u8 good, u8 bad, if (!ata_status(drive, 0, BUSY_STAT)) { unsigned long flags; - __save_flags(flags); + local_save_flags(flags); local_irq_enable(); timeout += jiffies; while (!ata_status(drive, 0, BUSY_STAT)) { if (time_after(jiffies, timeout)) { - __restore_flags(flags); + local_irq_restore(flags); return ata_error(drive, rq, "status timeout"); } } - __restore_flags(flags); + local_irq_restore(flags); } /* diff --git a/drivers/ide/hd.c b/drivers/ide/hd.c index a34945a2382f..f5fb26632eb2 100644 --- a/drivers/ide/hd.c +++ b/drivers/ide/hd.c @@ -83,9 +83,6 @@ static void bad_rw_intr(void); static char recalibrate[MAX_HD]; static char special_op[MAX_HD]; -static int access_count[MAX_HD]; -static char busy[MAX_HD]; -static DECLARE_WAIT_QUEUE_HEAD(busy_wait); static int reset; static int hd_error; @@ -644,7 +641,7 @@ static int hd_ioctl(struct inode * inode, struct file * file, g.heads = hd_info[dev].head; g.sectors = hd_info[dev].sect; g.cylinders = hd_info[dev].cyl; - g.start = get_start_sect(inode->i_rdev); + g.start = get_start_sect(inode->i_bdev); return copy_to_user(loc, &g, sizeof g) ? -EFAULT : 0; } @@ -653,14 +650,6 @@ static int hd_ioctl(struct inode * inode, struct file * file, return -EACCES; return revalidate_hddisk(inode->i_rdev, 1); - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKROSET: - case BLKROGET: - case BLKFLSBUF: - case BLKPG: - return blk_ioctl(inode->i_bdev, cmd, arg); - default: return -EINVAL; } @@ -668,14 +657,9 @@ static int hd_ioctl(struct inode * inode, struct file * file, static int hd_open(struct inode * inode, struct file * filp) { - int target; - target = DEVICE_NR(inode->i_rdev); - + int target = DEVICE_NR(inode->i_rdev); if (target >= NR_HD) return -ENODEV; - while (busy[target]) - sleep_on(&busy_wait); - access_count[target]++; return 0; } @@ -683,12 +667,6 @@ static int hd_open(struct inode * inode, struct file * filp) * Releasing a block device means we sync() it, so that it can safely * be forgotten about... */ -static int hd_release(struct inode * inode, struct file * file) -{ - int target = DEVICE_NR(inode->i_rdev); - access_count[target]--; - return 0; -} extern struct block_device_operations hd_fops; @@ -715,7 +693,6 @@ static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs) static struct block_device_operations hd_fops = { .open = hd_open, - .release = hd_release, .ioctl = hd_ioctl, }; @@ -854,13 +831,9 @@ int __init hd_init(void) return 0; } -#define DEVICE_BUSY busy[target] -#define USAGE access_count[target] #define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl) /* We assume that the BIOS parameters do not change, so the disk capacity will not change */ -#undef MAYBE_REINIT -#define GENDISK_STRUCT hd_gendisk /* * This routine is called to flush all partitions and partition tables @@ -872,36 +845,15 @@ int __init hd_init(void) */ static int revalidate_hddisk(kdev_t dev, int maxusage) { - int target; - struct gendisk * gdev; - int res; - long flags; - - target = DEVICE_NR(dev); - gdev = &GENDISK_STRUCT; - - save_flags(flags); - cli(); - if (DEVICE_BUSY || USAGE > maxusage) { - restore_flags(flags); - return -EBUSY; - } - DEVICE_BUSY = 1; - restore_flags(flags); - - res = wipe_partitions(dev); - if (res) - goto leave; - -#ifdef MAYBE_REINIT - MAYBE_REINIT; -#endif - - grok_partitions(dev, CAPACITY); - -leave: - DEVICE_BUSY = 0; - wake_up(&busy_wait); + int target = DEVICE_NR(dev); + kdev_t device = mk_kdev(MAJOR_NR, target << 6); + int res = dev_lock_part(device); + if (res < 0) + return res; + res = wipe_partitions(device); + if (!res) + grok_partitions(device, CAPACITY); + dev_unlock_part(device); return res; } diff --git a/drivers/ide/hptraid.c b/drivers/ide/hptraid.c index 9e8e07b35a2f..43b45c6e06eb 100644 --- a/drivers/ide/hptraid.c +++ b/drivers/ide/hptraid.c @@ -122,11 +122,6 @@ static int hptraid_ioctl(struct inode *inode, struct file *file, return 0; } - case BLKROSET: - case BLKROGET: - case BLKSSZGET: - return blk_ioctl(inode->i_bdev, cmd, arg); - default: return -EINVAL; }; diff --git a/drivers/ide/ide-pmac.c b/drivers/ide/ide-pmac.c index b3089a4bca47..5a52c4fa4169 100644 --- a/drivers/ide/ide-pmac.c +++ b/drivers/ide/ide-pmac.c @@ -419,10 +419,10 @@ pmac_ide_do_setfeature(struct ata_device *drive, u8 command) OUT_BYTE(SETFEATURES_XFER, IDE_FEATURE_REG); OUT_BYTE(WIN_SETFEATURES, IDE_COMMAND_REG); udelay(1); - __save_flags(flags); + local_save_flags(flags); local_irq_enable(); result = wait_for_ready(drive); - __restore_flags(flags); + local_irq_restore(flags); ata_irq_enable(drive, 1); if (result) printk(KERN_ERR "pmac_ide_do_setfeature disk not ready after SET_FEATURE !\n"); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index a83f8e7ee6d6..230bad45d91d 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -288,7 +288,7 @@ u8 ata_dump(struct ata_device *drive, struct request * rq, const char *msg) u8 err = 0; /* FIXME: --bzolnier */ - __save_flags(flags); + local_save_flags(flags); local_irq_enable(); printk("%s: %s: status=0x%02x", drive->name, msg, drive->status); @@ -337,7 +337,7 @@ u8 ata_dump(struct ata_device *drive, struct request * rq, const char *msg) #endif printk("\n"); } - __restore_flags (flags); + local_irq_restore (flags); return err; } @@ -1105,9 +1105,6 @@ static int ide_open(struct inode * inode, struct file * filp) if (drive->driver == NULL) ide_driver_module(); - while (drive->busy) - sleep_on(&drive->wqueue); - ++drive->usage; if (ata_ops(drive) && ata_ops(drive)->open) return ata_ops(drive)->open(inode, filp, drive); diff --git a/drivers/ide/ioctl.c b/drivers/ide/ioctl.c index 1c86cbc9c177..003b743b4772 100644 --- a/drivers/ide/ioctl.c +++ b/drivers/ide/ioctl.c @@ -343,19 +343,6 @@ int ata_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned case BLKRRPART: /* Re-read partition tables */ return ata_revalidate(inode->i_rdev); - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKROSET: - case BLKROGET: - case BLKFLSBUF: - case BLKSSZGET: - case BLKPG: - case BLKELVGET: - case BLKELVSET: - case BLKBSZGET: - case BLKBSZSET: - return blk_ioctl(inode->i_bdev, cmd, arg); - /* Now check whatever this particular ioctl has a device type * specific implementation. */ diff --git a/drivers/ide/main.c b/drivers/ide/main.c index 24cc8bc9a75e..d1052495e97c 100644 --- a/drivers/ide/main.c +++ b/drivers/ide/main.c @@ -249,28 +249,22 @@ struct ata_device *get_info_ptr(kdev_t i_rdev) */ int ata_revalidate(kdev_t i_rdev) { + kdev_t device = mk_kdev(major(i_rdev), minor(i_rdev) & ~PARTN_MASK); struct ata_device *drive; - unsigned long flags; int res; - if ((drive = get_info_ptr(i_rdev)) == NULL) + if ((drive = get_info_ptr(device)) == NULL) return -ENODEV; - /* FIXME: The locking here doesn't make the slightest sense! */ - spin_lock_irqsave(&ide_lock, flags); - - if (drive->busy || (drive->usage > 1)) { - spin_unlock_irqrestore(&ide_lock, flags); - - return -EBUSY; - } - - drive->busy = 1; MOD_INC_USE_COUNT; - spin_unlock_irqrestore(&ide_lock, flags); + res = dev_lock_part(device); + if (res < 0) { + MOD_DEC_USE_COUNT; + return res; + } - res = wipe_partitions(i_rdev); + res = wipe_partitions(device); if (!res) { if (ata_ops(drive) && ata_ops(drive)->revalidate) { ata_get(ata_ops(drive)); @@ -281,14 +275,11 @@ int ata_revalidate(kdev_t i_rdev) ata_ops(drive)->revalidate(drive); ata_put(ata_ops(drive)); } else - grok_partitions(i_rdev, ata_capacity(drive)); + grok_partitions(device, ata_capacity(drive)); } - drive->busy = 0; - wake_up(&drive->wqueue); - + dev_unlock_part(device); MOD_DEC_USE_COUNT; - return res; } @@ -1091,18 +1082,18 @@ int ide_unregister_subdriver(struct ata_device *drive) { unsigned long flags; - save_flags(flags); /* all CPUs */ - cli(); /* all CPUs */ + local_save_flags(flags); // FIXME: is this safe? + local_irq_disable(); #if 0 if (__MOD_IN_USE(ata_ops(drive)->owner)) { - restore_flags(flags); + local_irq_restore(flags); // FIXME: is this safe? return 1; } #endif if (drive->usage || drive->busy || !ata_ops(drive)) { - restore_flags(flags); /* all CPUs */ + local_irq_restore(flags); // FIXME: is this safe? return 1; } @@ -1111,7 +1102,7 @@ int ide_unregister_subdriver(struct ata_device *drive) #endif drive->driver = NULL; - restore_flags(flags); /* all CPUs */ + local_irq_restore(flags); // FIXME: is this safe? return 0; } diff --git a/drivers/ide/pdcraid.c b/drivers/ide/pdcraid.c index 4d6f81507582..d1bd67ba7f45 100644 --- a/drivers/ide/pdcraid.c +++ b/drivers/ide/pdcraid.c @@ -152,11 +152,6 @@ static int pdcraid_ioctl(struct inode *inode, struct file *file, return 0; } - case BLKROSET: - case BLKROGET: - case BLKSSZGET: - return blk_ioctl(inode->i_bdev, cmd, arg); - default: printk("Invalid ioctl \n"); return -EINVAL; diff --git a/drivers/ide/probe.c b/drivers/ide/probe.c index 3bdb1de45817..abe93fece6cf 100644 --- a/drivers/ide/probe.c +++ b/drivers/ide/probe.c @@ -733,7 +733,7 @@ static void channel_probe(struct ata_channel *ch) ch->straight8 = 0; - __save_flags(flags); + local_save_flags(flags); local_irq_enable(); /* needed for jiffies and irq probing */ /* @@ -852,7 +852,7 @@ static void channel_probe(struct ata_channel *ch) if (ch->reset) ata_reset(ch); - __restore_flags(flags); + local_irq_restore(flags); /* * Now setup the PIO transfer modes of the drives on this channel. @@ -869,7 +869,7 @@ static void channel_probe(struct ata_channel *ch) return; not_found: - __restore_flags(flags); + local_irq_restore(flags); } /* diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index 3338ed620e69..3a0244704002 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -3097,7 +3097,7 @@ static int sbp2scsi_reset (Scsi_Cmnd *SCpnt) /* * Called by scsi stack to get bios parameters (used by fdisk, and at boot). */ -static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]) +static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[]) { int heads, sectors, cylinders; diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h index 7d6da4a61dd5..12e6dde4944b 100644 --- a/drivers/ieee1394/sbp2.h +++ b/drivers/ieee1394/sbp2.h @@ -542,7 +542,7 @@ static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id static int sbp2scsi_detect (Scsi_Host_Template *tpnt); static const char *sbp2scsi_info (struct Scsi_Host *host); void sbp2scsi_setup(char *str, int *ints); -static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]); +static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[]); static int sbp2scsi_abort (Scsi_Cmnd *SCpnt); static int sbp2scsi_reset (Scsi_Cmnd *SCpnt); static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c index 586ceb8f59af..945eecc05120 100644 --- a/drivers/input/joystick/a3d.c +++ b/drivers/input/joystick/a3d.c @@ -84,8 +84,8 @@ static int a3d_read_packet(struct gameport *gameport, int length, char *data) t = gameport_time(gameport, A3D_MAX_START); s = gameport_time(gameport, A3D_MAX_STROBE); - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); gameport_trigger(gameport); v = gameport_read(gameport); @@ -98,7 +98,7 @@ static int a3d_read_packet(struct gameport *gameport, int length, char *data) } } - __restore_flags(flags); + local_irq_restore(flags); return i; } diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c index 66ed7834a213..4ad09c0f2bf5 100644 --- a/drivers/input/joystick/adi.c +++ b/drivers/input/joystick/adi.c @@ -152,8 +152,8 @@ static void adi_read_packet(struct adi_port *port) s[i] = 0; } - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); gameport_trigger(gameport); v = z = gameport_read(gameport); @@ -172,7 +172,7 @@ static void adi_read_packet(struct adi_port *port) } } while (t[0] > 0 || t[1] > 0); - __restore_flags(flags); + local_irq_restore(flags); return; } diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c index ffe496e6cad8..f091805b3ea7 100644 --- a/drivers/input/joystick/analog.c +++ b/drivers/input/joystick/analog.c @@ -232,11 +232,11 @@ static int analog_cooked_read(struct analog_port *port) loopout = (ANALOG_LOOP_TIME * port->loop) / 1000; timeout = ANALOG_MAX_TIME * port->speed; - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); gameport_trigger(gameport); GET_TIME(now); - __restore_flags(flags); + local_irq_restore(flags); start = now; this = port->mask; @@ -246,10 +246,10 @@ static int analog_cooked_read(struct analog_port *port) loop = now; last = this; - __cli(); + local_irq_disable(); this = gameport_read(gameport) & port->mask; GET_TIME(now); - __restore_flags(flags); + local_irq_restore(flags); if ((last ^ this) && (DELTA(loop, now) < loopout)) { data[i] = last ^ this; diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c index 16c83a5900dc..eafdca07c381 100644 --- a/drivers/input/joystick/cobra.c +++ b/drivers/input/joystick/cobra.c @@ -73,8 +73,8 @@ static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int * t[i] = COBRA_MAX_STROBE; } - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); u = gameport_read(gameport); @@ -91,7 +91,7 @@ static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int * } } while (t[0] > 0 || t[1] > 0); - __restore_flags(flags); + local_irq_restore(flags); ret = 0; diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c index 23ebebe3adb4..d8d58db2e230 100644 --- a/drivers/input/joystick/gamecon.c +++ b/drivers/input/joystick/gamecon.c @@ -113,13 +113,13 @@ static void gc_n64_read_packet(struct gc *gc, unsigned char *data) * Request the pad to transmit data */ - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) { parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0)); udelay(GC_N64_DWS); } - __restore_flags(flags); + local_irq_restore(flags); /* * Wait for the pad response to be loaded into the 33-bit register of the adapter @@ -270,8 +270,8 @@ static int gc_psx_read_packet(struct gc *gc, unsigned char *data) parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */ udelay(GC_PSX_DELAY * 2); - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); gc_psx_command(gc, 0x01); /* Access pad */ id = gc_psx_command(gc, 0x42); /* Get device id */ @@ -280,7 +280,7 @@ static int gc_psx_read_packet(struct gc *gc, unsigned char *data) data[i] = gc_psx_command(gc, 0); } else id = 0; - __restore_flags(flags); + local_irq_restore(flags); parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c index d39c4eff0f92..8bd3c5a3e7c6 100644 --- a/drivers/input/joystick/gf2k.c +++ b/drivers/input/joystick/gf2k.c @@ -106,8 +106,8 @@ static int gf2k_read_packet(struct gameport *gameport, int length, char *data) i = 0; - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); gameport_trigger(gameport); v = gameport_read(gameport);; @@ -121,7 +121,7 @@ static int gf2k_read_packet(struct gameport *gameport, int length, char *data) } } - __restore_flags(flags); + local_irq_restore(flags); return i; } @@ -137,8 +137,8 @@ static void gf2k_trigger_seq(struct gameport *gameport, short *seq) unsigned long flags; int i, t; - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); i = 0; do { @@ -150,7 +150,7 @@ static void gf2k_trigger_seq(struct gameport *gameport, short *seq) gameport_trigger(gameport); - __restore_flags(flags); + local_irq_restore(flags); } /* diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c index d5fb8a08196a..da806f47320f 100644 --- a/drivers/input/joystick/grip.c +++ b/drivers/input/joystick/grip.c @@ -98,8 +98,8 @@ static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned i t = strobe; i = 0; - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); v = gameport_read(gameport) >> shift; @@ -112,7 +112,7 @@ static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned i } } while (i < GRIP_LENGTH_GPP && t > 0); - __restore_flags(flags); + local_irq_restore(flags); if (i < GRIP_LENGTH_GPP) return -1; @@ -140,8 +140,8 @@ static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned in status = buf = i = j = 0; t = strobe; - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); v = w = (gameport_read(gameport) >> shift) & 3; @@ -176,7 +176,7 @@ static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned in } while (status != 0xf && i < GRIP_MAX_BITS_XT && j < GRIP_MAX_CHUNKS_XT && t > 0); - __restore_flags(flags); + local_irq_restore(flags); return -(status != 0xf); } diff --git a/drivers/input/joystick/guillemot.c b/drivers/input/joystick/guillemot.c index 53c46728a2bf..2a4903fe4d21 100644 --- a/drivers/input/joystick/guillemot.c +++ b/drivers/input/joystick/guillemot.c @@ -98,8 +98,8 @@ static int guillemot_read_packet(struct gameport *gameport, u8 *data) t = gameport_time(gameport, GUILLEMOT_MAX_START); s = gameport_time(gameport, GUILLEMOT_MAX_STROBE); - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); gameport_trigger(gameport); v = gameport_read(gameport); @@ -113,7 +113,7 @@ static int guillemot_read_packet(struct gameport *gameport, u8 *data) } } - __restore_flags(flags); + local_irq_restore(flags); return i; } diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c index 5dfcc3d44b2d..edb606a33bc2 100644 --- a/drivers/input/joystick/interact.c +++ b/drivers/input/joystick/interact.c @@ -103,8 +103,8 @@ static int interact_read_packet(struct gameport *gameport, int length, u32 *data t = gameport_time(gameport, INTERACT_MAX_START); s = gameport_time(gameport, INTERACT_MAX_STROBE); - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); gameport_trigger(gameport); v = gameport_read(gameport); @@ -120,7 +120,7 @@ static int interact_read_packet(struct gameport *gameport, int length, u32 *data } } - __restore_flags(flags); + local_irq_restore(flags); return i; } diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c index d93b9bfc54ab..0bc0f403f625 100644 --- a/drivers/input/joystick/sidewinder.c +++ b/drivers/input/joystick/sidewinder.c @@ -149,8 +149,8 @@ static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int len pending = 0; sched = 0; - __save_flags(flags); /* Quiet, please */ - __cli(); + local_save_flags(flags); /* Quiet, please */ + local_irq_disable(); gameport_trigger(gameport); /* Trigger */ v = gameport_read(gameport); @@ -193,7 +193,7 @@ static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int len } } - __restore_flags(flags); /* Done - relax */ + local_irq_restore(flags); /* Done - relax */ #ifdef SW_DEBUG { @@ -245,8 +245,8 @@ static void sw_init_digital(struct gameport *gameport) unsigned long flags; int i, t; - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); i = 0; do { @@ -258,7 +258,7 @@ static void sw_init_digital(struct gameport *gameport) gameport_trigger(gameport); /* Last trigger */ - __restore_flags(flags); + local_irq_restore(flags); } /* diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c index a85f2017e966..fa3efbeae1e3 100644 --- a/drivers/input/joystick/tmdc.c +++ b/drivers/input/joystick/tmdc.c @@ -125,8 +125,8 @@ static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMD i[k] = j[k] = 0; } - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); gameport_trigger(gameport); w = gameport_read(gameport) >> 4; @@ -153,7 +153,7 @@ static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMD } } while (t[0] > 0 || t[1] > 0); - __restore_flags(flags); + local_irq_restore(flags); return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1); } diff --git a/drivers/md/lvm.c b/drivers/md/lvm.c index c44a1b8a74b2..ab05b01ee4ce 100644 --- a/drivers/md/lvm.c +++ b/drivers/md/lvm.c @@ -872,17 +872,6 @@ static int lvm_blk_ioctl(struct inode *inode, struct file *file, return -EFAULT; break; - - case BLKFLSBUF: - /* flush buffer cache */ - if (!capable(CAP_SYS_ADMIN)) return -EACCES; - - P_IOCTL("BLKFLSBUF\n"); - - fsync_bdev(inode->i_bdev); - invalidate_buffers(inode->i_rdev); - break; - case HDIO_GETGEO: /* get disk geometry */ P_IOCTL("%s -- lvm_blk_ioctl -- HDIO_GETGEO\n", lvm_name); diff --git a/drivers/md/md.c b/drivers/md/md.c index 549063948426..d08613aea3bb 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2241,28 +2241,6 @@ static int md_ioctl(struct inode *inode, struct file *file, autostart_arrays(); goto done; #endif - - case BLKGETSIZE: /* Return device size */ - if (!arg) { - err = -EINVAL; - MD_BUG(); - goto abort; - } - err = put_user(md_hd_struct[minor].nr_sects, - (unsigned long *) arg); - goto done; - - case BLKGETSIZE64: /* Return device size */ - err = put_user((u64)md_hd_struct[minor].nr_sects << 9, - (u64 *) arg); - goto done; - - case BLKFLSBUF: - case BLKBSZGET: - case BLKBSZSET: - err = blk_ioctl(inode->i_bdev, cmd, arg); - goto abort; - default:; } @@ -2386,7 +2364,7 @@ static int md_ioctl(struct inode *inode, struct file *file, (short *) &loc->cylinders); if (err) goto abort_unlock; - err = put_user (get_start_sect(dev), + err = put_user (get_start_sect(inode->i_bdev), (long *) &loc->start); goto done_unlock; } diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index 8d03a096d507..5c049fb8dfdd 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -3576,7 +3576,7 @@ mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *m */ int -mptscsih_bios_param(Disk * disk, kdev_t dev, int *ip) +mptscsih_bios_param(Disk * disk, struct block_device *dev, int *ip) { int size; diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h index c26ec0fe1845..b0c55517d1e6 100644 --- a/drivers/message/fusion/mptscsih.h +++ b/drivers/message/fusion/mptscsih.h @@ -201,7 +201,7 @@ extern int x_scsi_host_reset(Scsi_Cmnd *); extern int x_scsi_old_abort(Scsi_Cmnd *); extern int x_scsi_old_reset(Scsi_Cmnd *, unsigned int); #endif -extern int x_scsi_bios_param(Disk *, kdev_t, int *); +extern int x_scsi_bios_param(Disk *, struct block_device *, int *); extern void x_scsi_select_queue_depths(struct Scsi_Host *, Scsi_Device *); extern void x_scsi_taskmgmt_bh(void *); diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c index bf11c559d43f..b82610655b49 100644 --- a/drivers/message/i2o/i2o_block.c +++ b/drivers/message/i2o/i2o_block.c @@ -1050,13 +1050,7 @@ static int do_i2ob_revalidate(kdev_t dev, int maxu) return -EBUSY; } - for( i = 15; i>=0 ; i--) - { - int m = minor+i; - invalidate_device(mk_kdev(MAJOR_NR, m), 1); - i2ob_gendisk.part[m].start_sect = 0; - i2ob_gendisk.part[m].nr_sects = 0; - } + wipe_partitions(mk_kdev(MAJOR_NR, minor), 1); /* * Do a physical check and then reconfigure @@ -1089,7 +1083,7 @@ static int i2ob_ioctl(struct inode *inode, struct file *file, int u = minor(inode->i_rdev) & 0xF0; i2o_block_biosparam(i2ob_sizes[u]<<1, &g.cylinders, &g.heads, &g.sectors); - g.start = get_start_sect(inode->i_rdev); + g.start = get_start_sect(inode->i_bdev); return copy_to_user((void *)arg, &g, sizeof(g)) ? -EFAULT : 0; } @@ -1099,14 +1093,6 @@ static int i2ob_ioctl(struct inode *inode, struct file *file, return -EACCES; return do_i2ob_revalidate(inode->i_rdev,1); - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKFLSBUF: - case BLKROSET: - case BLKROGET: - case BLKPG: - return blk_ioctl(inode->i_bdev, cmd, arg); - default: return -EINVAL; } @@ -1815,7 +1801,6 @@ int i2o_block_init(void) * Now fill in the boiler plate */ - blk_size[MAJOR_NR] = i2ob_sizes; blk_dev[MAJOR_NR].queue = i2ob_get_queue; blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), i2ob_request); diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c index a25603a79897..1c119e8a44ce 100644 --- a/drivers/message/i2o/i2o_scsi.c +++ b/drivers/message/i2o/i2o_scsi.c @@ -902,7 +902,7 @@ int i2o_scsi_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) * This is anyones guess quite frankly. */ -int i2o_scsi_bios_param(Disk * disk, kdev_t dev, int *ip) +int i2o_scsi_bios_param(Disk * disk, struct block_device *dev, int *ip) { int size; diff --git a/drivers/message/i2o/i2o_scsi.h b/drivers/message/i2o/i2o_scsi.h index c62d2849b118..1979284f10c6 100644 --- a/drivers/message/i2o/i2o_scsi.h +++ b/drivers/message/i2o/i2o_scsi.h @@ -20,7 +20,7 @@ extern int i2o_scsi_command(Scsi_Cmnd *); extern int i2o_scsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); extern int i2o_scsi_abort(Scsi_Cmnd *); extern int i2o_scsi_reset(Scsi_Cmnd *, unsigned int); -extern int i2o_scsi_bios_param(Disk *, kdev_t, int *); +extern int i2o_scsi_bios_param(Disk *, struct block_device *, int *); extern void i2o_scsi_setup(char *str, int *ints); extern int i2o_scsi_release(struct Scsi_Host *host); diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index de201fdea95e..c68d10d829f9 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -880,9 +880,6 @@ static release_t ftl_close(struct inode *inode, struct file *file) DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor); - /* Flush all writes */ - invalidate_device(inode->i_rdev, 1); - /* Wait for any pending erase operations to complete */ if (part->mtd->sync) part->mtd->sync(part->mtd); @@ -1126,22 +1123,11 @@ static int ftl_ioctl(struct inode *inode, struct file *file, put_user(1, (char *)&geo->heads); put_user(8, (char *)&geo->sectors); put_user((sect>>3), (short *)&geo->cylinders); - put_user(get_start_sect(inode->i_rdev), (u_long *)&geo->start); - break; - case BLKGETSIZE: - ret = put_user(ftl_hd[minor].nr_sects, (unsigned long *)arg); - break; - case BLKGETSIZE64: - ret = put_user((u64)ftl_hd[minor].nr_sects << 9, (u64 *)arg); + put_user(get_start_sect(inode->i_bdev), (u_long *)&geo->start); break; case BLKRRPART: ret = ftl_reread_partitions(inode->i_rdev); break; - case BLKROSET: - case BLKROGET: - case BLKFLSBUF: - ret = blk_ioctl(inode->i_bdev, cmd, arg); - break; default: ret = -EINVAL; } @@ -1157,25 +1143,20 @@ static int ftl_ioctl(struct inode *inode, struct file *file, static int ftl_reread_partitions(kdev_t dev) { - int minor = minor(dev); - partition_t *part = myparts[minor >> 4]; - int res; - - DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor); - if ((atomic_read(&part->open) > 1)) { - return -EBUSY; - } - - res = wipe_partitions(dev); - if (res) - goto leave; - - scan_header(part); - - register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART, - &ftl_blk_fops, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE); - - return res; + int minor = minor(dev); + partition_t *part = myparts[minor >> 4]; + kdev_t device = mk_kdev(MAJOR_NR, minor & ~15); + int res = dev_lock_part(device); + if (rec < 0) + return res; + res = wipe_partitions(device); + if (!res) { + scan_header(part); + grok_partitions(device, + le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE); + } + dev_unlock_part(device); + return res; } /*====================================================================== @@ -1285,13 +1266,13 @@ static void ftl_notify_add(struct mtd_info *mtd) partition->mtd = mtd; - if ((scan_header(partition) == 0) && - (build_maps(partition) == 0)) { - + if ((scan_header(partition) == 0) && (build_maps(partition) == 0)) { partition->state = FTL_FORMATTED; atomic_set(&partition->open, 0); myparts[device] = partition; - ftl_reread_partitions(device << 4); + register_disk(&ftl_gendisk, mk_kdev(MAJOR_NR, device << 4), + MAX_PART, &ftl_blk_fops, + le32_to_cpu(partition->header.FormattedSize)/SECTOR_SIZE); #ifdef PCMCIA_DEBUG printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n", le32_to_cpu(partition->header.FormattedSize) >> 10); diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c index 56535e9a41e9..928ebe405251 100644 --- a/drivers/mtd/mtdblock.c +++ b/drivers/mtd/mtdblock.c @@ -354,8 +354,6 @@ static release_t mtdblock_release(struct inode *inode, struct file *file) if (inode == NULL) release_return(-ENODEV); - invalidate_device(inode->i_rdev, 1); - dev = minor(inode->i_rdev); mtdblk = mtdblks[dev]; diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c index 4939a5cb8145..72482560b696 100644 --- a/drivers/mtd/mtdblock_ro.c +++ b/drivers/mtd/mtdblock_ro.c @@ -76,8 +76,6 @@ static release_t mtdblock_release(struct inode *inode, struct file *file) if (inode == NULL) release_return(-ENODEV); - invalidate_device(inode->i_rdev, 1); - dev = minor(inode->i_rdev); mtd = __get_mtd_device(NULL, dev); diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index bbe20a1721b3..f54e17f14540 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -115,7 +115,6 @@ static void NFTL_setup(struct mtd_info *mtd) #endif /* linux stuff */ - nftl->usecount = 0; nftl->cylinders = 1024; nftl->heads = 16; @@ -153,8 +152,9 @@ static void NFTL_setup(struct mtd_info *mtd) #if LINUX_VERSION_CODE < 0x20328 resetup_one_dev(&nftl_gendisk, firstfree); #else - grok_partitions(mk_kdev(MAJOR_NR,firstfree<<NFTL_PARTN_BITS), - nftl->nr_sects); + register_disk(&nftl_gendisk, + mk_kdev(MAJOR_NR,firstfree<<NFTL_PARTN_BITS), + 1<<NFTL_PARTN_BITS, &nftl_fops, nftl->nr_sects); #endif } @@ -787,7 +787,7 @@ static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd g.heads = nftl->heads; g.sectors = nftl->sectors; g.cylinders = nftl->cylinders; - g.start = get_start_sect(inode->i_rdev); + g.start = get_start_sect(inode->i_bdev); return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0; } case BLKFLSBUF: @@ -800,29 +800,18 @@ static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd case BLKRRPART: if (!capable(CAP_SYS_ADMIN)) return -EACCES; - if (nftl->usecount > 1) return -EBUSY; - /* - * We have to flush all buffers and invalidate caches, - * or we won't be able to re-use the partitions, - * if there was a change and we don't want to reboot - */ - res = wipe_partitions(inode->i_rdev); + { + kdev_t device = mk_kdev(MAJOR_NR, + minor(inode->i_rdev) & -(1<<NFTL_PARTN_BITS)); + res = dev_lock_part(device); + if (res < 0) + return res; + res = wipe_partitions(device); if (!res) - grok_partitions(inode->i_rdev, nftl->nr_sects); - + grok_partitions(device, nftl->nr_sects); + dev_unlock_part(device); + } return res; - -#if (LINUX_VERSION_CODE < 0x20303) - RO_IOCTLS(inode->i_rdev, arg); /* ref. linux/blk.h */ -#else - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKROSET: - case BLKROGET: - case BLKSSZGET: - return blk_ioctl(inode->i_bdev, cmd, arg); -#endif - default: return -EINVAL; } @@ -955,7 +944,6 @@ static int nftl_open(struct inode *ip, struct file *fp) return -EROFS; #endif /* !CONFIG_NFTL_RW */ - thisNFTL->usecount++; if (!get_mtd_device(thisNFTL->mtd, -1)) return /* -E'SBUGGEREDOFF */ -ENXIO; @@ -970,11 +958,8 @@ static int nftl_release(struct inode *inode, struct file *fp) DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n"); - invalidate_device(inode->i_rdev, 1); - if (thisNFTL->mtd->sync) thisNFTL->mtd->sync(thisNFTL->mtd); - thisNFTL->usecount--; put_mtd_device(thisNFTL->mtd); diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 9b7bfac1c4a3..5fa80ade4429 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -926,13 +926,15 @@ static struct net_device_stats *cp_get_stats(struct net_device *dev) static void cp_stop_hw (struct cp_private *cp) { + struct net_device *dev = cp->dev; + cpw16(IntrMask, 0); cpr16(IntrMask); cpw8(Cmd, 0); cpw16(CpCmd, 0); cpr16(CpCmd); cpw16(IntrStatus, ~(cpr16(IntrStatus))); - synchronize_irq(); + synchronize_irq(dev->irq); udelay(10); cp->rx_tail = 0; diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 6eb8e2ff52d4..76a257ea33e0 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -2130,7 +2130,9 @@ static int rtl8139_close (struct net_device *dev) spin_unlock_irqrestore (&tp->lock, flags); - synchronize_irq (); + /* TODO: isn't this code racy? we synchronize the IRQ and then free it, */ + /* but another IRQ could've happened in between the sync and free */ + synchronize_irq (dev->irq); free_irq (dev->irq, dev); rtl8139_tx_clear (tp); diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 46d9d832a0d6..dfe2f73298b3 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -3389,14 +3389,14 @@ static int __init read_eeprom_byte(struct net_device *dev, * Don't take interrupts on this CPU will bit banging * the %#%#@$ I2C device */ - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); eeprom_start(regs); eeprom_prep(regs, EEPROM_WRITE_SELECT); if (eeprom_check_ack(regs)) { - __restore_flags(flags); + local_irq_restore(flags); printk(KERN_ERR "%s: Unable to sync eeprom\n", dev->name); result = -EIO; goto eeprom_read_error; @@ -3404,7 +3404,7 @@ static int __init read_eeprom_byte(struct net_device *dev, eeprom_prep(regs, (offset >> 8) & 0xff); if (eeprom_check_ack(regs)) { - __restore_flags(flags); + local_irq_restore(flags); printk(KERN_ERR "%s: Unable to set address byte 0\n", dev->name); result = -EIO; @@ -3413,7 +3413,7 @@ static int __init read_eeprom_byte(struct net_device *dev, eeprom_prep(regs, offset & 0xff); if (eeprom_check_ack(regs)) { - __restore_flags(flags); + local_irq_restore(flags); printk(KERN_ERR "%s: Unable to set address byte 1\n", dev->name); result = -EIO; @@ -3423,7 +3423,7 @@ static int __init read_eeprom_byte(struct net_device *dev, eeprom_start(regs); eeprom_prep(regs, EEPROM_READ_SELECT); if (eeprom_check_ack(regs)) { - __restore_flags(flags); + local_irq_restore(flags); printk(KERN_ERR "%s: Unable to set READ_SELECT\n", dev->name); result = -EIO; @@ -3469,7 +3469,7 @@ static int __init read_eeprom_byte(struct net_device *dev, udelay(ACE_SHORT_DELAY); eeprom_stop(regs); - __restore_flags(flags); + local_irq_restore(flags); out: return result; diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index cd6524d58341..485a0a319a98 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -1354,7 +1354,7 @@ static void speedo_tx_timeout(struct net_device *dev) udelay(10); /* Disable interrupts. */ outw(SCBMaskAll, ioaddr + SCBCmd); - synchronize_irq(); + synchronize_irq(dev->irq); speedo_tx_buffer_gc(dev); /* Free as much as possible. It helps to recover from a hang because of out-of-memory. diff --git a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c index 0819ccc93818..771762a06bed 100644 --- a/drivers/net/fc/iph5526.c +++ b/drivers/net/fc/iph5526.c @@ -3891,7 +3891,7 @@ struct pci_dev *pdev = NULL; } -int iph5526_biosparam(Disk * disk, kdev_t n, int ip[]) +int iph5526_biosparam(Disk * disk, struct block_device *n, int ip[]) { int size = disk->capacity; ip[0] = 64; diff --git a/drivers/net/fc/iph5526_scsi.h b/drivers/net/fc/iph5526_scsi.h index 18221157ba29..a0224c6a0925 100644 --- a/drivers/net/fc/iph5526_scsi.h +++ b/drivers/net/fc/iph5526_scsi.h @@ -25,7 +25,7 @@ int iph5526_queuecommand(Scsi_Cmnd *Cmnd, void (*done) (Scsi_Cmnd *)); int iph5526_release(struct Scsi_Host *host); int iph5526_abort(Scsi_Cmnd *Cmnd); const char *iph5526_info(struct Scsi_Host *host); -int iph5526_biosparam(Disk * disk, kdev_t n, int ip[]); +int iph5526_biosparam(Disk * disk, struct block_device *n, int ip[]); #endif diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c index 03fd3f71682c..0ef5c0d77ea6 100644 --- a/drivers/net/hamradio/baycom_par.c +++ b/drivers/net/hamradio/baycom_par.c @@ -288,14 +288,14 @@ static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs) par96_rx(dev, bc); if (--bc->modem.arb_divider <= 0) { bc->modem.arb_divider = 6; - __sti(); + local_irq_enable(); hdlcdrv_arbitrate(dev, &bc->hdrv); } } - __sti(); + local_irq_enable(); hdlcdrv_transmitter(dev, &bc->hdrv); hdlcdrv_receiver(dev, &bc->hdrv); - __cli(); + local_irq_disable(); } /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c index 4a06e8251142..64eea939a50e 100644 --- a/drivers/net/hamradio/baycom_ser_fdx.c +++ b/drivers/net/hamradio/baycom_ser_fdx.c @@ -350,7 +350,7 @@ static void ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) bc->modem.ser12.txshreg >>= 1; } end_transmit: - __sti(); + local_irq_enable(); if (!bc->modem.ptt && txcount) { hdlcdrv_arbitrate(dev, &bc->hdrv); if (hdlcdrv_ptt(&bc->hdrv)) { @@ -361,7 +361,7 @@ static void ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) } hdlcdrv_transmitter(dev, &bc->hdrv); hdlcdrv_receiver(dev, &bc->hdrv); - __cli(); + local_irq_disable(); } /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c index 479ea0968e4f..9c860f1e5ef3 100644 --- a/drivers/net/hamradio/baycom_ser_hdx.c +++ b/drivers/net/hamradio/baycom_ser_hdx.c @@ -416,13 +416,13 @@ static void ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) } while (!(iir & 1)); if (bc->modem.arb_divider <= 0) { bc->modem.arb_divider = SER12_ARB_DIVIDER(bc); - __sti(); + local_irq_enable(); hdlcdrv_arbitrate(dev, &bc->hdrv); } - __sti(); + local_irq_enable(); hdlcdrv_transmitter(dev, &bc->hdrv); hdlcdrv_receiver(dev, &bc->hdrv); - __cli(); + local_irq_disable(); } /* --------------------------------------------------------------------- */ diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 864d9b833043..47a9422e672c 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -518,7 +518,7 @@ plip_bh_timeout_error(struct net_device *dev, struct net_local *nl, spin_unlock_irq(&nl->lock); if (error == HS_TIMEOUT) { DISABLE(dev->irq); - synchronize_irq(); + synchronize_irq(dev->irq); } disable_parport_interrupts (dev); netif_stop_queue (dev); @@ -840,7 +840,7 @@ plip_send_packet(struct net_device *dev, struct net_local *nl, if (c0 & 0x08) { spin_unlock_irq(&nl->lock); DISABLE(dev->irq); - synchronize_irq(); + synchronize_irq(dev->irq); if (nl->connection == PLIP_CN_RECEIVE) { /* Interrupted. We don't need to enable irq, @@ -1178,7 +1178,7 @@ plip_close(struct net_device *dev) netif_stop_queue (dev); DISABLE(dev->irq); - synchronize_irq(); + synchronize_irq(dev->irq); if (dev->irq == -1) { diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 62139af4dd77..2541f73969cd 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -450,7 +450,7 @@ static int sgiseeq_open(struct net_device *dev) unsigned long flags; int err; - __save_and_cli(flags); + local_irq_save(flags); err = -EAGAIN; if (request_irq(dev->irq, sgiseeq_interrupt, 0, sgiseeqstr, dev)) { @@ -464,7 +464,7 @@ static int sgiseeq_open(struct net_device *dev) netif_start_queue(dev); out: - __restore_flags(flags); + local_irq_restore(flags); return err; } diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 80dcf338487b..fe9796509be8 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -1455,7 +1455,7 @@ static void de_tx_timeout (struct net_device *dev) /* Update the error counts. */ __de_get_stats(de); - synchronize_irq(); + synchronize_irq(dev->irq); de_clean_rings(de); de_init_hw(de); diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index 79a3f784de5e..5f4876da8461 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -534,10 +534,10 @@ __orinoco_start_irqs(struct orinoco_private *priv, u16 irqmask) TRACE_ENTER(priv->ndev->name); - __cli(); /* FIXME: is this necessary? */ + local_irq_disable(); /* FIXME: is this necessary? */ set_bit(ORINOCO_STATE_DOIRQ, &priv->state); hermes_set_irqmask(hw, irqmask); - __sti(); + local_irq_enable(); TRACE_EXIT(priv->ndev->name); } diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index ca62073e1009..beea10ab977d 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -447,11 +447,6 @@ static int dasd_ioctl_set_ro(void *inp, int no, long args) return 0; } -static int dasd_ioctl_blkioctl(void *inp, int no, long args) -{ - return blk_ioctl(((struct inode *) inp)->i_bdev, no, args); -} - /* * Return device size in number of sectors. */ @@ -517,12 +512,12 @@ static int dasd_ioctl_rr_partition(void *inp, int no, long args) static int dasd_ioctl_getgeo(void *inp, int no, long args) { struct hd_geometry geo = { 0, }; + struct inode *inode = inp; dasd_devmap_t *devmap; dasd_device_t *device; - kdev_t kdev; + kdev_t kdev = inode->i_rdev; int rc; - kdev = ((struct inode *) inp)->i_rdev; devmap = dasd_devmap_from_kdev(kdev); device = (devmap != NULL) ? dasd_get_device(devmap) : ERR_PTR(-ENODEV); @@ -532,7 +527,7 @@ static int dasd_ioctl_getgeo(void *inp, int no, long args) if (device != NULL && device->discipline != NULL && device->discipline->fill_geometry != NULL) { device->discipline->fill_geometry(device, &geo); - geo.start = get_start_sect(kdev); + geo.start = get_start_sect(inode->i_bdev); if (copy_to_user((struct hd_geometry *) args, &geo, sizeof (struct hd_geometry))) rc = -EFAULT; @@ -554,16 +549,10 @@ static struct { int no; dasd_ioctl_fn_t fn; } dasd_ioctls[] = { BIODASDINFO2, dasd_ioctl_information }, { BIODASDPRRD, dasd_ioctl_read_profile }, { BIODASDPRRST, dasd_ioctl_reset_profile }, - { BLKELVGET, dasd_ioctl_blkioctl }, - { BLKELVSET, dasd_ioctl_blkioctl }, - { BLKFLSBUF, dasd_ioctl_blkioctl }, { BLKGETSIZE, dasd_ioctl_blkgetsize }, { BLKGETSIZE64, dasd_ioctl_blkgetsize64 }, - { BLKPG, dasd_ioctl_blkioctl }, - { BLKROGET, dasd_ioctl_blkioctl }, { BLKROSET, dasd_ioctl_set_ro }, { BLKRRPART, dasd_ioctl_rr_partition }, - { BLKSSZGET, dasd_ioctl_blkioctl }, { DASDAPIVER, dasd_ioctl_api_version }, { HDIO_GETGEO, dasd_ioctl_getgeo }, { -1, NULL } diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index be899c77943a..3985f4274eac 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -342,14 +342,6 @@ static int xpram_ioctl (struct inode *inode, struct file *filp, if (idx >= xpram_devs) return -ENODEV; switch (cmd) { - case BLKGETSIZE: - /* Return the device size, expressed in sectors */ - return put_user(xpram_sizes[idx] << 1, (unsigned long *) arg); - case BLKGETSIZE64: - /* Return the device size, expressed in bytes */ - return put_user((u64) xpram_sizes[idx] << 10, (u64 *) arg); - case BLKFLSBUF: - return blk_ioctl(((struct inode *) inode)->i_bdev, cmd, arg); case BLKRRPART: /* re-read partition table: can't do it */ return -EINVAL; diff --git a/drivers/s390/char/tubio.h b/drivers/s390/char/tubio.h index 4e4fd0dbc858..e9a6d04cfd8c 100644 --- a/drivers/s390/char/tubio.h +++ b/drivers/s390/char/tubio.h @@ -338,11 +338,11 @@ extern void fs3270_devfs_unregister(tub_t *); #define spin_trylock_irqsave(lock, flags) \ ({ \ int success; \ - __save_flags(flags); \ - __cli(); \ + local_save_flags(flags); \ + local_irq_disable(); \ success = spin_trylock(lock); \ if (success == 0) \ - __restore_flags(flags); \ + local_irq_restore(flags); \ success; \ }) #endif /* if not spin_trylock_irqsave */ diff --git a/drivers/s390/cio/s390io.c b/drivers/s390/cio/s390io.c index ddb2f90c61de..1e4e0fac63ec 100644 --- a/drivers/s390/cio/s390io.c +++ b/drivers/s390/cio/s390io.c @@ -163,11 +163,11 @@ s390_init_IRQ (void) * function we resestablish the old environment. * * Note : as we don't need a system wide lock, therefore - * we shouldn't use cli(), but __cli() as this + * we shouldn't use cli(), but local_irq_disable() as this * affects the current CPU only. */ - __save_flags (flags); - __cli (); + local_save_flags (flags); + local_irq_disable (); /* * disable all interrupts @@ -204,7 +204,7 @@ s390_init_IRQ (void) init_IRQ_complete = 1; - __restore_flags (flags); + local_irq_restore (flags); return; } @@ -578,10 +578,10 @@ read_dev_chars (int irq, void **buffer, int length) * also require to run disabled. * * Note : as no global lock is required, we must not use - * cli(), but __cli() instead. + * cli(), but local_irq_disable() instead. */ - __save_flags (flags); - __cli (); + local_save_flags (flags); + local_irq_disable (); rdc_ccw = &ioinfo[irq]->senseccw; @@ -643,7 +643,7 @@ read_dev_chars (int irq, void **buffer, int length) } - __restore_flags (flags); + local_irq_restore (flags); /* * on success we update the user input parms @@ -720,8 +720,8 @@ read_conf_data (int irq, void **buffer, int *length, __u8 lpm) int emulated = 0; /* no i/O handler installed */ int retry = 5; /* retry count */ - __save_flags (flags); - __cli (); + local_save_flags (flags); + local_irq_disable (); if (!ioinfo[irq]->ui.flags.ready) { pdevstat = &devstat; @@ -816,7 +816,7 @@ read_conf_data (int irq, void **buffer, int *length, __u8 lpm) } - __restore_flags (flags); + local_irq_restore (flags); } diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index 6fb0b535c58e..1913714b5ba7 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -968,7 +968,7 @@ lcs_kernel_thread(lcs_drvr_globals * drvr_globals) #if LINUX_VERSION_CODE<=KERNEL_VERSION(2,2,16) /* tq_scheduler sometimes leaves interrupts disabled from do * bottom half */ - __sti(); + local_irq_enable(); #endif if (kernel_thread((int (*)(void *)) drvr_globals->kernel_thread_routine, (void *) drvr_globals, SIGCHLD) < 0) { diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c index 3db5c108ee5c..6cbd8545ebba 100644 --- a/drivers/s390/s390mach.c +++ b/drivers/s390/s390mach.c @@ -254,8 +254,8 @@ s390_machine_check_handler(void *parm) found = 0; /* init ... */ - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); do { @@ -311,7 +311,7 @@ s390_machine_check_handler(void *parm) } while (pmache); - __restore_flags(flags); + local_irq_restore(flags); } while (1); diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index a2c58e179445..c7d5306043c6 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -464,14 +464,6 @@ static int jsfd_ioctl(struct inode *inode, struct file *file, case BLKGETSIZE64: return put_user(jsfd_bytesizes[dev], (u64 *) arg); -#if 0 - case BLKROSET: - case BLKROGET: - case BLKSSZGET: - return blk_ioctl(inode->i_bdev, cmd, arg); -#endif - - /* case BLKFLSBUF: */ /* Program, then read, what happens? Stale? */ default: ; } return -ENOTTY; diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 87b883e6107f..3e71b678fb64 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -2084,7 +2084,7 @@ int tw_reset_sequence(TW_Device_Extension *tw_dev) } /* End tw_reset_sequence() */ /* This funciton returns unit geometry in cylinders/heads/sectors */ -int tw_scsi_biosparam(Disk *disk, kdev_t dev, int geom[]) +int tw_scsi_biosparam(Disk *disk, struct block_device *dev, int geom[]) { int heads, sectors, cylinders; TW_Device_Extension *tw_dev; diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index 4dce8ea588e0..3f96e3753da3 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h @@ -56,7 +56,6 @@ #include <linux/version.h> #include <linux/types.h> -#include <linux/kdev_t.h> /* AEN strings */ static char *tw_aen_string[] = { @@ -445,7 +444,7 @@ int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds); int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id); int tw_reset_device_extension(TW_Device_Extension *tw_dev); int tw_reset_sequence(TW_Device_Extension *tw_dev); -int tw_scsi_biosparam(Disk *disk, kdev_t dev, int geom[]); +int tw_scsi_biosparam(Disk *disk, struct block_device *dev, int geom[]); int tw_scsi_detect(Scsi_Host_Template *tw_host); int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt); int tw_scsi_eh_reset(Scsi_Cmnd *SCpnt); diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index e7e9dcab1884..08ba8fba4876 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -4110,7 +4110,7 @@ int BusLogic_ResetCommand(SCSI_Command_T *Command, unsigned int ResetFlags) the BIOS, and a warning may be displayed. */ -int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device, +int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, struct block_device *bdev, int *Parameters) { BusLogic_HostAdapter_T *HostAdapter = @@ -4138,7 +4138,7 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device, } DiskParameters->Cylinders = Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors); - buf = scsi_bios_ptable(Device); + buf = scsi_bios_ptable(bdev); if (buf == NULL) return 0; /* If the boot sector partition table flag is valid, search for a partition diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h index e415cbc9a67d..44822851a138 100644 --- a/drivers/scsi/BusLogic.h +++ b/drivers/scsi/BusLogic.h @@ -34,7 +34,6 @@ of the Linux Kernel and SCSI Subsystem. */ -typedef kdev_t KernelDevice_T; typedef unsigned long ProcessorFlags_T; typedef struct pt_regs Registers_T; typedef struct partition PartitionTable_T; @@ -58,7 +57,7 @@ extern int BusLogic_QueueCommand(SCSI_Command_T *, void (*CompletionRoutine)(SCSI_Command_T *)); extern int BusLogic_AbortCommand(SCSI_Command_T *); extern int BusLogic_ResetCommand(SCSI_Command_T *, unsigned int); -extern int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, KernelDevice_T, int *); +extern int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, struct block_device *, int *); extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int); diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c index bffa89fb0d43..119869ca0e8e 100644 --- a/drivers/scsi/NCR53c406a.c +++ b/drivers/scsi/NCR53c406a.c @@ -760,7 +760,7 @@ NCR53c406a_reset(Scsi_Cmnd *SCpnt, unsigned int ignored){ } int -NCR53c406a_biosparm(Scsi_Disk *disk, kdev_t dev, int* info_array){ +NCR53c406a_biosparm(Scsi_Disk *disk, struct block_device *dev, int* info_array){ int size; DEB(printk("NCR53c406a_biosparm called\n")); diff --git a/drivers/scsi/NCR53c406a.h b/drivers/scsi/NCR53c406a.h index 0ef6c67ba6a7..b056a9367f8b 100644 --- a/drivers/scsi/NCR53c406a.h +++ b/drivers/scsi/NCR53c406a.h @@ -50,7 +50,7 @@ int NCR53c406a_command(Scsi_Cmnd *); int NCR53c406a_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int NCR53c406a_abort(Scsi_Cmnd *); int NCR53c406a_reset(Scsi_Cmnd *, unsigned int); -int NCR53c406a_biosparm(Disk *, kdev_t, int []); +int NCR53c406a_biosparm(Disk *, struct block_device *, int []); #endif /* _NCR53C406A_H */ diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 107fae08cb44..ace0da2c55c0 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -6114,7 +6114,7 @@ advansys_reset(Scsi_Cmnd *scp) * ip[2]: cylinders */ int -advansys_biosparam(Disk *dp, kdev_t dep, int ip[]) +advansys_biosparam(Disk *dp, struct block_device *dep, int ip[]) { asc_board_t *boardp; diff --git a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h index 22cdadd55f2f..756e5c64cc78 100644 --- a/drivers/scsi/advansys.h +++ b/drivers/scsi/advansys.h @@ -52,7 +52,7 @@ int advansys_release(struct Scsi_Host *); const char *advansys_info(struct Scsi_Host *); int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); int advansys_reset(Scsi_Cmnd *); -int advansys_biosparam(Disk *, kdev_t, int[]); +int advansys_biosparam(Disk *, struct block_device *, int[]); #ifdef CONFIG_PROC_FS #if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28) extern struct proc_dir_entry proc_scsi_advansys; diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c index 4a9a9cfb93f5..7f353ce582d9 100644 --- a/drivers/scsi/aha152x.c +++ b/drivers/scsi/aha152x.c @@ -1830,7 +1830,7 @@ int aha152x_host_reset(Scsi_Cmnd * SCpnt) * Return the "logical geometry" * */ -int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array) +int aha152x_biosparam(Scsi_Disk * disk, struct block_device *bdev, int *info_array) { struct Scsi_Host *shpnt = disk->device->host; @@ -1844,7 +1844,7 @@ int aha152x_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array) int info[3]; /* try to figure out the geometry from the partition table */ - if (scsicam_bios_param(disk, dev, info) < 0 || + if (scsicam_bios_param(disk, bdev, info) < 0 || !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) { if (EXT_TRANS) { printk(KERN_NOTICE diff --git a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h index d0a7126ccf7d..0bd6c02ff796 100644 --- a/drivers/scsi/aha152x.h +++ b/drivers/scsi/aha152x.h @@ -20,7 +20,7 @@ int aha152x_release(struct Scsi_Host *shpnt); int aha152x_device_reset(Scsi_Cmnd *); int aha152x_bus_reset(Scsi_Cmnd *); int aha152x_host_reset(Scsi_Cmnd *); -int aha152x_biosparam(Disk *, kdev_t, int*); +int aha152x_biosparam(Disk *, struct block_device *, int*); int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); /* number of queueable commands diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c index ad1af6379ffb..96712452a8fa 100644 --- a/drivers/scsi/aha1542.c +++ b/drivers/scsi/aha1542.c @@ -1783,7 +1783,7 @@ fail: #include "sd.h" -static int aha1542_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip) +static int aha1542_biosparam(Scsi_Disk * disk, struct block_device *dev, int *ip) { int translation_algorithm; int size = disk->capacity; diff --git a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h index a15fff3b2fd2..4808317841f6 100644 --- a/drivers/scsi/aha1542.h +++ b/drivers/scsi/aha1542.h @@ -32,7 +32,6 @@ */ #include <linux/types.h> -#include <linux/kdev_t.h> /* I/O Port interface 4.2 */ /* READ */ @@ -141,7 +140,7 @@ static int aha1542_host_reset(Scsi_Cmnd * SCpnt); static int aha1542_old_abort(Scsi_Cmnd * SCpnt); static int aha1542_old_reset(Scsi_Cmnd *, unsigned int); #endif -static int aha1542_biosparam(Disk *, kdev_t, int*); +static int aha1542_biosparam(Disk *, struct block_device *, int*); #define AHA1542_MAILBOXES 8 #define AHA1542_SCATTER 16 diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c index ad043e6020c8..de1e23c9fbb7 100644 --- a/drivers/scsi/aha1740.c +++ b/drivers/scsi/aha1740.c @@ -590,7 +590,7 @@ int aha1740_reset(Scsi_Cmnd * SCpnt, unsigned int ignored) return SCSI_RESET_PUNT; } -int aha1740_biosparam(Disk * disk, kdev_t dev, int* ip) +int aha1740_biosparam(Disk * disk, struct block_device *dev, int* ip) { int size = disk->capacity; int extended = HOSTDATA(disk->device->host)->translation; diff --git a/drivers/scsi/aha1740.h b/drivers/scsi/aha1740.h index 036effaa4e17..9a4410976961 100644 --- a/drivers/scsi/aha1740.h +++ b/drivers/scsi/aha1740.h @@ -11,7 +11,6 @@ */ #include <linux/types.h> -#include <linux/kdev_t.h> /* Eisa Enhanced mode operation - slot locating and addressing */ #define MINEISA 1 /* I don't have an EISA Spec to know these ranges, so I */ @@ -158,7 +157,7 @@ int aha1740_command(Scsi_Cmnd *); int aha1740_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int aha1740_abort(Scsi_Cmnd *); int aha1740_reset(Scsi_Cmnd *, unsigned int); -int aha1740_biosparam(Disk *, kdev_t, int*); +int aha1740_biosparam(Disk *, struct block_device *, int*); int aha1740_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); diff --git a/drivers/scsi/aic7xxx/aic7xxx_linux.c b/drivers/scsi/aic7xxx/aic7xxx_linux.c index a5ed9dac061a..ffcbb4aa09e0 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_linux.c +++ b/drivers/scsi/aic7xxx/aic7xxx_linux.c @@ -2722,7 +2722,7 @@ ahc_linux_bus_reset(Scsi_Cmnd *cmd) * Return the disk geometry for the given SCSI device. */ int -ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) +ahc_linux_biosparam(Disk *disk, struct block_device *bdev, int geom[]) { int heads; int sectors; @@ -2733,7 +2733,7 @@ ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) unsigned char *buf; ahc = *((struct ahc_softc **)disk->device->host->hostdata); - buf = scsi_bios_ptable(dev); + buf = scsi_bios_ptable(bdev); if (buf) { ret = scsi_partsize(buf, disk->capacity, diff --git a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h index 491b0eb49872..4c3735f5a392 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h +++ b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h @@ -47,7 +47,7 @@ int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); int ahc_linux_detect(Scsi_Host_Template *); int ahc_linux_release(struct Scsi_Host *); const char *ahc_linux_info(struct Scsi_Host *); -int ahc_linux_biosparam(Disk *, kdev_t, int[]); +int ahc_linux_biosparam(Disk *, struct block_device *, int[]); int ahc_linux_bus_reset(Scsi_Cmnd *); int ahc_linux_dev_reset(Scsi_Cmnd *); int ahc_linux_abort(Scsi_Cmnd *); diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c index ae927a405e08..acf88a76fca0 100644 --- a/drivers/scsi/aic7xxx_old.c +++ b/drivers/scsi/aic7xxx_old.c @@ -11719,14 +11719,14 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags) * Return the disk geometry for the given SCSI device. *-F*************************************************************************/ int -aic7xxx_biosparam(Disk *disk, kdev_t dev, int geom[]) +aic7xxx_biosparam(Disk *disk, struct block_device *bdev, int geom[]) { int heads, sectors, cylinders, ret; struct aic7xxx_host *p; unsigned char *buf; p = (struct aic7xxx_host *) disk->device->host->hostdata; - buf = scsi_bios_ptable(dev); + buf = scsi_bios_ptable(bdev); if ( buf ) { diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.h b/drivers/scsi/aic7xxx_old/aic7xxx.h index ce397e38d5e8..ac1d78b8602f 100644 --- a/drivers/scsi/aic7xxx_old/aic7xxx.h +++ b/drivers/scsi/aic7xxx_old/aic7xxx.h @@ -58,7 +58,7 @@ } extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); -extern int aic7xxx_biosparam(Disk *, kdev_t, int[]); +extern int aic7xxx_biosparam(Disk *, struct block_device *, int[]); extern int aic7xxx_detect(Scsi_Host_Template *); extern int aic7xxx_command(Scsi_Cmnd *); extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int); diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index 5ba17a3bc2ff..6f64a4466d71 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -2835,7 +2835,7 @@ stop_output: #include "sd.h" -int atp870u_biosparam(Scsi_Disk * disk, kdev_t dev, int *ip) +int atp870u_biosparam(Scsi_Disk * disk, struct block_device *dev, int *ip) { int heads, sectors, cylinders; diff --git a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h index cda1a387ca67..ab61bf99891e 100644 --- a/drivers/scsi/atp870u.h +++ b/drivers/scsi/atp870u.h @@ -11,7 +11,6 @@ */ #include <linux/types.h> -#include <linux/kdev_t.h> /* I/O Port */ @@ -23,7 +22,7 @@ int atp870u_command(Scsi_Cmnd *); int atp870u_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int atp870u_abort(Scsi_Cmnd *); int atp870u_reset(Scsi_Cmnd *, unsigned int); -int atp870u_biosparam(Disk *, kdev_t, int *); +int atp870u_biosparam(Disk *, struct block_device *, int *); int atp870u_release(struct Scsi_Host *); void send_s870(unsigned char); diff --git a/drivers/scsi/cpqfcTS.h b/drivers/scsi/cpqfcTS.h index 529171e82b9a..a91b3ca51a99 100644 --- a/drivers/scsi/cpqfcTS.h +++ b/drivers/scsi/cpqfcTS.h @@ -12,7 +12,7 @@ extern int cpqfcTS_abort(Scsi_Cmnd *); extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int); extern int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd); extern int cpqfcTS_eh_device_reset(Scsi_Cmnd *); -extern int cpqfcTS_biosparam(Disk *, kdev_t, int[]); +extern int cpqfcTS_biosparam(Disk *, struct block_device *, int[]); extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg); // note: since Tachyon TS supports an extended scatter/gather diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c index f38e377207c7..dbac6cde86d9 100644 --- a/drivers/scsi/cpqfcTSinit.c +++ b/drivers/scsi/cpqfcTSinit.c @@ -1625,7 +1625,7 @@ int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags) (from hosts.h) */ -int cpqfcTS_biosparam(Disk *disk, kdev_t n, int ip[]) +int cpqfcTS_biosparam(Disk *disk, struct block_device *n, int ip[]) { int size = disk->capacity; diff --git a/drivers/scsi/dc390.h b/drivers/scsi/dc390.h index 02fe82eaf1db..be436bf43d83 100644 --- a/drivers/scsi/dc390.h +++ b/drivers/scsi/dc390.h @@ -39,7 +39,7 @@ extern int DC390_detect(Scsi_Host_Template *psht); extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); extern int DC390_abort(Scsi_Cmnd *cmd); extern int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags); -extern int DC390_bios_param(Disk *disk, kdev_t devno, int geom[]); +extern int DC390_bios_param(Disk *disk, struct block_device *dev, int geom[]); #ifdef MODULE static int DC390_release(struct Scsi_Host *); diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index e20cfea59b60..f063b5dc1738 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -453,7 +453,7 @@ static int adpt_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) return adpt_scsi_to_i2o(pHba, cmd, pDev); } -static int adpt_bios_param(Disk* disk, kdev_t dev, int geom[]) +static int adpt_bios_param(Disk* disk, struct block_device *dev, int geom[]) { int heads=-1; int sectors=-1; diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h index 670afcc2c070..dfff119adc2b 100644 --- a/drivers/scsi/dpti.h +++ b/drivers/scsi/dpti.h @@ -45,7 +45,7 @@ static int adpt_reset(Scsi_Cmnd* cmd); static int adpt_release(struct Scsi_Host *host); static const char *adpt_info(struct Scsi_Host *pSHost); -static int adpt_bios_param(Disk * disk, kdev_t dev, int geom[]); +static int adpt_bios_param(Disk * disk, struct block_device *dev, int geom[]); static int adpt_bus_reset(Scsi_Cmnd* cmd); static int adpt_device_reset(Scsi_Cmnd* cmd); diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c index 910effea59b4..2fa2cd414363 100644 --- a/drivers/scsi/dtc.c +++ b/drivers/scsi/dtc.c @@ -295,7 +295,7 @@ int __init dtc_detect(Scsi_Host_Template * tpnt){ } /* - * Function : int dtc_biosparam(Disk * disk, kdev_t dev, int *ip) + * Function : int dtc_biosparam(Disk * disk, struct block_device *dev, int *ip) * * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for * the specified device / size. @@ -314,7 +314,7 @@ int __init dtc_detect(Scsi_Host_Template * tpnt){ * and matching the H_C_S coordinates to what DOS uses. */ -int dtc_biosparam(Disk * disk, kdev_t dev, int * ip) +int dtc_biosparam(Disk * disk, struct block_device *dev, int * ip) { int size = disk->capacity; diff --git a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h index 73616ed085c0..f5ce0c95df3e 100644 --- a/drivers/scsi/dtc.h +++ b/drivers/scsi/dtc.h @@ -30,7 +30,7 @@ #ifndef ASM int dtc_abort(Scsi_Cmnd *); -int dtc_biosparam(Disk *, kdev_t, int*); +int dtc_biosparam(Disk *, struct block_device *, int*); int dtc_detect(Scsi_Host_Template *); int dtc_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int dtc_reset(Scsi_Cmnd *, unsigned int reset_flags); diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c index cc73354accc6..9690e38bed42 100644 --- a/drivers/scsi/eata.c +++ b/drivers/scsi/eata.c @@ -1803,10 +1803,10 @@ int eata2x_reset(Scsi_Cmnd *SCarg) { return do_reset(SCarg); } -int eata2x_biosparam(Disk *disk, kdev_t dev, int *dkinfo) { +int eata2x_biosparam(Disk *disk, struct block_device *bdev, int *dkinfo) { int size = disk->capacity; - if (ext_tran || (scsicam_bios_param(disk, dev, dkinfo) < 0)) { + if (ext_tran || (scsicam_bios_param(disk, bdev, dkinfo) < 0)) { dkinfo[0] = 255; dkinfo[1] = 63; dkinfo[2] = size / (dkinfo[0] * dkinfo[1]); diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h index f1c5e5b84b91..56f00bf01c7b 100644 --- a/drivers/scsi/eata.h +++ b/drivers/scsi/eata.h @@ -11,7 +11,7 @@ int eata2x_release(struct Scsi_Host *); int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int eata2x_abort(Scsi_Cmnd *); int eata2x_reset(Scsi_Cmnd *); -int eata2x_biosparam(Disk *, kdev_t, int *); +int eata2x_biosparam(Disk *, struct block_device *, int *); #define EATA_VERSION "7.22.00" diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c index c41d92c3f08e..271ce78aa14f 100644 --- a/drivers/scsi/fd_mcs.c +++ b/drivers/scsi/fd_mcs.c @@ -1383,9 +1383,8 @@ int fd_mcs_reset( Scsi_Cmnd *SCpnt, unsigned int reset_flags ) #include "sd.h" #include <scsi/scsi_ioctl.h> -int fd_mcs_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array ) +int fd_mcs_biosparam( Scsi_Disk *disk, struct block_device *bdev, int *info_array ) { - int drive; unsigned char buf[512 + sizeof( int ) * 2]; int size = disk->capacity; int *sizes = (int *)buf; @@ -1394,8 +1393,6 @@ int fd_mcs_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array ) int retcode; /* BIOS >= 3.4 for MCA cards */ - drive = MINOR(dev) / 16; - /* This algorithm was provided by Future Domain (much thanks!). */ sizes[0] = 0; /* zero bytes out */ diff --git a/drivers/scsi/fd_mcs.h b/drivers/scsi/fd_mcs.h index 1841d5c28661..fb490c906afc 100644 --- a/drivers/scsi/fd_mcs.h +++ b/drivers/scsi/fd_mcs.h @@ -28,7 +28,7 @@ extern int fd_mcs_command( Scsi_Cmnd * ); extern int fd_mcs_abort( Scsi_Cmnd * ); extern int fd_mcs_reset( Scsi_Cmnd *, unsigned int ); extern int fd_mcs_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) ); -extern int fd_mcs_biosparam( Disk *, kdev_t, int * ); +extern int fd_mcs_biosparam( Disk *, struct block_device *, int * ); extern int fd_mcs_proc_info( char *, char **, off_t, int, int, int ); extern const char *fd_mcs_info(struct Scsi_Host *); diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c index c853eabf386f..6fdd13a4c1a4 100644 --- a/drivers/scsi/fdomain.c +++ b/drivers/scsi/fdomain.c @@ -1874,7 +1874,7 @@ int fdomain_16x0_reset( Scsi_Cmnd *SCpnt, unsigned int ignored ) #include "sd.h" #include <scsi/scsi_ioctl.h> -int fdomain_16x0_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array ) +int fdomain_16x0_biosparam( Scsi_Disk *disk, struct block_device *bdev, int *info_array ) { int drive; unsigned char buf[512 + sizeof (Scsi_Ioctl_Command)]; @@ -1933,11 +1933,11 @@ int fdomain_16x0_biosparam( Scsi_Disk *disk, kdev_t dev, int *info_array ) 0x0a bytes long. Heads are one less than we need to report. */ - if (major(dev) != SCSI_DISK0_MAJOR) { + if (MAJOR(bdev->bd_dev) != SCSI_DISK0_MAJOR) { printk("scsi: <fdomain> fdomain_16x0_biosparam: too many disks"); return 0; } - drive = minor(dev) >> 4; + drive = MINOR(bdev->bd_dev) >> 4; if (bios_major == 2) { switch (Quantum) { diff --git a/drivers/scsi/fdomain.h b/drivers/scsi/fdomain.h index a85539af125b..cc1f8babadaa 100644 --- a/drivers/scsi/fdomain.h +++ b/drivers/scsi/fdomain.h @@ -31,7 +31,7 @@ int fdomain_16x0_abort( Scsi_Cmnd * ); const char *fdomain_16x0_info( struct Scsi_Host * ); int fdomain_16x0_reset( Scsi_Cmnd *, unsigned int ); int fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) ); -int fdomain_16x0_biosparam( Disk *, kdev_t, int * ); +int fdomain_16x0_biosparam( Disk *, struct block_device *, int * ); int fdomain_16x0_proc_info( char *buffer, char **start, off_t offset, int length, int hostno, int inout ); int fdomain_16x0_release( struct Scsi_Host *shpnt ); diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index ae4136b29491..8789580496b6 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -512,7 +512,7 @@ int generic_NCR5380_release_resources(struct Scsi_Host *instance) * Locks: none */ -int generic_NCR5380_biosparam(Disk * disk, kdev_t dev, int *ip) +int generic_NCR5380_biosparam(Disk * disk, struct block_device *dev, int *ip) { int size = disk->capacity; ip[0] = 64; diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h index 3ab55b6f7bcd..0d07adaa8e9f 100644 --- a/drivers/scsi/g_NCR5380.h +++ b/drivers/scsi/g_NCR5380.h @@ -53,7 +53,7 @@ int notyet_generic_proc_info (char *buffer ,char **start, off_t offset, int length, int hostno, int inout); const char* generic_NCR5380_info(struct Scsi_Host *); #ifdef BIOSPARAM -int generic_NCR5380_biosparam(Disk *, kdev_t, int *); +int generic_NCR5380_biosparam(Disk *, struct block_device *, int *); #endif int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout); diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 8508b693f316..2cb9f5d75851 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -4512,11 +4512,7 @@ int gdth_eh_host_reset(Scsi_Cmnd *scp) } #endif -#if LINUX_VERSION_CODE >= 0x010300 -int gdth_bios_param(Disk *disk,kdev_t dev,int *ip) -#else -int gdth_bios_param(Disk *disk,int dev,int *ip) -#endif +int gdth_bios_param(Disk *disk,struct block_device *bdev,int *ip) { unchar b, t; int hanum; diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h index 1b34a881014a..67355b74b832 100644 --- a/drivers/scsi/gdth.h +++ b/drivers/scsi/gdth.h @@ -1031,8 +1031,7 @@ int gdth_reset(Scsi_Cmnd *); #endif const char *gdth_info(struct Scsi_Host *); -#if LINUX_VERSION_CODE >= 0x020322 -int gdth_bios_param(Disk *,kdev_t,int *); +int gdth_bios_param(Disk *,struct block_device *,int *); int gdth_proc_info(char *,char **,off_t,int,int,int); int gdth_eh_abort(Scsi_Cmnd *scp); int gdth_eh_device_reset(Scsi_Cmnd *scp); @@ -1061,83 +1060,5 @@ int gdth_eh_host_reset(Scsi_Cmnd *scp); unchecked_isa_dma: 1, \ use_clustering: ENABLE_CLUSTERING } -#elif LINUX_VERSION_CODE >= 0x02015F -int gdth_bios_param(Disk *,kdev_t,int *); -extern struct proc_dir_entry proc_scsi_gdth; -int gdth_proc_info(char *,char **,off_t,int,int,int); -int gdth_eh_abort(Scsi_Cmnd *scp); -int gdth_eh_device_reset(Scsi_Cmnd *scp); -int gdth_eh_bus_reset(Scsi_Cmnd *scp); -int gdth_eh_host_reset(Scsi_Cmnd *scp); -#define GDTH { proc_dir: &proc_scsi_gdth, \ - proc_info: gdth_proc_info, \ - name: "GDT SCSI Disk Array Controller",\ - detect: gdth_detect, \ - release: gdth_release, \ - info: gdth_info, \ - command: NULL, \ - queuecommand: gdth_queuecommand, \ - eh_abort_handler: gdth_eh_abort, \ - eh_device_reset_handler: gdth_eh_device_reset, \ - eh_bus_reset_handler: gdth_eh_bus_reset, \ - eh_host_reset_handler: gdth_eh_host_reset, \ - abort: gdth_abort, \ - reset: gdth_reset, \ - bios_param: gdth_bios_param, \ - can_queue: GDTH_MAXCMDS, \ - this_id: -1, \ - sg_tablesize: GDTH_MAXSG, \ - cmd_per_lun: GDTH_MAXC_P_L, \ - present: 0, \ - unchecked_isa_dma: 1, \ - use_clustering: ENABLE_CLUSTERING } - -#elif LINUX_VERSION_CODE >= 0x010300 -int gdth_bios_param(Disk *,kdev_t,int *); -extern struct proc_dir_entry proc_scsi_gdth; -int gdth_proc_info(char *,char **,off_t,int,int,int); -#define GDTH { NULL, NULL, \ - &proc_scsi_gdth, \ - gdth_proc_info, \ - "GDT SCSI Disk Array Controller", \ - gdth_detect, \ - gdth_release, \ - gdth_info, \ - NULL, \ - gdth_queuecommand, \ - gdth_abort, \ - gdth_reset, \ - NULL, \ - gdth_bios_param, \ - GDTH_MAXCMDS, \ - -1, \ - GDTH_MAXSG, \ - GDTH_MAXC_P_L, \ - 0, \ - 1, \ - ENABLE_CLUSTERING} - -#else -int gdth_bios_param(Disk *,int,int *); -#define GDTH { NULL, NULL, \ - "GDT SCSI Disk Array Controller", \ - gdth_detect, \ - gdth_release, \ - gdth_info, \ - NULL, \ - gdth_queuecommand, \ - gdth_abort, \ - gdth_reset, \ - NULL, \ - gdth_bios_param, \ - GDTH_MAXCMDS, \ - -1, \ - GDTH_MAXSG, \ - GDTH_MAXC_P_L, \ - 0, \ - 1, \ - ENABLE_CLUSTERING} -#endif - #endif diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h index f338366ff443..4d7f25dda311 100644 --- a/drivers/scsi/hosts.h +++ b/drivers/scsi/hosts.h @@ -210,9 +210,9 @@ typedef struct SHT * This function determines the bios parameters for a given * harddisk. These tend to be numbers that are made up by * the host adapter. Parameters: - * size, device number, list (heads, sectors, cylinders) + * size, device, list (heads, sectors, cylinders) */ - int (* bios_param)(Disk *, kdev_t, int []); + int (* bios_param)(Disk *, struct block_device *, int []); /* diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c index 1b034e4e4e7f..09d809bae4c8 100644 --- a/drivers/scsi/ibmmca.c +++ b/drivers/scsi/ibmmca.c @@ -2382,7 +2382,7 @@ int ibmmca_reset (Scsi_Cmnd * cmd, unsigned int reset_flags) return SCSI_RESET_SUCCESS; } -int ibmmca_biosparam (Disk * disk, kdev_t dev, int *info) +int ibmmca_biosparam (Disk * disk, struct block_device *dev, int *info) { info[0] = 64; info[1] = 32; diff --git a/drivers/scsi/ibmmca.h b/drivers/scsi/ibmmca.h index fa3ec5458576..d8df93cd0ec3 100644 --- a/drivers/scsi/ibmmca.h +++ b/drivers/scsi/ibmmca.h @@ -17,7 +17,7 @@ extern int ibmmca_command (Scsi_Cmnd *); extern int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); extern int ibmmca_abort (Scsi_Cmnd *); extern int ibmmca_reset (Scsi_Cmnd *, unsigned int); -extern int ibmmca_biosparam (Disk *, kdev_t, int *); +extern int ibmmca_biosparam (Disk *, struct block_device *, int *); /*structure for /proc filesystem */ extern struct proc_dir_entry proc_scsi_ibmmca; diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 6cb967d14650..f05c5f37b1ed 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -711,7 +711,7 @@ static int idescsi_device_reset(Scsi_Cmnd *cmd) return SUCCESS; } -static int idescsi_bios(Disk *disk, kdev_t dev, int *parm) +static int idescsi_bios(Disk *disk, struct block_device *dev, int *parm) { idescsi_scsi_t *scsi = idescsi_private(disk->device->host); struct ata_device *drive = scsi->drive; diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c index 161cf9799a40..a23e04a157f1 100644 --- a/drivers/scsi/imm.c +++ b/drivers/scsi/imm.c @@ -1117,7 +1117,7 @@ int imm_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) * be done in sd.c. Even if it gets fixed there, this will still * work. */ -int imm_biosparam(Disk * disk, kdev_t dev, int ip[]) +int imm_biosparam(Disk * disk, struct block_device *dev, int ip[]) { ip[0] = 0x40; ip[1] = 0x20; diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h index ab3c8a71c369..ac28d5063c4d 100644 --- a/drivers/scsi/imm.h +++ b/drivers/scsi/imm.h @@ -162,7 +162,7 @@ int imm_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int imm_abort(Scsi_Cmnd *); int imm_reset(Scsi_Cmnd *); int imm_proc_info(char *, char **, off_t, int, int, int); -int imm_biosparam(Disk *, kdev_t, int *); +int imm_biosparam(Disk *, struct block_device *, int *); #define IMM { proc_name: "imm", \ proc_info: imm_proc_info, \ diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c index 5659858c18d9..83fe01110ce0 100644 --- a/drivers/scsi/in2000.c +++ b/drivers/scsi/in2000.c @@ -2158,7 +2158,7 @@ char buf[32]; * supposed to do... */ -int in2000_biosparam(Disk *disk, kdev_t dev, int *iinfo) +int in2000_biosparam(Disk *disk, struct block_device *dev, int *iinfo) { int size; diff --git a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h index 4f12b8fd5e94..f29f4de0bd94 100644 --- a/drivers/scsi/in2000.h +++ b/drivers/scsi/in2000.h @@ -402,7 +402,7 @@ int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int in2000_abort(Scsi_Cmnd *); void in2000_setup(char *, int *) in2000__INIT; int in2000_proc_info(char *, char **, off_t, int, int, int); -int in2000_biosparam(struct scsi_disk *, kdev_t, int *); +int in2000_biosparam(struct scsi_disk *, struct block_device *, int *); int in2000_reset(Scsi_Cmnd *, unsigned int); diff --git a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c index c6c53caf11d3..dd252714d421 100644 --- a/drivers/scsi/ini9100u.c +++ b/drivers/scsi/ini9100u.c @@ -583,7 +583,7 @@ int i91u_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) /* * Return the "logical geometry" */ -int i91u_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array) +int i91u_biosparam(Scsi_Disk * disk, struct block_device *dev, int *info_array) { HCS *pHcb; /* Point to Host adapter control block */ TCS *pTcb; diff --git a/drivers/scsi/ini9100u.h b/drivers/scsi/ini9100u.h index 557518771e40..a8e88f538f97 100644 --- a/drivers/scsi/ini9100u.h +++ b/drivers/scsi/ini9100u.h @@ -84,7 +84,7 @@ extern int i91u_command(Scsi_Cmnd *); extern int i91u_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); extern int i91u_abort(Scsi_Cmnd *); extern int i91u_reset(Scsi_Cmnd *, unsigned int); -extern int i91u_biosparam(Scsi_Disk *, kdev_t, int *); /*for linux v2.0 */ +extern int i91u_biosparam(Scsi_Disk *, struct block_device *, int *); #define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.03g" diff --git a/drivers/scsi/inia100.c b/drivers/scsi/inia100.c index f4685153398f..e5dc661cc491 100644 --- a/drivers/scsi/inia100.c +++ b/drivers/scsi/inia100.c @@ -653,7 +653,7 @@ void inia100SCBPost(BYTE * pHcb, BYTE * pScb) Output : None. Return : pSRB - Pointer to SCSI request block. *****************************************************************************/ -int inia100_biosparam(Scsi_Disk * disk, kdev_t dev, int *info_array) +int inia100_biosparam(Scsi_Disk * disk, struct block_device *dev, int *info_array) { ORC_HCS *pHcb; /* Point to Host adapter control block */ ORC_TCS *pTcb; diff --git a/drivers/scsi/inia100.h b/drivers/scsi/inia100.h index 786b28329aa9..431c8adfff09 100644 --- a/drivers/scsi/inia100.h +++ b/drivers/scsi/inia100.h @@ -83,7 +83,7 @@ extern int inia100_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); extern int inia100_abort(Scsi_Cmnd *); extern int inia100_reset(Scsi_Cmnd *, unsigned int); -extern int inia100_biosparam(Scsi_Disk *, kdev_t, int *); /*for linux v2.0 */ +extern int inia100_biosparam(Scsi_Disk *, struct block_device *, int *); #define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02c" diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index be8f9cee7e88..3d22bcaf7072 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -437,7 +437,7 @@ int ips_release(struct Scsi_Host *); int ips_eh_abort(Scsi_Cmnd *); int ips_eh_reset(Scsi_Cmnd *); int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *)); -int ips_biosparam(Disk *, kdev_t, int *); +int ips_biosparam(Disk *, struct block_device *, int *); const char * ips_info(struct Scsi_Host *); void do_ipsintr(int, void *, struct pt_regs *); static int ips_hainit(ips_ha_t *); @@ -1853,7 +1853,7 @@ ips_queue(Scsi_Cmnd *SC, void (*done) (Scsi_Cmnd *)) { /* */ /****************************************************************************/ int -ips_biosparam(Disk *disk, kdev_t dev, int geom[]) { +ips_biosparam(Disk *disk, struct block_device *dev, int geom[]) { ips_ha_t *ha; int heads; int sectors; diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h index febbd953eb00..9cc112d362e6 100644 --- a/drivers/scsi/ips.h +++ b/drivers/scsi/ips.h @@ -56,7 +56,7 @@ extern int ips_eh_abort(Scsi_Cmnd *); extern int ips_eh_reset(Scsi_Cmnd *); extern int ips_queue(Scsi_Cmnd *, void (*) (Scsi_Cmnd *)); - extern int ips_biosparam(Disk *, kdev_t, int *); + extern int ips_biosparam(Disk *, struct block_device *, int *); extern const char * ips_info(struct Scsi_Host *); extern void do_ips(int, void *, struct pt_regs *); diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index ea23cc09fba7..7d2bf583126f 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -4218,13 +4218,13 @@ static void mega_create_proc_entry (int index, struct proc_dir_entry *parent) * Return the disk geometry for a particular disk * Input: * Disk *disk - Disk geometry - * kdev_t dev - Device node + * struct block_device *dev - Device node * int *geom - Returns geometry fields * geom[0] = heads * geom[1] = sectors * geom[2] = cylinders *-------------------------------------------------------------*/ -int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom) +int megaraid_biosparam (Disk * disk, struct block_device *bdev, int *geom) { int heads, sectors, cylinders; mega_host_config *megaCfg; @@ -4251,7 +4251,7 @@ int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom) geom[2] = cylinders; } else { - if( mega_partsize(disk, dev, geom) == 0 ) return 0; + if( mega_partsize(disk, bdev, geom) == 0 ) return 0; printk(KERN_WARNING "megaraid: invalid partition on this disk on channel %d\n", @@ -4279,7 +4279,7 @@ int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom) } /* - * Function : static int mega_partsize(Disk * disk, kdev_t dev, int *geom) + * Function : static int mega_partsize(Disk * disk, struct block_device *bdev, int *geom) * * Purpose : to determine the BIOS mapping used to create the partition * table, storing the results (cyls, hds, and secs) in geom @@ -4289,7 +4289,7 @@ int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom) * Returns : -1 on failure, 0 on success. */ static int -mega_partsize(Disk * disk, kdev_t dev, int *geom) +mega_partsize(Disk * disk, struct block_device *bdev, int *geom) { struct partition *p, *largest = NULL; int i, largest_cyl; @@ -4297,7 +4297,7 @@ mega_partsize(Disk * disk, kdev_t dev, int *geom) int capacity = disk->capacity; unsigned char *buf; - if (!(buf = scsi_bios_ptable(dev))) + if (!(buf = scsi_bios_ptable(bdev))) return -1; if( *(unsigned short *)(buf + 64) == 0xAA55 ) { @@ -4534,7 +4534,6 @@ static int megadev_ioctl (struct inode *inode, struct file *filep, unsigned int cmd, unsigned long arg) { int adapno; - kdev_t dev; u32 inlen; struct uioctl_t ioc; char *kvaddr = NULL; @@ -4561,8 +4560,6 @@ static int megadev_ioctl (struct inode *inode, struct file *filep, if (!inode) return -EINVAL; - dev = inode->i_rdev; - if (_IOC_TYPE (cmd) != MEGAIOC_MAGIC) return (-EINVAL); diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h index c7f011222769..746252eb44c9 100644 --- a/drivers/scsi/megaraid.h +++ b/drivers/scsi/megaraid.h @@ -950,7 +950,7 @@ int megaraid_command (Scsi_Cmnd *); int megaraid_abort (Scsi_Cmnd *); int megaraid_reset (Scsi_Cmnd *, unsigned int); int megaraid_queue (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); -int megaraid_biosparam (Disk *, kdev_t, int *); +int megaraid_biosparam (Disk *, struct block_device *, int *); int megaraid_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout); @@ -998,7 +998,7 @@ static mega_passthru* mega_prepare_passthru(mega_host_config *, mega_scb *, static mega_ext_passthru* mega_prepare_extpassthru(mega_host_config *, mega_scb *, Scsi_Cmnd *); static void mega_enum_raid_scsi(mega_host_config *); -static int mega_partsize(Disk *, kdev_t, int *); +static int mega_partsize(Disk *, struct block_device *, int *); static void mega_get_boot_ldrv(mega_host_config *); static int mega_get_lun(mega_host_config *, Scsi_Cmnd *); static int mega_support_random_del(mega_host_config *); diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c index 339287d6238e..5c347dc8edea 100644 --- a/drivers/scsi/pas16.c +++ b/drivers/scsi/pas16.c @@ -486,7 +486,7 @@ int __init pas16_detect(Scsi_Host_Template * tpnt) } /* - * Function : int pas16_biosparam(Disk *disk, kdev_t dev, int *ip) + * Function : int pas16_biosparam(Disk *disk, struct block_device *dev, int *ip) * * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for * the specified device / size. @@ -505,7 +505,7 @@ int __init pas16_detect(Scsi_Host_Template * tpnt) * and matching the H_C_S coordinates to what DOS uses. */ -int pas16_biosparam(Disk * disk, kdev_t dev, int * ip) +int pas16_biosparam(Disk * disk, struct block_device *dev, int * ip) { int size = disk->capacity; ip[0] = 64; diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h index 543a4cfc502f..e16e94bb312a 100644 --- a/drivers/scsi/pas16.h +++ b/drivers/scsi/pas16.h @@ -115,7 +115,7 @@ #ifndef ASM int pas16_abort(Scsi_Cmnd *); -int pas16_biosparam(Disk *, kdev_t, int*); +int pas16_biosparam(Disk *, struct block_device *, int*); int pas16_detect(Scsi_Host_Template *); int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int pas16_reset(Scsi_Cmnd *, unsigned int); diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c index 0e86e7362f90..1b840371057b 100644 --- a/drivers/scsi/pci2000.c +++ b/drivers/scsi/pci2000.c @@ -830,7 +830,7 @@ int Pci2000_Release (struct Scsi_Host *pshost) * Returns: zero. * ****************************************************************/ -int Pci2000_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[]) +int Pci2000_BiosParam (Scsi_Disk *disk, struct block_device *dev, int geom[]) { PADAPTER2000 padapter; diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h index fe990d4e93d0..dd5882c7091a 100644 --- a/drivers/scsi/pci2000.h +++ b/drivers/scsi/pci2000.h @@ -22,7 +22,6 @@ #define _PCI2000_H #include <linux/types.h> -#include <linux/kdev_t.h> #ifndef PSI_EIDE_SCSIOP #define PSI_EIDE_SCSIOP 1 @@ -194,7 +193,7 @@ int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); int Pci2000_Abort (Scsi_Cmnd *SCpnt); int Pci2000_Reset (Scsi_Cmnd *SCpnt, unsigned int flags); int Pci2000_Release (struct Scsi_Host *pshost); -int Pci2000_BiosParam (Disk *disk, kdev_t dev, int geom[]); +int Pci2000_BiosParam (Disk *disk, struct block_device *dev, int geom[]); #ifndef NULL #define NULL 0 diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c index 77f007e9d85a..4c0cb5f6df45 100644 --- a/drivers/scsi/pci2220i.c +++ b/drivers/scsi/pci2220i.c @@ -49,7 +49,6 @@ #include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/stat.h> -#include <linux/kdev_t.h> #include <linux/blk.h> #include <linux/timer.h> #include <linux/spinlock.h> @@ -2903,7 +2902,7 @@ int Pci2220i_Release (struct Scsi_Host *pshost) * Returns: zero. * ****************************************************************/ -int Pci2220i_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[]) +int Pci2220i_BiosParam (Scsi_Disk *disk, struct block_device *dev, int geom[]) { POUR_DEVICE pdev; diff --git a/drivers/scsi/pci2220i.h b/drivers/scsi/pci2220i.h index e7aad4d958e6..d34b3a0acea3 100644 --- a/drivers/scsi/pci2220i.h +++ b/drivers/scsi/pci2220i.h @@ -33,7 +33,7 @@ int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); int Pci2220i_Abort (Scsi_Cmnd *SCpnt); int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int flags); int Pci2220i_Release (struct Scsi_Host *pshost); -int Pci2220i_BiosParam (Disk *disk, kdev_t dev, int geom[]); +int Pci2220i_BiosParam (Disk *disk, struct block_device *dev, int geom[]); #ifndef NULL #define NULL 0 diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c index f0618cd93f6b..dd4d0544e18f 100644 --- a/drivers/scsi/ppa.c +++ b/drivers/scsi/ppa.c @@ -998,7 +998,7 @@ int ppa_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) * be done in sd.c. Even if it gets fixed there, this will still * work. */ -int ppa_biosparam(Disk * disk, kdev_t dev, int ip[]) +int ppa_biosparam(Disk * disk, struct block_device *dev, int ip[]) { ip[0] = 0x40; ip[1] = 0x20; diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h index 7479092b906e..b789f94734b6 100644 --- a/drivers/scsi/ppa.h +++ b/drivers/scsi/ppa.h @@ -170,7 +170,7 @@ int ppa_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int ppa_abort(Scsi_Cmnd *); int ppa_reset(Scsi_Cmnd *); int ppa_proc_info(char *, char **, off_t, int, int, int); -int ppa_biosparam(Disk *, kdev_t, int *); +int ppa_biosparam(Disk *, struct block_device *, int *); #define PPA { proc_name: "ppa", \ proc_info: ppa_proc_info, \ diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c index 8ea40aab26cc..cfb7f3f7ae5e 100644 --- a/drivers/scsi/psi240i.c +++ b/drivers/scsi/psi240i.c @@ -703,7 +703,7 @@ int Psi240i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags) * Returns: zero. * ****************************************************************/ -int Psi240i_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[]) +int Psi240i_BiosParam (Scsi_Disk *disk, struct block_device *dev, int geom[]) { POUR_DEVICE pdev; diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h index d41a5298a805..904c3870b3b9 100644 --- a/drivers/scsi/psi240i.h +++ b/drivers/scsi/psi240i.h @@ -28,7 +28,6 @@ #define _PSI240I_H #include <linux/types.h> -#include <linux/kdev_t.h> #ifndef PSI_EIDE_SCSIOP #define PSI_EIDE_SCSIOP 1 @@ -315,7 +314,7 @@ int Psi240i_Command (Scsi_Cmnd *SCpnt); int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)); int Psi240i_Abort (Scsi_Cmnd *SCpnt); int Psi240i_Reset (Scsi_Cmnd *SCpnt, unsigned int flags); -int Psi240i_BiosParam (Disk *disk, kdev_t dev, int geom[]); +int Psi240i_BiosParam (Disk *disk, struct block_device * dev, int geom[]); #ifndef NULL #define NULL 0 diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 9debb242fe73..7930540f1bb6 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1699,7 +1699,7 @@ qla1280_reset(Scsi_Cmnd * cmd, unsigned int flags) * Return the disk geometry for the given SCSI device. **************************************************************************/ int -qla1280_biosparam(Disk * disk, kdev_t dev, int geom[]) +qla1280_biosparam(Disk * disk, struct block_device *dev, int geom[]) { int heads, sectors, cylinders; diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index 76b60c6e3d73..b8b90c170ee2 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -1313,7 +1313,7 @@ int qla1280_release(struct Scsi_Host *); int qla1280_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int qla1280_abort(Scsi_Cmnd *); int qla1280_reset(Scsi_Cmnd *, unsigned int); -int qla1280_biosparam(Disk *, kdev_t, int[]); +int qla1280_biosparam(Disk *, struct block_device *, int[]); void qla1280_intr_handler(int, void *, struct pt_regs *); void qla1280_setup(char *s, int *dummy); diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c index 6fdb00edcfac..dc589a0a5f32 100644 --- a/drivers/scsi/qlogicfas.c +++ b/drivers/scsi/qlogicfas.c @@ -651,7 +651,7 @@ host->proc_name = "qlogicfas"; /*----------------------------------------------------------------*/ /* return bios parameters */ -int qlogicfas_biosparam(Disk * disk, kdev_t dev, int ip[]) +int qlogicfas_biosparam(Disk * disk, struct block_device *dev, int ip[]) { /* This should mimic the DOS Qlogic driver's behavior exactly */ ip[0] = 0x40; diff --git a/drivers/scsi/qlogicfas.h b/drivers/scsi/qlogicfas.h index 78129c4d0769..cca31ef3df58 100644 --- a/drivers/scsi/qlogicfas.h +++ b/drivers/scsi/qlogicfas.h @@ -7,7 +7,7 @@ int qlogicfas_command(Scsi_Cmnd *); int qlogicfas_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); int qlogicfas_abort(Scsi_Cmnd *); int qlogicfas_reset(Scsi_Cmnd *, unsigned int); -int qlogicfas_biosparam(Disk *, kdev_t, int[]); +int qlogicfas_biosparam(Disk *, struct block_device *, int[]); #ifndef NULL #define NULL (0) diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c index 32627b9e3c05..6ae15e45a619 100644 --- a/drivers/scsi/qlogicfc.c +++ b/drivers/scsi/qlogicfc.c @@ -1800,7 +1800,7 @@ int isp2x00_reset(Scsi_Cmnd * Cmnd, unsigned int reset_flags) } -int isp2x00_biosparam(Disk * disk, kdev_t n, int ip[]) +int isp2x00_biosparam(Disk * disk, struct block_device *n, int ip[]) { int size = disk->capacity; diff --git a/drivers/scsi/qlogicfc.h b/drivers/scsi/qlogicfc.h index d8831ccb2328..e67e9f5af274 100644 --- a/drivers/scsi/qlogicfc.h +++ b/drivers/scsi/qlogicfc.h @@ -75,7 +75,7 @@ const char * isp2x00_info(struct Scsi_Host *); int isp2x00_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); int isp2x00_abort(Scsi_Cmnd *); int isp2x00_reset(Scsi_Cmnd *, unsigned int); -int isp2x00_biosparam(Disk *, kdev_t, int[]); +int isp2x00_biosparam(Disk *, struct block_device *, int[]); #ifndef NULL #define NULL (0) diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c index edfa513d9614..446c1c9308f7 100644 --- a/drivers/scsi/qlogicisp.c +++ b/drivers/scsi/qlogicisp.c @@ -84,14 +84,11 @@ struct { { \ unsigned long flags; \ \ - save_flags(flags); \ - cli(); \ trace.buf[trace.next].name = (w); \ trace.buf[trace.next].time = jiffies; \ trace.buf[trace.next].index = (i); \ trace.buf[trace.next].addr = (long) (a); \ trace.next = (trace.next + 1) & (TRACE_BUF_LEN - 1); \ - restore_flags(flags); \ } #else @@ -1240,7 +1237,7 @@ int isp1020_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags) } -int isp1020_biosparam(Disk *disk, kdev_t n, int ip[]) +int isp1020_biosparam(Disk *disk, struct block_device *n, int ip[]) { int size = disk->capacity; @@ -1704,9 +1701,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host) ENTER("isp1020_load_parameters"); - save_flags(flags); - cli(); - hwrev = isp_inw(host, ISP_CFG0) & ISP_CFG0_HWMSK; isp_cfg1 = ISP_CFG1_F64 | ISP_CFG1_BENAB; if (hwrev == ISP_CFG0_1040A) { @@ -1724,7 +1718,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host) isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); printk("qlogicisp : set initiator id failure\n"); return 1; } @@ -1736,7 +1729,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host) isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); printk("qlogicisp : set retry count failure\n"); return 1; } @@ -1747,7 +1739,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host) isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); printk("qlogicisp : async data setup time failure\n"); return 1; } @@ -1759,7 +1750,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host) isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); printk("qlogicisp : set active negation state failure\n"); return 1; } @@ -1771,7 +1761,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host) isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); printk("qlogicisp : set pci control parameter failure\n"); return 1; } @@ -1782,7 +1771,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host) isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); printk("qlogicisp : set tag age limit failure\n"); return 1; } @@ -1793,7 +1781,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host) isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); printk("qlogicisp : set selection timeout failure\n"); return 1; } @@ -1812,7 +1799,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host) isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); printk("qlogicisp : set target parameter failure\n"); return 1; } @@ -1827,7 +1813,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host) isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); printk("qlogicisp : set device queue " "parameter failure\n"); return 1; @@ -1854,7 +1839,6 @@ static int isp1020_load_parameters(struct Scsi_Host *host) isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); printk("qlogicisp : set response queue failure\n"); return 1; } @@ -1879,13 +1863,10 @@ static int isp1020_load_parameters(struct Scsi_Host *host) isp1020_mbox_command(host, param); if (param[0] != MBOX_COMMAND_COMPLETE) { - restore_flags(flags); printk("qlogicisp : set request queue failure\n"); return 1; } - restore_flags(flags); - LEAVE("isp1020_load_parameters"); return 0; diff --git a/drivers/scsi/qlogicisp.h b/drivers/scsi/qlogicisp.h index 85940ed2f6ae..724d807dfd72 100644 --- a/drivers/scsi/qlogicisp.h +++ b/drivers/scsi/qlogicisp.h @@ -64,7 +64,7 @@ const char * isp1020_info(struct Scsi_Host *); int isp1020_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); int isp1020_abort(Scsi_Cmnd *); int isp1020_reset(Scsi_Cmnd *, unsigned int); -int isp1020_biosparam(Disk *, kdev_t, int[]); +int isp1020_biosparam(Disk *, struct block_device *, int[]); #ifndef NULL #define NULL (0) diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 7943596690d2..39416bd52295 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1456,7 +1456,7 @@ static void qpti_intr(int irq, void *dev_id, struct pt_regs *regs) } while (dq != NULL); spin_unlock(qpti->qhost->host_lock); } - __restore_flags(flags); + local_irq_restore(flags); } int qlogicpti_abort(Scsi_Cmnd *Cmnd) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 058688349f5d..4f7ae5c4fc34 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1008,7 +1008,7 @@ static int scsi_debug_abort(Scsi_Cmnd * SCpnt) #endif } -static int scsi_debug_biosparam(Disk * disk, kdev_t dev, int *info) +static int scsi_debug_biosparam(Disk * disk, struct block_device *dev, int *info) { if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: biosparam\n"); diff --git a/drivers/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h index d1eb11c93fd6..92290b6158d5 100644 --- a/drivers/scsi/scsi_debug.h +++ b/drivers/scsi/scsi_debug.h @@ -1,13 +1,12 @@ #ifndef _SCSI_DEBUG_H #include <linux/types.h> -#include <linux/kdev_t.h> static int scsi_debug_detect(Scsi_Host_Template *); /* static int scsi_debug_command(Scsi_Cmnd *); */ static int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); static int scsi_debug_abort(Scsi_Cmnd *); -static int scsi_debug_biosparam(Disk *, kdev_t, int[]); +static int scsi_debug_biosparam(Disk *, struct block_device *, int[]); static int scsi_debug_bus_reset(Scsi_Cmnd *); static int scsi_debug_device_reset(Scsi_Cmnd *); static int scsi_debug_host_reset(Scsi_Cmnd *); diff --git a/drivers/scsi/scsi_mid_low_api.txt b/drivers/scsi/scsi_mid_low_api.txt index 8af86db6d3f2..fbde06519c97 100644 --- a/drivers/scsi/scsi_mid_low_api.txt +++ b/drivers/scsi/scsi_mid_low_api.txt @@ -85,7 +85,7 @@ The interface functions are listed below in alphabetical order. * pre-initialized with made up values just in case this function * doesn't output anything. **/ - int bios_param(Scsi_Disk * sdkp, kdev_t dev, int params[3]); + int bios_param(Scsi_Disk * sdkp, struct block_device *bdev, int params[3]); /** diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c index 7559b235eba3..db6ca281c59e 100644 --- a/drivers/scsi/scsicam.c +++ b/drivers/scsi/scsicam.c @@ -26,39 +26,25 @@ static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs); -unsigned char *scsi_bios_ptable(kdev_t dev) +unsigned char *scsi_bios_ptable(struct block_device *dev) { - struct block_device *bdev; unsigned char *res = kmalloc(66, GFP_KERNEL); - kdev_t rdev = mk_kdev(major(dev), minor(dev) & ~0x0f); - if (res) { - struct buffer_head *bh; - int err; - - bdev = bdget(kdev_t_to_nr(rdev)); - if (!bdev) - goto fail; - err = blkdev_get(bdev, FMODE_READ, 0, BDEV_FILE); - if (err) - goto fail; - bh = __bread(bdev, 0, block_size(bdev)); - if (!bh) - goto fail2; - memcpy(res, bh->b_data + 0x1be, 66); - brelse(bh); - blkdev_put(bdev, BDEV_FILE); + struct block_device *bdev = dev->bd_contains; + struct buffer_head *bh = __bread(bdev, 0, block_size(bdev)); + if (bh) { + memcpy(res, bh->b_data + 0x1be, 66); + brelse(bh); + } else { + kfree(res); + res = NULL; + } } return res; -fail2: - blkdev_put(bdev, BDEV_FILE); -fail: - kfree(res); - return NULL; } /* - * Function : int scsicam_bios_param (Disk *disk, int dev, int *ip) + * Function : int scsicam_bios_param (Disk *disk, struct block_device *bdev, int *ip) * * Purpose : to determine the BIOS mapping used for a drive in a * SCSI-CAM system, storing the results in ip as required @@ -69,13 +55,13 @@ fail: */ int scsicam_bios_param(Disk * disk, /* SCSI disk */ - kdev_t dev, /* Device major, minor */ + struct block_device *bdev, int *ip /* Heads, sectors, cylinders in that order */ ) { int ret_code; int size = disk->capacity; unsigned long temp_cyl; - unsigned char *p = scsi_bios_ptable(dev); + unsigned char *p = scsi_bios_ptable(bdev); if (!p) return -1; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index fd92ed1924f1..f6dd5107974d 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -233,33 +233,20 @@ static int sd_ioctl(struct inode * inode, struct file * filp, or driver values */ if(host->hostt->bios_param != NULL) - host->hostt->bios_param(sdkp, dev, + host->hostt->bios_param(sdkp, inode->i_bdev, &diskinfo[0]); else - scsicam_bios_param(sdkp, dev, &diskinfo[0]); + scsicam_bios_param(sdkp, inode->i_bdev, &diskinfo[0]); if (put_user(diskinfo[0], &loc->heads) || put_user(diskinfo[1], &loc->sectors) || put_user(diskinfo[2], &loc->cylinders) || put_user((unsigned) - get_start_sect(inode->i_rdev), + get_start_sect(inode->i_bdev), (unsigned long *) &loc->start)) return -EFAULT; return 0; } - case BLKGETSIZE: - case BLKGETSIZE64: - case BLKROSET: - case BLKROGET: - case BLKFLSBUF: - case BLKSSZGET: - case BLKPG: - case BLKELVGET: - case BLKELVSET: - case BLKBSZGET: - case BLKBSZSET: - return blk_ioctl(inode->i_bdev, cmd, arg); - case BLKRRPART: /* Re-read partition tables */ if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -507,16 +494,6 @@ static int sd_open(struct inode *inode, struct file *filp) if (!scsi_block_when_processing_errors(sdp)) return -ENXIO; /* - * Make sure that only one process can do a check_change_disk at - * one time. This is also used to lock out further access when - * the partition table is being re-read. - */ - - while (sdp->busy) { - barrier(); - cpu_relax(); - } - /* * The following code can sleep. * Module unloading must be prevented */ @@ -527,9 +504,7 @@ static int sd_open(struct inode *inode, struct file *filp) sdp->access_count++; if (sdp->removable) { - sdp->allow_revalidate = 1; check_disk_change(inode->i_rdev); - sdp->allow_revalidate = 0; /* * If the drive is empty, just let the open fail. @@ -1464,9 +1439,10 @@ static int sd_attach(Scsi_Device * sdp) int revalidate_scsidisk(kdev_t dev, int maxusage) { int dsk_nr = DEVICE_NR(dev); - int res; Scsi_Disk * sdkp; Scsi_Device * sdp; + kdev_t device = mk_kdev(major(dev), minor(dev) & ~15); + int res; SCSI_LOG_HLQUEUE(3, printk("revalidate_scsidisk: dsk_nr=%d\n", DEVICE_NR(dev))); @@ -1474,24 +1450,20 @@ int revalidate_scsidisk(kdev_t dev, int maxusage) if ((NULL == sdkp) || (NULL == (sdp = sdkp->device))) return -ENODEV; - if (sdp->busy || ((sdp->allow_revalidate == 0) && - (sdp->access_count > maxusage))) { - printk(KERN_WARNING "Device busy for revalidation " - "(access_count=%d)\n", sdp->access_count); - return -EBUSY; - } - sdp->busy = 1; + res = dev_lock_part(device); + if (res < 0) + return res; - res = wipe_partitions(dev); + res = wipe_partitions(device); if (res) goto leave; sd_init_onedisk(sdkp, dsk_nr); - grok_partitions(dev, sdkp->capacity); + grok_partitions(device, sdkp->capacity); leave: - sdp->busy = 0; + dev_unlock_part(device); return res; } diff --git a/drivers/scsi/sim710.h b/drivers/scsi/sim710.h index 2fd837fea8a2..7cd2ff5558d7 100644 --- a/drivers/scsi/sim710.h +++ b/drivers/scsi/sim710.h @@ -14,7 +14,7 @@ int sim710_abort(Scsi_Cmnd * SCpnt); int sim710_bus_reset(Scsi_Cmnd * SCpnt); int sim710_dev_reset(Scsi_Cmnd * SCpnt); int sim710_host_reset(Scsi_Cmnd * SCpnt); -int sim710_biosparam(Disk *, kdev_t, int*); +int sim710_biosparam(Disk *, struct block_device *, int*); #ifdef MODULE int sim710_release(struct Scsi_Host *); #else diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c index 2ad532933c49..e32c05b5ddc4 100644 --- a/drivers/scsi/sym53c416.c +++ b/drivers/scsi/sym53c416.c @@ -828,7 +828,7 @@ static int sym53c416_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) return SCSI_RESET_PENDING; } -static int sym53c416_bios_param(Disk *disk, kdev_t dev, int *ip) +static int sym53c416_bios_param(Disk *disk, struct block_device *dev, int *ip) { int size; diff --git a/drivers/scsi/sym53c416.h b/drivers/scsi/sym53c416.h index 8124b1c78d28..0ecf3917626a 100644 --- a/drivers/scsi/sym53c416.h +++ b/drivers/scsi/sym53c416.h @@ -27,7 +27,6 @@ #endif #include <linux/types.h> -#include <linux/kdev_t.h> #define SYM53C416_SCSI_ID 7 @@ -37,7 +36,7 @@ static int sym53c416_command(Scsi_Cmnd *); static int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); static int sym53c416_abort(Scsi_Cmnd *); static int sym53c416_reset(Scsi_Cmnd *, unsigned int); -static int sym53c416_bios_param(Disk *, kdev_t, int *); +static int sym53c416_bios_param(Disk *, struct block_device *, int *); static void sym53c416_setup(char *str, int *ints); #define SYM53C416 { \ diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c index a803b1ab9474..4bd494a01a1c 100644 --- a/drivers/scsi/t128.c +++ b/drivers/scsi/t128.c @@ -279,7 +279,7 @@ int __init t128_detect(Scsi_Host_Template * tpnt){ } /* - * Function : int t128_biosparam(Disk * disk, kdev_t dev, int *ip) + * Function : int t128_biosparam(Disk * disk, struct block_device *dev, int *ip) * * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for * the specified device / size. @@ -298,7 +298,7 @@ int __init t128_detect(Scsi_Host_Template * tpnt){ * and matching the H_C_S coordinates to what DOS uses. */ -int t128_biosparam(Disk * disk, kdev_t dev, int * ip) +int t128_biosparam(Disk * disk, struct block_device *dev, int * ip) { int size = disk->capacity; ip[0] = 64; diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h index f315160773ef..e07449e524ab 100644 --- a/drivers/scsi/t128.h +++ b/drivers/scsi/t128.h @@ -92,7 +92,7 @@ #ifndef ASM int t128_abort(Scsi_Cmnd *); -int t128_biosparam(Disk *, kdev_t, int*); +int t128_biosparam(Disk *, struct block_device *, int*); int t128_detect(Scsi_Host_Template *); int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int t128_reset(Scsi_Cmnd *, unsigned int reset_flags); diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c index dac2c059d02b..e9bd6a72ffbc 100644 --- a/drivers/scsi/tmscsim.c +++ b/drivers/scsi/tmscsim.c @@ -1439,7 +1439,7 @@ static int partsize(unsigned char *buf, unsigned long capacity, * Note: * In contrary to other externally callable funcs (DC390_), we don't lock ***********************************************************************/ -int DC390_bios_param (Disk *disk, kdev_t devno, int geom[]) +int DC390_bios_param (Disk *disk, struct block_device *bdev, int geom[]) { int heads, sectors, cylinders; PACB pACB = (PACB) disk->device->host->hostdata; @@ -1447,7 +1447,7 @@ int DC390_bios_param (Disk *disk, kdev_t devno, int geom[]) int size = disk->capacity; unsigned char *buf; - if ((buf = scsi_bios_ptable(devno))) + if ((buf = scsi_bios_ptable(bdev))) { /* try to infer mapping from partition table */ ret_code = partsize (buf, (unsigned long) size, (unsigned int *) geom + 2, @@ -1475,9 +1475,9 @@ int DC390_bios_param (Disk *disk, kdev_t devno, int geom[]) return (0); } #else -int DC390_bios_param (Disk *disk, kdev_t devno, int geom[]) +int DC390_bios_param (Disk *disk, struct block_device *bdev, int geom[]) { - return scsicam_bios_param (disk, devno, geom); + return scsicam_bios_param (disk, bdev, geom); }; #endif @@ -2525,8 +2525,8 @@ else if (!p1) goto ok2 if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, "")) goto einv2; \ else if (!p1) goto ok2 -#define SEARCH3(buffer, pos, &p0, var, txt, max, scale, ign) \ -if (dc390_search (&buffer, &pos, p0, &var, txt, max, scale, ign)) goto einv2; \ +#define SEARCH3(buffer, pos, p0, var, txt, max, scale, ign) \ +if (dc390_search (&buffer, &pos, &p0, &var, txt, max, scale, ign)) goto einv2; \ else if (!p1) goto ok2 diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c index 6de097b8368b..993109521385 100644 --- a/drivers/scsi/u14-34f.c +++ b/drivers/scsi/u14-34f.c @@ -1452,7 +1452,7 @@ int u14_34f_reset(Scsi_Cmnd *SCarg) { return do_reset(SCarg); } -int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) { +int u14_34f_biosparam(Disk *disk, struct block_device *bdev, int *dkinfo) { unsigned int j = 0; int size = disk->capacity; @@ -1460,7 +1460,7 @@ int u14_34f_biosparam(Disk *disk, kdev_t dev, int *dkinfo) { dkinfo[1] = HD(j)->sectors; dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors); - if (ext_tran && (scsicam_bios_param(disk, dev, dkinfo) < 0)) { + if (ext_tran && (scsicam_bios_param(disk, bdev, dkinfo) < 0)) { dkinfo[0] = 255; dkinfo[1] = 63; dkinfo[2] = size / (dkinfo[0] * dkinfo[1]); diff --git a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h index c5dfe2d80f55..fe8fe7830a1a 100644 --- a/drivers/scsi/u14-34f.h +++ b/drivers/scsi/u14-34f.h @@ -11,7 +11,7 @@ int u14_34f_release(struct Scsi_Host *); int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int u14_34f_abort(Scsi_Cmnd *); int u14_34f_reset(Scsi_Cmnd *); -int u14_34f_biosparam(Disk *, kdev_t, int *); +int u14_34f_biosparam(Disk *, struct block_device *, int *); #define U14_34F_VERSION "7.22.00" diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c index 1a042201b07a..1876d52a86ab 100644 --- a/drivers/scsi/ultrastor.c +++ b/drivers/scsi/ultrastor.c @@ -1020,7 +1020,7 @@ int ultrastor_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags) } -int ultrastor_biosparam(Disk * disk, kdev_t dev, int * dkinfo) +int ultrastor_biosparam(Disk * disk, struct block_device *dev, int * dkinfo) { int size = disk->capacity; unsigned int s = config.heads * config.sectors; diff --git a/drivers/scsi/ultrastor.h b/drivers/scsi/ultrastor.h index ffe57ec18b80..4dcb9def40fd 100644 --- a/drivers/scsi/ultrastor.h +++ b/drivers/scsi/ultrastor.h @@ -12,14 +12,13 @@ #ifndef _ULTRASTOR_H #define _ULTRASTOR_H -#include <linux/kdev_t.h> int ultrastor_detect(Scsi_Host_Template *); const char *ultrastor_info(struct Scsi_Host * shpnt); int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int ultrastor_abort(Scsi_Cmnd *); int ultrastor_reset(Scsi_Cmnd *, unsigned int); -int ultrastor_biosparam(Disk *, kdev_t, int *); +int ultrastor_biosparam(Disk *, struct block_device *, int *); #define ULTRASTOR_14F_MAX_SG 16 diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c index 3e1bafa68cb1..97c891fb9f03 100644 --- a/drivers/scsi/wd7000.c +++ b/drivers/scsi/wd7000.c @@ -1706,9 +1706,9 @@ int wd7000_reset (Scsi_Cmnd *SCpnt, unsigned int unused) /* * This was borrowed directly from aha1542.c. (Zaga) */ -int wd7000_biosparam (Disk *disk, kdev_t dev, int *ip) +int wd7000_biosparam (Disk *disk, struct block_device *bdev, int *ip) { - dprintk("wd7000_biosparam: dev=%s, size=%d, ", kdevname(dev), + dprintk("wd7000_biosparam: dev=%s, size=%d, ", bdevname(bdev), disk->capacity); /* @@ -1727,7 +1727,7 @@ int wd7000_biosparam (Disk *disk, kdev_t dev, int *ip) /* * try to figure out the geometry from the partition table */ - if ((scsicam_bios_param (disk, dev, info) < 0) || + if ((scsicam_bios_param (disk, bdev, info) < 0) || !(((info[0] == 64) && (info[1] == 32)) || ((info[0] == 255) && (info[1] == 63)))) { printk ("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n" diff --git a/drivers/scsi/wd7000.h b/drivers/scsi/wd7000.h index c90e07f787f0..a9570edcffce 100644 --- a/drivers/scsi/wd7000.h +++ b/drivers/scsi/wd7000.h @@ -12,7 +12,6 @@ */ #include <linux/types.h> -#include <linux/kdev_t.h> int wd7000_set_info (char *buffer, int length, struct Scsi_Host *host); int wd7000_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout); @@ -21,7 +20,7 @@ int wd7000_command (Scsi_Cmnd *); int wd7000_queuecommand (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int wd7000_abort (Scsi_Cmnd *); int wd7000_reset (Scsi_Cmnd *, unsigned int); -int wd7000_biosparam (Disk *, kdev_t, int *); +int wd7000_biosparam (Disk *, struct block_device *, int *); #ifndef NULL #define NULL 0L diff --git a/drivers/serial/Config.help b/drivers/serial/Config.help new file mode 100644 index 000000000000..c9f938fbb513 --- /dev/null +++ b/drivers/serial/Config.help @@ -0,0 +1,225 @@ +# $Id: Config.help,v 1.5 2002/07/06 17:16:24 rmk Exp $ + +CONFIG_SERIAL_8250 + This selects whether you want to include the driver for the standard + serial ports. The standard answer is Y. People who might say N + here are those that are setting up dedicated Ethernet WWW/FTP + servers, or users that have one of the various bus mice instead of a + serial mouse and don't intend to use their machine's standard serial + port for anything. (Note that the Cyclades and Stallion multi + serial port drivers do not need this driver built in for them to + work.) + + If you want to compile this driver as a module, say M here and read + <file:Documentation/modules.txt>. The module will be called + serial.o. + [WARNING: Do not compile this driver as a module if you are using + non-standard serial ports, since the configuration information will + be lost when the driver is unloaded. This limitation may be lifted + in the future.] + + BTW1: If you have a mouseman serial mouse which is not recognized by + the X window system, try running gpm first. + + BTW2: If you intend to use a software modem (also called Winmodem) + under Linux, forget it. These modems are crippled and require + proprietary drivers which are only available under Windows. + + Most people will say Y or M here, so that they can use serial mice, + modems and similar devices connecting to the standard serial ports. + +CONFIG_SERIAL_8250_CONSOLE + If you say Y here, it will be possible to use a serial port as the + system console (the system console is the device which receives all + kernel messages and warnings and which allows logins in single user + mode). This could be useful if some terminal or printer is connected + to that serial port. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyS1". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + + If you don't have a VGA card installed and you say Y here, the + kernel will automatically use the first serial line, /dev/ttyS0, as + system console. + + If unsure, say N. + +CONFIG_SERIAL_8250_CS + Say Y here to enable support for 16-bit PCMCIA serial devices, + including serial port cards, modems, and the modem functions of + multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are + credit-card size devices often used with laptops.) + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called serial_cs.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + If unsure, say N. + +CONFIG_SERIAL_8250_EXTENDED + If you wish to use any non-standard features of the standard "dumb" + driver, say Y here. This includes HUB6 support, shared serial + interrupts, special multiport support, support for more than the + four COM 1/2/3/4 boards, etc. + + Note that the answer to this question won't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about serial driver options. If unsure, say N. + +CONFIG_SERIAL_8250_MANY_PORTS + Say Y here if you have dumb serial boards other than the four + standard COM 1/2/3/4 ports. This may happen if you have an AST + FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available + from <http://www.linuxdoc.org/docs.html#howto>), or other custom + serial port hardware which acts similar to standard serial port + hardware. If you only use the standard COM 1/2/3/4 ports, you can + say N here to save some memory. You can also say Y if you have an + "intelligent" multiport card such as Cyclades, Digiboards, etc. + +CONFIG_SERIAL_8250_SHARE_IRQ + Some serial boards have hardware support which allows multiple dumb + serial ports on the same board to share a single IRQ. To enable + support for this in the serial driver, say Y here. + +CONFIG_SERIAL_8250_DETECT_IRQ + Say Y here if you want the kernel to try to guess which IRQ + to use for your serial port. + + This is considered unsafe; it is far better to configure the IRQ in + a boot script using the setserial command. + + If unsure, say N. + +CONFIG_SERIAL_8250_MULTIPORT + Some multiport serial ports have special ports which are used to + signal when there are any serial ports on the board which need + servicing. Say Y here to enable the serial driver to take advantage + of those special I/O ports. + +CONFIG_SERIAL_8250_RSA + ::: To be written ::: + +CONFIG_ATOMWIDE_SERIAL + If you have an Atomwide Serial card for an Acorn system, say Y to + this option. The driver can handle 1, 2, or 3 port cards. + If unsure, say N. + +CONFIG_DUALSP_SERIAL + If you have the Serial Port's dual serial card for an Acorn system, + say Y to this option. If unsure, say N. + +CONFIG_SERIAL_ANAKIN + ::: To be written ::: +CONFIG_SERIAL_ANAKIN_CONSOLE + ::: To be written ::: + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyAN0". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +CONFIG_ANAKIN_DEFAULT_BAUDRATE + ::: To be written ::: + +CONFIG_SERIAL_AMBA + This selects the ARM(R) AMBA(R) PrimeCell UART. If you have an + Integrator platform, say Y or M here. + + If unsure, say N. + +CONFIG_SERIAL_AMBA_CONSOLE + Say Y here if you wish to use an AMBA PrimeCell UART as the system + console (the system console is the device which receives all kernel + messages and warnings and which allows logins in single user mode). + + Even if you say Y here, the currently visible framebuffer console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyAM0". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +CONFIG_SERIAL_CLPS711X + ::: To be written ::: + +CONFIG_SERIAL_CLPS711X_CONSOLE + ::: To be written ::: + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyCL1". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +CONFIG_SERIAL_CLPS711X_OLD_NAME + ::: To be written ::: + +CONFIG_SERIAL_21285 + If you have a machine based on a 21285 (Footbridge) StrongARM(R)/ + PCI bridge you can enable its onboard serial port by enabling this + option. + +CONFIG_SERIAL_21285_OLD + Use the old /dev/ttyS name, major 4 minor 64. This is obsolete + and will be removed during later 2.5 development. + +CONFIG_SERIAL_21285_CONSOLE + If you have enabled the serial port on the 21285 footbridge you can + make it the console by answering Y to this option. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyFB". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +CONFIG_SERIAL_UART00 + Say Y here if you want to use the hard logic uart on Excalibur. This + driver also supports soft logic implentations of this uart core. + +CONFIG_SERIAL_UART00_CONSOLE + Say Y here if you want to support a serial console on an Excalibur + hard logic uart or uart00 IP core. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttyS1". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +CONFIG_SERIAL_SA1100 + If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you + can enable its onboard serial port by enabling this option. + Please read <file:Documentation/arm/SA1100/serial_UART> for further + info. + +CONFIG_SERIAL_SA1100_CONSOLE + If you have enabled the serial port on the SA1100/SA1110 StrongARM + CPU you can make it the console by answering Y to this option. + + Even if you say Y here, the currently visible virtual console + (/dev/tty0) will still be used as the system console by default, but + you can alter that using a kernel command line option such as + "console=ttySA0". (Try "man bootparam" or see the documentation of + your boot loader (lilo or loadlin) about how to pass options to the + kernel at boot time.) + +#CONFIG_SERIAL_L7200 +# If you have a LinkUp Systems L7200 board you can enable its two +# onboard serial ports by enabling this option. The device numbers +# are major ID 4 with minor 64 and 65 respectively. +# +#CONFIG_SERIAL_L7200_CONSOLE +# If you have enabled the serial ports on the L7200 development board +# you can make the first serial port the console by answering Y to +# this option. + diff --git a/drivers/serial/Config.in b/drivers/serial/Config.in new file mode 100644 index 000000000000..7783775e9420 --- /dev/null +++ b/drivers/serial/Config.in @@ -0,0 +1,77 @@ +# +# Serial device configuration +# +# $Id: Config.in,v 1.15 2002/07/06 17:16:24 rmk Exp $ +# +mainmenu_option next_comment +comment 'Serial drivers' + +# +# The new 8250/16550 serial drivers +dep_tristate '8250/16550 and compatible serial support (EXPERIMENTAL)' CONFIG_SERIAL_8250 $CONFIG_EXPERIMENTAL +dep_bool ' Console on 8250/16550 and compatible serial port (EXPERIMENTAL)' CONFIG_SERIAL_8250_CONSOLE $CONFIG_SERIAL_8250 $CONFIG_EXPERIMENTAL +dep_tristate ' 8250/16550 PCMCIA device support' CONFIG_SERIAL_8250_CS $CONFIG_PCMCIA $CONFIG_SERIAL_8250 + +dep_mbool 'Extended 8250/16550 serial driver options' CONFIG_SERIAL_8250_EXTENDED $CONFIG_SERIAL_8250 +dep_bool ' Support more than 4 serial ports' CONFIG_SERIAL_8250_MANY_PORTS $CONFIG_SERIAL_8250_EXTENDED +dep_bool ' Support for sharing serial interrupts' CONFIG_SERIAL_8250_SHARE_IRQ $CONFIG_SERIAL_8250_EXTENDED +dep_bool ' Autodetect IRQ on standard ports (unsafe)' CONFIG_SERIAL_8250_DETECT_IRQ $CONFIG_SERIAL_8250_EXTENDED +dep_bool ' Support special multiport boards' CONFIG_SERIAL_8250_MULTIPORT $CONFIG_SERIAL_8250_EXTENDED +dep_bool ' Support RSA serial ports' CONFIG_SERIAL_8250_RSA $CONFIG_SERIAL_8250_EXTENDED + +comment 'Non-8250 serial port support' + +if [ "$CONFIG_ARM" = "y" ]; then + dep_tristate 'Acorn Atomwide 16550 serial port support' CONFIG_ATOMWIDE_SERIAL $CONFIG_ARCH_ACORN $CONFIG_SERIAL_8250 + dep_tristate 'Acorn Dual 16550 serial port support' CONFIG_DUALSP_SERIAL $CONFIG_ARCH_ACORN $CONFIG_SERIAL_8250 + dep_bool 'Anakin serial port support' CONFIG_SERIAL_ANAKIN $CONFIG_ARCH_ANAKIN + dep_bool ' Console on Anakin serial port' CONFIG_SERIAL_ANAKIN_CONSOLE $CONFIG_SERIAL_ANAKIN + if [ "$CONFIG_SERIAL_ANAKIN" = "y" ]; then + int ' Default Anakin serial baudrate' CONFIG_ANAKIN_DEFAULT_BAUDRATE 9600 + fi + + dep_tristate 'ARM AMBA serial port support' CONFIG_SERIAL_AMBA $CONFIG_ARCH_INTEGRATOR + dep_bool ' Support for console on AMBA serial port' CONFIG_SERIAL_AMBA_CONSOLE $CONFIG_SERIAL_AMBA + if [ "$CONFIG_SERIAL_AMBA" = "y" ]; then + define_bool CONFIG_SERIAL_INTEGRATOR y + fi + + dep_tristate 'CLPS711X serial port support' CONFIG_SERIAL_CLPS711X $CONFIG_ARCH_CLPS711X + dep_bool ' Support for console on CLPS711X serial port' CONFIG_SERIAL_CLPS711X_CONSOLE $CONFIG_SERIAL_CLPS711X + dep_bool ' Use the old 2.4 names for CLPS711X serial port' CONFIG_SERIAL_CLPS711X_OLD_NAME $CONFIG_SERIAL_CLPS711X + + dep_tristate 'DC21285 serial port support' CONFIG_SERIAL_21285 $CONFIG_FOOTBRIDGE + dep_bool ' Use /dev/ttyS0 device (OBSOLETE)' CONFIG_SERIAL_21285_OLD $CONFIG_SERIAL_21285 $CONFIG_OBSOLETE + dep_bool ' Console on DC21285 serial port' CONFIG_SERIAL_21285_CONSOLE $CONFIG_SERIAL_21285 + + dep_bool 'Excalibur serial port (uart00) support' CONFIG_SERIAL_UART00 $CONFIG_ARCH_CAMELOT + dep_bool ' Support for console on Excalibur serial port' CONFIG_SERIAL_UART00_CONSOLE $CONFIG_SERIAL_UART00 + + dep_bool 'SA1100 serial port support' CONFIG_SERIAL_SA1100 $CONFIG_ARCH_SA1100 + dep_bool ' Console on SA1100 serial port' CONFIG_SERIAL_SA1100_CONSOLE $CONFIG_SERIAL_SA1100 +fi + +if [ "$CONFIG_SERIAL_AMBA" = "y" -o "$CONFIG_SERIAL_CLPS711X" = "y" -o \ + "$CONFIG_SERIAL_21285" = "y" -o "$CONFIG_SERIAL_SA1100" = "y" -o \ + "$CONFIG_SERIAL_ANAKIN" = "y" -o "$CONFIG_SERIAL_UART00" = "y" -o \ + "$CONFIG_SERIAL_8250" = "y" -o "$CONFIG_SERIAL_ROCKETPORT" = "y" ]; then + define_bool CONFIG_SERIAL_CORE y +else + if [ "$CONFIG_SERIAL_AMBA" = "m" -o "$CONFIG_SERIAL_CLPS711X" = "m" -o \ + "$CONFIG_SERIAL_21285" = "m" -o "$CONFIG_SERIAL_SA1100" = "m" -o \ + "$CONFIG_SERIAL_ANAKIN" = "m" -o "$CONFIG_SERIAL_UART00" = "m" -o \ + "$CONFIG_SERIAL_8250" = "m" -o "$CONFIG_SERIAL_ROCKETPORT" = "m" ]; then + define_bool CONFIG_SERIAL_CORE m + fi +fi +if [ "$CONFIG_SERIAL_AMBA_CONSOLE" = "y" -o \ + "$CONFIG_SERIAL_CLPS711X_CONSOLE" = "y" -o \ + "$CONFIG_SERIAL_21285_CONSOLE" = "y" -o \ + "$CONFIG_SERIAL_SA1100_CONSOLE" = "y" -o \ + "$CONFIG_SERIAL_ANAKIN_CONSOLE" = "y" -o \ + "$CONFIG_SERIAL_UART00_CONSOLE" = "y" -o \ + "$CONFIG_SERIAL_8250_CONSOLE" = "y" ]; then + define_bool CONFIG_SERIAL_CORE_CONSOLE y +fi + +endmenu diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile new file mode 100644 index 000000000000..613e9d9b7cef --- /dev/null +++ b/drivers/serial/Makefile @@ -0,0 +1,22 @@ +# +# Makefile for the kernel serial device drivers. +# +# $Id: Makefile,v 1.7 2002/07/06 17:16:24 rmk Exp $ +# + +export-objs := serial_core.o serial_8250.o + +serial-8250-y := +serial-8250-$(CONFIG_PCI) += serial_8250_pci.o +serial-8250-$(CONFIG_ISAPNP) += serial_8250_pnp.o +obj-$(CONFIG_SERIAL_CORE) += serial_core.o +obj-$(CONFIG_SERIAL_21285) += serial_21285.o +obj-$(CONFIG_SERIAL_8250) += serial_8250.o $(serial-8250-y) +obj-$(CONFIG_SERIAL_8250_CS) += serial_8250_cs.o +obj-$(CONFIG_SERIAL_ANAKIN) += serial_anakin.o +obj-$(CONFIG_SERIAL_AMBA) += serial_amba.o +obj-$(CONFIG_SERIAL_CLPS711X) += serial_clps711x.o +obj-$(CONFIG_SERIAL_SA1100) += serial_sa1100.o +obj-$(CONFIG_SERIAL_UART00) += serial_uart00.o + +include $(TOPDIR)/Rules.make diff --git a/drivers/serial/serial_21285.c b/drivers/serial/serial_21285.c new file mode 100644 index 000000000000..0b63b3a7deb6 --- /dev/null +++ b/drivers/serial/serial_21285.c @@ -0,0 +1,553 @@ +/* + * linux/drivers/char/serial_21285.c + * + * Driver for the serial port on the 21285 StrongArm-110 core logic chip. + * + * Based on drivers/char/serial.c + * + * $Id: serial_21285.c,v 1.32 2002/07/21 08:57:55 rmk Exp $ + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/serial.h> +#include <linux/major.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/console.h> +#include <linux/serial_core.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/hardware/dec21285.h> +#include <asm/hardware.h> + +#define BAUD_BASE (mem_fclk_21285/64) + +#define SERIAL_21285_NAME "ttyFB" +#define SERIAL_21285_MAJOR 204 +#define SERIAL_21285_MINOR 4 + +#define RXSTAT_DUMMY_READ 0x80000000 +#define RXSTAT_FRAME (1 << 0) +#define RXSTAT_PARITY (1 << 1) +#define RXSTAT_OVERRUN (1 << 2) +#define RXSTAT_ANYERR (RXSTAT_FRAME|RXSTAT_PARITY|RXSTAT_OVERRUN) + +#define H_UBRLCR_BREAK (1 << 0) +#define H_UBRLCR_PARENB (1 << 1) +#define H_UBRLCR_PAREVN (1 << 2) +#define H_UBRLCR_STOPB (1 << 3) +#define H_UBRLCR_FIFO (1 << 4) + +static const char serial21285_name[] = "Footbridge UART"; + +#define tx_enabled(port) ((port)->unused[0]) +#define rx_enabled(port) ((port)->unused[1]) + +/* + * The documented expression for selecting the divisor is: + * BAUD_BASE / baud - 1 + * However, typically BAUD_BASE is not divisible by baud, so + * we want to select the divisor that gives us the minimum + * error. Therefore, we want: + * int(BAUD_BASE / baud - 0.5) -> + * int(BAUD_BASE / baud - (baud >> 1) / baud) -> + * int((BAUD_BASE - (baud >> 1)) / baud) + */ + +static void __serial21285_stop_tx(struct uart_port *port) +{ + if (tx_enabled(port)) { + disable_irq(IRQ_CONTX); + tx_enabled(port) = 0; + } +} + +static void +serial21285_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + __serial21285_stop_tx(port); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void +serial21285_start_tx(struct uart_port *port, unsigned int tty_start) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (!tx_enabled(port)) { + enable_irq(IRQ_CONTX); + tx_enabled(port) = 1; + } + spin_unlock_irqrestore(&port->lock, flags); +} + +static void serial21285_stop_rx(struct uart_port *port) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (rx_enabled(port)) { + disable_irq(IRQ_CONRX); + rx_enabled(port) = 0; + } + spin_unlock_irqrestore(&port->lock, flags); +} + +static void serial21285_enable_ms(struct uart_port *port) +{ +} + +static void serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *regs) +{ + struct uart_port *port = dev_id; + struct tty_struct *tty = port->info->tty; + unsigned int status, ch, rxs, max_count = 256; + + status = *CSR_UARTFLG; + while (!(status & 0x10) && max_count--) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty->flip.tqueue.routine((void *)tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + printk(KERN_WARNING "TTY_DONT_FLIP set\n"); + return; + } + } + + ch = *CSR_UARTDR; + + *tty->flip.char_buf_ptr = ch; + *tty->flip.flag_buf_ptr = TTY_NORMAL; + port->icount.rx++; + + rxs = *CSR_RXSTAT | RXSTAT_DUMMY_READ; + if (rxs & RXSTAT_ANYERR) { + if (rxs & RXSTAT_PARITY) + port->icount.parity++; + else if (rxs & RXSTAT_FRAME) + port->icount.frame++; + if (rxs & RXSTAT_OVERRUN) + port->icount.overrun++; + + rxs &= port->read_status_mask; + + if (rxs & RXSTAT_PARITY) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (rxs & RXSTAT_FRAME) + *tty->flip.flag_buf_ptr = TTY_FRAME; + } + + if ((rxs & port->ignore_status_mask) == 0) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + if ((rxs & RXSTAT_OVERRUN) && + tty->flip.count < TTY_FLIPBUF_SIZE) { + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character. + */ + *tty->flip.char_buf_ptr++ = 0; + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + tty->flip.count++; + } + status = *CSR_UARTFLG; + } + tty_flip_buffer_push(tty); +} + +static void serial21285_tx_chars(int irq, void *dev_id, struct pt_regs *regs) +{ + struct uart_port *port = dev_id; + struct circ_buf *xmit = &port->info->xmit; + int count = 256; + + if (port->x_char) { + *CSR_UARTDR = port->x_char; + port->icount.tx++; + port->x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + __serial21285_stop_tx(port); + return; + } + + do { + *CSR_UARTDR = xmit->buf[xmit->tail]; + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0 && !(*CSR_UARTFLG & 0x20)); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_event(port, EVT_WRITE_WAKEUP); + + if (uart_circ_empty(xmit)) + __serial21285_stop_tx(port); +} + +static unsigned int serial21285_tx_empty(struct uart_port *port) +{ + return (*CSR_UARTFLG & 8) ? 0 : TIOCSER_TEMT; +} + +/* no modem control lines */ +static unsigned int serial21285_get_mctrl(struct uart_port *port) +{ + return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; +} + +static void serial21285_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static void serial21285_break_ctl(struct uart_port *port, int break_state) +{ + unsigned long flags; + unsigned int h_lcr; + + spin_lock_irqsave(&port->lock, flags); + h_lcr = *CSR_H_UBRLCR; + if (break_state) + h_lcr |= H_UBRLCR_BREAK; + else + h_lcr &= ~H_UBRLCR_BREAK; + *CSR_H_UBRLCR = h_lcr; + spin_unlock_irqrestore(&port->lock, flags); +} + +static int serial21285_startup(struct uart_port *port) +{ + int ret; + + tx_enabled(port) = 1; + rx_enabled(port) = 1; + + ret = request_irq(IRQ_CONRX, serial21285_rx_chars, 0, + serial21285_name, port); + if (ret == 0) { + ret = request_irq(IRQ_CONTX, serial21285_tx_chars, 0, + serial21285_name, port); + if (ret) + free_irq(IRQ_CONRX, port); + } + + return ret; +} + +static void serial21285_shutdown(struct uart_port *port) +{ + free_irq(IRQ_CONTX, port); + free_irq(IRQ_CONRX, port); +} + +static void +serial21285_change_speed(struct uart_port *port, unsigned int cflag, + unsigned int iflag, unsigned int quot) +{ + unsigned int h_lcr; + + switch (cflag & CSIZE) { + case CS5: + h_lcr = 0x00; + break; + case CS6: + h_lcr = 0x20; + break; + case CS7: + h_lcr = 0x40; + break; + default: /* CS8 */ + h_lcr = 0x60; + break; + } + + if (cflag & CSTOPB) + h_lcr |= H_UBRLCR_STOPB; + if (cflag & PARENB) { + h_lcr |= H_UBRLCR_PARENB; + if (!(cflag & PARODD)) + h_lcr |= H_UBRLCR_PAREVN; + } + + if (port->fifosize) + h_lcr |= H_UBRLCR_FIFO; + + port->read_status_mask = RXSTAT_OVERRUN; + if (iflag & INPCK) + port->read_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (iflag & IGNPAR) + port->ignore_status_mask |= RXSTAT_FRAME | RXSTAT_PARITY; + if (iflag & IGNBRK && iflag & IGNPAR) + port->ignore_status_mask |= RXSTAT_OVERRUN; + + /* + * Ignore all characters if CREAD is not set. + */ + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= RXSTAT_DUMMY_READ; + + quot -= 1; + + *CSR_UARTCON = 0; + *CSR_L_UBRLCR = quot & 0xff; + *CSR_M_UBRLCR = (quot >> 8) & 0x0f; + *CSR_H_UBRLCR = h_lcr; + *CSR_UARTCON = 1; +} + +static const char *serial21285_type(struct uart_port *port) +{ + return port->type == PORT_21285 ? "DC21285" : NULL; +} + +static void serial21285_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, 32); +} + +static int serial21285_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, 32, serial21285_name) + != NULL ? 0 : -EBUSY; +} + +static void serial21285_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE && serial21285_request_port(port) == 0) + port->type = PORT_21285; +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int serial21285_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_21285) + ret = -EINVAL; + if (ser->irq != NO_IRQ) + ret = -EINVAL; + if (ser->baud_base != port->uartclk / 16) + ret = -EINVAL; + return ret; +} + +static struct uart_ops serial21285_ops = { + tx_empty: serial21285_tx_empty, + get_mctrl: serial21285_get_mctrl, + set_mctrl: serial21285_set_mctrl, + stop_tx: serial21285_stop_tx, + start_tx: serial21285_start_tx, + stop_rx: serial21285_stop_rx, + enable_ms: serial21285_enable_ms, + break_ctl: serial21285_break_ctl, + startup: serial21285_startup, + shutdown: serial21285_shutdown, + change_speed: serial21285_change_speed, + type: serial21285_type, + release_port: serial21285_release_port, + request_port: serial21285_request_port, + config_port: serial21285_config_port, + verify_port: serial21285_verify_port, +}; + +static struct uart_port serial21285_port = { + membase: 0, + mapbase: 0x42000160, + iotype: SERIAL_IO_MEM, + irq: NO_IRQ, + uartclk: 0, + fifosize: 16, + ops: &serial21285_ops, + flags: ASYNC_BOOT_AUTOCONF, +}; + +static void serial21285_setup_ports(void) +{ + serial21285_port.uartclk = mem_fclk_21285 / 4; +} + +#ifdef CONFIG_SERIAL_21285_CONSOLE + +static void +serial21285_console_write(struct console *co, const char *s, + unsigned int count) +{ + int i; + + for (i = 0; i < count; i++) { + while (*CSR_UARTFLG & 0x20) + barrier(); + *CSR_UARTDR = s[i]; + if (s[i] == '\n') { + while (*CSR_UARTFLG & 0x20) + barrier(); + *CSR_UARTDR = '\r'; + } + } +} + +static kdev_t serial21285_console_device(struct console *c) +{ + return mk_kdev(SERIAL_21285_MAJOR, SERIAL_21285_MINOR); +} + +static void __init +serial21285_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + if (*CSR_UARTCON == 1) { + unsigned int tmp; + + tmp = *CSR_H_UBRLCR; + switch (tmp & 0x60) { + case 0x00: + *bits = 5; + break; + case 0x20: + *bits = 6; + break; + case 0x40: + *bits = 7; + break; + default: + case 0x60: + *bits = 8; + break; + } + + if (tmp & H_UBRLCR_PARENB) { + *parity = 'o'; + if (tmp & H_UBRLCR_PAREVN) + *parity = 'e'; + } + + tmp = *CSR_L_UBRLCR | (*CSR_M_UBRLCR << 8); + + *baud = port->uartclk / (16 * (tmp + 1)); + } +} + +static int __init serial21285_console_setup(struct console *co, char *options) +{ + struct uart_port *port = &serial21285_port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (machine_is_personal_server()) + baud = 57600; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + serial21285_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +#ifdef CONFIG_SERIAL_21285_OLD +static struct console serial21285_old_cons = +{ + name: SERIAL_21285_OLD_NAME, + write: serial21285_console_write, + device: serial21285_console_device, + setup: serial21285_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; +#endif + +static struct console serial21285_console = +{ + name: SERIAL_21285_NAME, + write: serial21285_console_write, + device: serial21285_console_device, + setup: serial21285_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +void __init rs285_console_init(void) +{ + serial21285_setup_ports(); + register_console(&serial21285_console); +} + +#define SERIAL_21285_CONSOLE &serial21285_console +#else +#define SERIAL_21285_CONSOLE NULL +#endif + +static struct uart_driver serial21285_reg = { + owner: THIS_MODULE, + driver_name: "ttyFB", +#ifdef CONFIG_DEVFS_FS + dev_name: "ttyFB%d", +#else + dev_name: "ttyFB", +#endif + major: SERIAL_21285_MAJOR, + minor: SERIAL_21285_MINOR, + nr: 1, + cons: SERIAL_21285_CONSOLE, +}; + +static int __init serial21285_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: 21285 driver $Revision: 1.32 $\n"); + + serial21285_setup_ports(); + + ret = uart_register_driver(&serial21285_reg); + if (ret == 0) + uart_add_one_port(&serial21285_reg, &serial21285_port); + + return ret; +} + +static void __exit serial21285_exit(void) +{ + uart_remove_one_port(&serial21285_reg, &serial21285_port); + uart_unregister_driver(&serial21285_reg); +} + +module_init(serial21285_init); +module_exit(serial21285_exit); + +EXPORT_NO_SYMBOLS; + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Intel Footbridge (21285) serial driver $Revision: 1.32 $"); diff --git a/drivers/serial/serial_8250.c b/drivers/serial/serial_8250.c new file mode 100644 index 000000000000..b763e3faa3de --- /dev/null +++ b/drivers/serial/serial_8250.c @@ -0,0 +1,2015 @@ +/* + * linux/drivers/char/serial_8250.c + * + * Driver for 8250/16550-type serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright (C) 2001 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * $Id: serial_8250.c,v 1.80 2002/07/21 08:57:55 rmk Exp $ + * + * A note about mapbase / membase + * + * mapbase is the physical address of the IO port. Currently, we don't + * support this very well, and it may well be dropped from this driver + * in future. As such, mapbase should be NULL. + * + * membase is an 'ioremapped' cookie. This is compatible with the old + * serial.c driver, and is currently the preferred form. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/compiler.h> +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/major.h> +#include <linux/slab.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/init.h> +#include <linux/serial.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/serial_reg.h> +#include <linux/serialP.h> +#include <linux/delay.h> +#include <linux/kmod.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/bitops.h> + +#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/serial_core.h> +#include "serial_8250.h" + +/* + * Configuration: + * share_irqs - whether we pass SA_SHIRQ to request_irq(). This option + * is unsafe when used on edge-triggered interrupts. + */ +unsigned int share_irqs = SERIAL8250_SHARE_IRQS; + +/* + * Debugging. + */ +#if 0 +#define DEBUG_AUTOCONF(fmt...) printk(fmt) +#else +#define DEBUG_AUTOCONF(fmt...) do { } while (0) +#endif + +#if 0 +#define DEBUG_INTR(fmt...) printk(fmt) +#else +#define DEBUG_INTR(fmt...) do { } while (0) +#endif + +#define PASS_LIMIT 256 + +/* + * We default to IRQ0 for the "no irq" hack. Some + * machine types want others as well - they're free + * to redefine this in their header file. + */ +#define is_real_interrupt(irq) ((irq) != 0) + +/* + * This converts from our new CONFIG_ symbols to the symbols + * that asm/serial.h expects. You _NEED_ to comment out the + * linux/config.h include contained inside asm/serial.h for + * this to work. + */ +#undef CONFIG_SERIAL_MANY_PORTS +#undef CONFIG_SERIAL_DETECT_IRQ +#undef CONFIG_SERIAL_MULTIPORT +#undef CONFIG_HUB6 + +#ifdef CONFIG_SERIAL_8250_DETECT_IRQ +#define CONFIG_SERIAL_DETECT_IRQ 1 +#endif +#ifdef CONFIG_SERIAL_8250_MULTIPORT +#define CONFIG_SERIAL_MULTIPORT 1 +#endif + +/* + * HUB6 is always on. This will be removed once the header + * files have been cleaned. + */ +#define CONFIG_HUB6 1 +#define CONFIG_SERIAL_MANY_PORTS 1 + +#include <asm/serial.h> + +static struct old_serial_port old_serial_port[] = { + SERIAL_PORT_DFNS /* defined in asm/serial.h */ +}; + +#define UART_NR ARRAY_SIZE(old_serial_port) + +#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE) + +#define PORT_RSA_MAX 4 +static int probe_rsa[PORT_RSA_MAX]; +static int force_rsa[PORT_RSA_MAX]; +#endif /* CONFIG_SERIAL_8250_RSA */ + +struct uart_8250_port { + struct uart_port port; + struct timer_list timer; /* "no irq" timer */ + struct list_head list; /* ports on this IRQ */ + unsigned char acr; + unsigned char ier; + unsigned char rev; + unsigned char lcr; + unsigned int lsr_break_flag; + + /* + * We provide a per-port pm hook. + */ + void (*pm)(struct uart_port *port, + unsigned int state, unsigned int old); +}; + +struct irq_info { + spinlock_t lock; + struct list_head *head; +}; + +static struct irq_info irq_lists[NR_IRQS]; + +/* + * Here we define the default xmit fifo size used for each type of UART. + */ +static const struct serial_uart_config uart_config[PORT_MAX_8250+1] = { + { "unknown", 1, 0 }, + { "8250", 1, 0 }, + { "16450", 1, 0 }, + { "16550", 1, 0 }, + { "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, + { "Cirrus", 1, 0 }, + { "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, + { "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, + { "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO }, + { "Startech", 1, 0 }, + { "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO }, + { "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, + { "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO | UART_STARTECH }, + { "RSA", 2048, UART_CLEAR_FIFO | UART_USE_FIFO } +}; + +static _INLINE_ unsigned int serial_in(struct uart_8250_port *up, int offset) +{ + offset <<= up->port.regshift; + + switch (up->port.iotype) { + case SERIAL_IO_HUB6: + outb(up->port.hub6 - 1 + offset, up->port.iobase); + return inb(up->port.iobase + 1); + + case SERIAL_IO_MEM: + return readb(up->port.membase + offset); + + default: + return inb(up->port.iobase + offset); + } +} + +static _INLINE_ void +serial_out(struct uart_8250_port *up, int offset, int value) +{ + offset <<= up->port.regshift; + + switch (up->port.iotype) { + case SERIAL_IO_HUB6: + outb(up->port.hub6 - 1 + offset, up->port.iobase); + outb(value, up->port.iobase + 1); + break; + + case SERIAL_IO_MEM: + writeb(value, up->port.membase + offset); + break; + + default: + outb(value, up->port.iobase + offset); + } +} + +/* + * We used to support using pause I/O for certain machines. We + * haven't supported this for a while, but just in case it's badly + * needed for certain old 386 machines, I've left these #define's + * in.... + */ +#define serial_inp(up, offset) serial_in(up, offset) +#define serial_outp(up, offset, value) serial_out(up, offset, value) + + +/* + * For the 16C950 + */ +static void serial_icr_write(struct uart_8250_port *up, int offset, int value) +{ + serial_out(up, UART_SCR, offset); + serial_out(up, UART_ICR, value); +} + +static unsigned int serial_icr_read(struct uart_8250_port *up, int offset) +{ + unsigned int value; + + serial_icr_write(up, UART_ACR, up->acr | UART_ACR_ICRRD); + serial_out(up, UART_SCR, offset); + value = serial_in(up, UART_ICR); + serial_icr_write(up, UART_ACR, up->acr); + + return value; +} + +#ifdef CONFIG_SERIAL_8250_RSA +/* + * Attempts to turn on the RSA FIFO. Returns zero on failure. + * We set the port uart clock rate if we succeed. + */ +static int __enable_rsa(struct uart_8250_port *up) +{ + unsigned char mode; + int result; + + mode = serial_inp(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + + if (!result) { + serial_outp(up, UART_RSA_MSR, mode | UART_RSA_MSR_FIFO); + mode = serial_inp(up, UART_RSA_MSR); + result = mode & UART_RSA_MSR_FIFO; + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE * 16; + + return result; +} + +static void enable_rsa(struct uart_8250_port *up) +{ + if (up->port.type == PORT_RSA) { + if (up->port.uartclk != SERIAL_RSA_BAUD_BASE * 16) { + spin_lock_irq(&up->port.lock); + __enable_rsa(up); + spin_unlock_irq(&up->port.lock); + } + if (up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) + serial_outp(up, UART_RSA_FRR, 0); + } +} + +/* + * Attempts to turn off the RSA FIFO. Returns zero on failure. + * It is unknown why interrupts were disabled in here. However, + * the caller is expected to preserve this behaviour by grabbing + * the spinlock before calling this function. + */ +static void disable_rsa(struct uart_8250_port *up) +{ + unsigned char mode; + int result; + + if (up->port.type == PORT_RSA && + up->port.uartclk == SERIAL_RSA_BAUD_BASE * 16) { + spin_lock_irq(&up->port.lock); + + mode = serial_inp(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + + if (!result) { + serial_outp(up, UART_RSA_MSR, mode & ~UART_RSA_MSR_FIFO); + mode = serial_inp(up, UART_RSA_MSR); + result = !(mode & UART_RSA_MSR_FIFO); + } + + if (result) + up->port.uartclk = SERIAL_RSA_BAUD_BASE_LO * 16; + spin_unlock_irq(&up->port.lock); + } +} +#endif /* CONFIG_SERIAL_8250_RSA */ + +/* + * This is a quickie test to see how big the FIFO is. + * It doesn't work at all the time, more's the pity. + */ +static int size_fifo(struct uart_8250_port *up) +{ + unsigned char old_fcr, old_mcr, old_dll, old_dlm; + int count; + + old_fcr = serial_inp(up, UART_FCR); + old_mcr = serial_inp(up, UART_MCR); + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_outp(up, UART_MCR, UART_MCR_LOOP); + serial_outp(up, UART_LCR, UART_LCR_DLAB); + old_dll = serial_inp(up, UART_DLL); + old_dlm = serial_inp(up, UART_DLM); + serial_outp(up, UART_DLL, 0x01); + serial_outp(up, UART_DLM, 0x00); + serial_outp(up, UART_LCR, 0x03); + for (count = 0; count < 256; count++) + serial_outp(up, UART_TX, count); + mdelay(20);/* FIXME - schedule_timeout */ + for (count = 0; (serial_inp(up, UART_LSR) & UART_LSR_DR) && + (count < 256); count++) + serial_inp(up, UART_RX); + serial_outp(up, UART_FCR, old_fcr); + serial_outp(up, UART_MCR, old_mcr); + serial_outp(up, UART_LCR, UART_LCR_DLAB); + serial_outp(up, UART_DLL, old_dll); + serial_outp(up, UART_DLM, old_dlm); + + return count; +} + +/* + * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's. + * When this function is called we know it is at least a StarTech + * 16650 V2, but it might be one of several StarTech UARTs, or one of + * its clones. (We treat the broken original StarTech 16650 V1 as a + * 16550, and why not? Startech doesn't seem to even acknowledge its + * existence.) + * + * What evil have men's minds wrought... + */ +static void +autoconfig_startech_uarts(struct uart_8250_port *up) +{ + unsigned char scratch, scratch2, scratch3, scratch4; + + /* + * First we check to see if it's an Oxford Semiconductor UART. + * + * If we have to do this here because some non-National + * Semiconductor clone chips lock up if you try writing to the + * LSR register (which serial_icr_read does) + */ + if (up->port.type == PORT_16550A) { + /* + * EFR [4] must be set else this test fails + * + * This shouldn't be necessary, but Mike Hudson + * (Exoray@isys.ca) claims that it's needed for 952 + * dual UART's (which are not recommended for new designs). + */ + up->acr = 0; + serial_out(up, UART_LCR, 0xBF); + serial_out(up, UART_EFR, 0x10); + serial_out(up, UART_LCR, 0x00); + /* Check for Oxford Semiconductor 16C950 */ + scratch = serial_icr_read(up, UART_ID1); + scratch2 = serial_icr_read(up, UART_ID2); + scratch3 = serial_icr_read(up, UART_ID3); + + if (scratch == 0x16 && scratch2 == 0xC9 && + (scratch3 == 0x50 || scratch3 == 0x52 || + scratch3 == 0x54)) { + up->port.type = PORT_16C950; + up->rev = serial_icr_read(up, UART_REV) | + (scratch3 << 8); + return; + } + } + + /* + * We check for a XR16C850 by setting DLL and DLM to 0, and then + * reading back DLL and DLM. The chip type depends on the DLM + * value read back: + * 0x10 - XR16C850 and the DLL contains the chip revision. + * 0x12 - XR16C2850. + * 0x14 - XR16C854. + */ + + /* Save the DLL and DLM */ + + serial_outp(up, UART_LCR, UART_LCR_DLAB); + scratch3 = serial_inp(up, UART_DLL); + scratch4 = serial_inp(up, UART_DLM); + + serial_outp(up, UART_DLL, 0); + serial_outp(up, UART_DLM, 0); + scratch2 = serial_inp(up, UART_DLL); + scratch = serial_inp(up, UART_DLM); + serial_outp(up, UART_LCR, 0); + + if (scratch == 0x10 || scratch == 0x12 || scratch == 0x14) { + if (scratch == 0x10) + up->rev = scratch2; + up->port.type = PORT_16850; + return; + } + + /* Restore the DLL and DLM */ + + serial_outp(up, UART_LCR, UART_LCR_DLAB); + serial_outp(up, UART_DLL, scratch3); + serial_outp(up, UART_DLM, scratch4); + serial_outp(up, UART_LCR, 0); + + /* + * We distinguish between the '654 and the '650 by counting + * how many bytes are in the FIFO. I'm using this for now, + * since that's the technique that was sent to me in the + * serial driver update, but I'm not convinced this works. + * I've had problems doing this in the past. -TYT + */ + if (size_fifo(up) == 64) + up->port.type = PORT_16654; + else + up->port.type = PORT_16650V2; +} + +/* + * This routine is called by rs_init() to initialize a specific serial + * port. It determines what type of UART chip this serial port is + * using: 8250, 16450, 16550, 16550A. The important question is + * whether or not this UART is a 16550A or not, since this will + * determine whether or not we can use its FIFO features or not. + */ +static void autoconfig(struct uart_8250_port *up, unsigned int probeflags) +{ + unsigned char status1, status2, scratch, scratch2, scratch3; + unsigned char save_lcr, save_mcr; + unsigned long flags; + + DEBUG_AUTOCONF("Testing ttyS%d (0x%04x, 0x%08lx)...\n", + up->port.line, up->port.iobase, up->port.membase); + + if (!up->port.iobase && !up->port.membase) + return; + + /* + * We really do need global IRQs disabled here - we're going to + * be frobbing the chips IRQ enable register to see if it exists. + */ + spin_lock_irqsave(&up->port.lock, flags); +// save_flags(flags); cli(); + + if (!(up->port.flags & ASYNC_BUGGY_UART)) { + /* + * Do a simple existence test first; if we fail this, + * there's no point trying anything else. + * + * 0x80 is used as a nonsense port to prevent against + * false positives due to ISA bus float. The + * assumption is that 0x80 is a non-existent port; + * which should be safe since include/asm/io.h also + * makes this assumption. + */ + scratch = serial_inp(up, UART_IER); + serial_outp(up, UART_IER, 0); +#ifdef __i386__ + outb(0xff, 0x080); +#endif + scratch2 = serial_inp(up, UART_IER); + serial_outp(up, UART_IER, 0x0F); +#ifdef __i386__ + outb(0, 0x080); +#endif + scratch3 = serial_inp(up, UART_IER); + serial_outp(up, UART_IER, scratch); + if (scratch2 != 0 || scratch3 != 0x0F) { + /* + * We failed; there's nothing here + */ + DEBUG_AUTOCONF("serial: ttyS%d: simple autoconfig " + "failed (%02x, %02x)\n", + up->port.line, scratch2, scratch3); + goto out; + } + } + + save_mcr = serial_in(up, UART_MCR); + save_lcr = serial_in(up, UART_LCR); + + /* + * Check to see if a UART is really there. Certain broken + * internal modems based on the Rockwell chipset fail this + * test, because they apparently don't implement the loopback + * test mode. So this test is skipped on the COM 1 through + * COM 4 ports. This *should* be safe, since no board + * manufacturer would be stupid enough to design a board + * that conflicts with COM 1-4 --- we hope! + */ + if (!(up->port.flags & ASYNC_SKIP_TEST)) { + serial_outp(up, UART_MCR, UART_MCR_LOOP | 0x0A); + status1 = serial_inp(up, UART_MSR) & 0xF0; + serial_outp(up, UART_MCR, save_mcr); + if (status1 != 0x90) { + DEBUG_AUTOCONF("serial: ttyS%d: no UART loopback " + "failed\n", up->port.line); + goto out; + } + } + serial_outp(up, UART_LCR, 0xBF); /* set up for StarTech test */ + serial_outp(up, UART_EFR, 0); /* EFR is the same as FCR */ + serial_outp(up, UART_LCR, 0); + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = serial_in(up, UART_IIR) >> 6; + switch (scratch) { + case 0: + up->port.type = PORT_16450; + break; + case 1: + up->port.type = PORT_UNKNOWN; + break; + case 2: + up->port.type = PORT_16550; + break; + case 3: + up->port.type = PORT_16550A; + break; + } + if (up->port.type == PORT_16550A) { + /* Check for Startech UART's */ + serial_outp(up, UART_LCR, UART_LCR_DLAB); + if (serial_in(up, UART_EFR) == 0) { + up->port.type = PORT_16650; + } else { + serial_outp(up, UART_LCR, 0xBF); + if (serial_in(up, UART_EFR) == 0) + autoconfig_startech_uarts(up); + } + } + if (up->port.type == PORT_16550A) { + /* Check for TI 16750 */ + serial_outp(up, UART_LCR, save_lcr | UART_LCR_DLAB); + serial_outp(up, UART_FCR, + UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + scratch = serial_in(up, UART_IIR) >> 5; + if (scratch == 7) { + /* + * If this is a 16750, and not a cheap UART + * clone, then it should only go into 64 byte + * mode if the UART_FCR7_64BYTE bit was set + * while UART_LCR_DLAB was latched. + */ + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(up, UART_LCR, 0); + serial_outp(up, UART_FCR, + UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); + scratch = serial_in(up, UART_IIR) >> 5; + if (scratch == 6) + up->port.type = PORT_16750; + } + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + } +#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE) + /* + * Only probe for RSA ports if we got the region. + */ + if (up->port.type == PORT_16550A && probeflags & PROBE_RSA) { + int i; + + for (i = 0 ; i < PORT_RSA_MAX ; ++i) { + if (!probe_rsa[i] && !force_rsa[i]) + break; + if (((probe_rsa[i] != up->port.iobase) || + check_region(up->port.iobase + UART_RSA_BASE, 16)) && + (force_rsa[i] != up->port.iobase)) + continue; + if (__enable_rsa(up)) { + up->port.type = PORT_RSA; + break; + } + } + } +#endif + serial_outp(up, UART_LCR, save_lcr); + if (up->port.type == PORT_16450) { + scratch = serial_in(up, UART_SCR); + serial_outp(up, UART_SCR, 0xa5); + status1 = serial_in(up, UART_SCR); + serial_outp(up, UART_SCR, 0x5a); + status2 = serial_in(up, UART_SCR); + serial_outp(up, UART_SCR, scratch); + + if ((status1 != 0xa5) || (status2 != 0x5a)) + up->port.type = PORT_8250; + } + + up->port.fifosize = uart_config[up->port.type].dfl_xmit_fifo_size; + + if (up->port.type == PORT_UNKNOWN) + goto out; + + /* + * Reset the UART. + */ +#ifdef CONFIG_SERIAL_8250_RSA + if (up->port.type == PORT_RSA) + serial_outp(up, UART_RSA_FRR, 0); +#endif + serial_outp(up, UART_MCR, save_mcr); + serial_outp(up, UART_FCR, (UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + serial_outp(up, UART_FCR, 0); + (void)serial_in(up, UART_RX); + serial_outp(up, UART_IER, 0); + + out: + spin_unlock_irqrestore(&up->port.lock, flags); +// restore_flags(flags); +#ifdef CONFIG_SERIAL_8250_RSA + if (up->port.iobase && up->port.type == PORT_RSA) { + release_region(up->port.iobase, 8); + request_region(up->port.iobase + UART_RSA_BASE, 16, + "serial_rsa"); + } +#endif +} + +static void autoconfig_irq(struct uart_8250_port *up) +{ + unsigned char save_mcr, save_ier; + unsigned char save_ICP = 0; + unsigned int ICP = 0; + unsigned long irqs; + int irq; + + if (up->port.flags & ASYNC_FOURPORT) { + ICP = (up->port.iobase & 0xfe0) | 0x1f; + save_ICP = inb_p(ICP); + outb_p(0x80, ICP); + (void) inb_p(ICP); + } + + /* forget possible initially masked and pending IRQ */ + probe_irq_off(probe_irq_on()); + save_mcr = serial_inp(up, UART_MCR); + save_ier = serial_inp(up, UART_IER); + serial_outp(up, UART_MCR, UART_MCR_OUT1 | UART_MCR_OUT2); + + irqs = probe_irq_on(); + serial_outp(up, UART_MCR, 0); + udelay (10); + if (up->port.flags & ASYNC_FOURPORT) { + serial_outp(up, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS); + } else { + serial_outp(up, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + } + serial_outp(up, UART_IER, 0x0f); /* enable all intrs */ + (void)serial_inp(up, UART_LSR); + (void)serial_inp(up, UART_RX); + (void)serial_inp(up, UART_IIR); + (void)serial_inp(up, UART_MSR); + serial_outp(up, UART_TX, 0xFF); + udelay (20); + irq = probe_irq_off(irqs); + + serial_outp(up, UART_MCR, save_mcr); + serial_outp(up, UART_IER, save_ier); + + if (up->port.flags & ASYNC_FOURPORT) + outb_p(save_ICP, ICP); + + up->port.irq = (irq > 0) ? irq : 0; +} + +static void __serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + + if (up->ier & UART_IER_THRI) { + up->ier &= ~UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + } + if (up->port.type == PORT_16C950 && tty_stop) { + up->acr |= UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } +} + +static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + __serial8250_stop_tx(port, tty_stop); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + + if (!(up->ier & UART_IER_THRI)) { + up->ier |= UART_IER_THRI; + serial_out(up, UART_IER, up->ier); + } + /* + * We only do this from uart_start + */ + if (tty_start && up->port.type == PORT_16C950) { + up->acr &= ~UART_ACR_TXDIS; + serial_icr_write(up, UART_ACR, up->acr); + } +} + +static void serial8250_stop_rx(struct uart_port *port) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + up->ier &= ~UART_IER_RLSI; + up->port.read_status_mask &= ~UART_LSR_DR; + serial_out(up, UART_IER, up->ier); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static void serial8250_enable_ms(struct uart_port *port) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + up->ier |= UART_IER_MSI; + serial_out(up, UART_IER, up->ier); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static _INLINE_ void +receive_chars(struct uart_8250_port *up, int *status, struct pt_regs *regs) +{ + struct tty_struct *tty = up->port.info->tty; + unsigned char ch; + int max_count = 256; + + do { + if (unlikely(tty->flip.count >= TTY_FLIPBUF_SIZE)) { + tty->flip.tqueue.routine((void *)tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + return; // if TTY_DONT_FLIP is set + } + ch = serial_inp(up, UART_RX); + *tty->flip.char_buf_ptr = ch; + *tty->flip.flag_buf_ptr = TTY_NORMAL; + up->port.icount.rx++; + + if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | + UART_LSR_FE | UART_LSR_OE))) { + /* + * For statistics only + */ + if (*status & UART_LSR_BI) { + *status &= ~(UART_LSR_FE | UART_LSR_PE); + up->port.icount.brk++; + /* + * We do the SysRQ and SAK checking + * here because otherwise the break + * may get masked by ignore_status_mask + * or read_status_mask. + */ + if (uart_handle_break(&up->port)) + goto ignore_char; + } else if (*status & UART_LSR_PE) + up->port.icount.parity++; + else if (*status & UART_LSR_FE) + up->port.icount.frame++; + if (*status & UART_LSR_OE) + up->port.icount.overrun++; + + /* + * Mask off conditions which should be ingored. + */ + *status &= up->port.read_status_mask; + +#ifdef CONFIG_SERIAL_8250_CONSOLE + if (up->port.line == up->port.cons->index) { + /* Recover the break flag from console xmit */ + *status |= up->lsr_break_flag; + up->lsr_break_flag = 0; + } +#endif + if (*status & UART_LSR_BI) { + DEBUG_INTR("handling break...."); + *tty->flip.flag_buf_ptr = TTY_BREAK; + } else if (*status & UART_LSR_PE) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (*status & UART_LSR_FE) + *tty->flip.flag_buf_ptr = TTY_FRAME; + } + if (uart_handle_sysrq_char(&up->port, ch, regs)) + goto ignore_char; + if ((*status & up->port.ignore_status_mask) == 0) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + if ((*status & UART_LSR_OE) && + tty->flip.count < TTY_FLIPBUF_SIZE) { + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character. + */ + *tty->flip.flag_buf_ptr = TTY_OVERRUN; + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + ignore_char: + *status = serial_inp(up, UART_LSR); + } while ((*status & UART_LSR_DR) && (max_count-- > 0)); + tty_flip_buffer_push(tty); +} + +static _INLINE_ void transmit_chars(struct uart_8250_port *up) +{ + struct circ_buf *xmit = &up->port.info->xmit; + int count; + + if (up->port.x_char) { + serial_outp(up, UART_TX, up->port.x_char); + up->port.icount.tx++; + up->port.x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { + __serial8250_stop_tx(&up->port, 0); + return; + } + + count = up->port.fifosize; + do { + serial_out(up, UART_TX, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + up->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_event(&up->port, EVT_WRITE_WAKEUP); + + DEBUG_INTR("THRE..."); + + if (uart_circ_empty(xmit)) + __serial8250_stop_tx(&up->port, 0); +} + +static _INLINE_ void check_modem_status(struct uart_8250_port *up) +{ + int status; + + status = serial_in(up, UART_MSR); + + if ((status & UART_MSR_ANY_DELTA) == 0) + return; + + if (status & UART_MSR_TERI) + up->port.icount.rng++; + if (status & UART_MSR_DDSR) + up->port.icount.dsr++; + if (status & UART_MSR_DDCD) + uart_handle_dcd_change(&up->port, status & UART_MSR_DCD); + if (status & UART_MSR_DCTS) + uart_handle_cts_change(&up->port, status & UART_MSR_CTS); + + wake_up_interruptible(&up->port.info->delta_msr_wait); +} + +/* + * This handles the interrupt from one port. + */ +static inline void +serial8250_handle_port(struct uart_8250_port *up, struct pt_regs *regs) +{ + unsigned int status = serial_inp(up, UART_LSR); + + DEBUG_INTR("status = %x...", status); + + if (status & UART_LSR_DR) + receive_chars(up, &status, regs); + check_modem_status(up); + if (status & UART_LSR_THRE) + transmit_chars(up); +} + +/* + * This is the serial driver's interrupt routine. + * + * Arjan thinks the old way was overly complex, so it got simplified. + * Alan disagrees, saying that need the complexity to handle the weird + * nature of ISA shared interrupts. (This is a special exception.) + * + * In order to handle ISA shared interrupts properly, we need to check + * that all ports have been serviced, and therefore the ISA interrupt + * line has been de-asserted. + * + * This means we need to loop through all ports. checking that they + * don't have an interrupt pending. + */ +static void serial8250_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct irq_info *i = dev_id; + struct list_head *l, *end = NULL; + int pass_counter = 0; + + DEBUG_INTR("serial8250_interrupt(%d)...", irq); + + spin_lock(&i->lock); + + l = i->head; + do { + struct uart_8250_port *up; + unsigned int iir; + + up = list_entry(l, struct uart_8250_port, list); + + iir = serial_in(up, UART_IIR); + if (!(iir & UART_IIR_NO_INT)) { + spin_lock(&up->port.lock); + serial8250_handle_port(up, regs); + spin_unlock(&up->port.lock); + + end = NULL; + } else if (end == NULL) + end = l; + + l = l->next; + + if (l == i->head && pass_counter++ > PASS_LIMIT) { + /* If we hit this, we're dead. */ + printk(KERN_ERR "serial8250: too much work for " + "irq%d\n", irq); + break; + } + } while (l != end); + + spin_unlock(&i->lock); + + DEBUG_INTR("end.\n"); +} + +/* + * To support ISA shared interrupts, we need to have one interrupt + * handler that ensures that the IRQ line has been deasserted + * before returning. Failing to do this will result in the IRQ + * line being stuck active, and, since ISA irqs are edge triggered, + * no more IRQs will be seen. + */ +static int serial_link_irq_chain(struct uart_8250_port *up) +{ + struct irq_info *i = irq_lists + up->port.irq; + int ret, irq_flags = share_irqs ? SA_SHIRQ : 0; + + spin_lock_irq(&i->lock); + + if (i->head) { + list_add(&up->list, i->head); + spin_unlock_irq(&i->lock); + + ret = 0; + } else { + INIT_LIST_HEAD(&up->list); + i->head = &up->list; + spin_unlock_irq(&i->lock); + + ret = request_irq(up->port.irq, serial8250_interrupt, + irq_flags, "serial", i); + } + + return ret; +} + +static void serial_unlink_irq_chain(struct uart_8250_port *up) +{ + struct irq_info *i = irq_lists + up->port.irq; + + BUG_ON(i->head == NULL); + + if (list_empty(i->head)) + free_irq(up->port.irq, i); + + spin_lock_irq(&i->lock); + + if (!list_empty(i->head)) { + if (i->head == &up->list) + i->head = i->head->next; + list_del(&up->list); + } else { + BUG_ON(i->head != &up->list); + i->head = NULL; + } + + spin_unlock_irq(&i->lock); +} + +/* + * This function is used to handle ports that do not have an + * interrupt. This doesn't work very well for 16450's, but gives + * barely passable results for a 16550A. (Although at the expense + * of much CPU overhead). + */ +static void serial8250_timeout(unsigned long data) +{ + struct uart_8250_port *up = (struct uart_8250_port *)data; + unsigned int timeout; + unsigned int iir; + + iir = serial_in(up, UART_IIR); + if (!(iir & UART_IIR_NO_INT)) { + spin_lock(&up->port.lock); + serial8250_handle_port(up, NULL); + spin_unlock(&up->port.lock); + } + + timeout = up->port.timeout; + timeout = timeout > 6 ? (timeout / 2 - 2) : 1; + mod_timer(&up->timer, jiffies + timeout); +} + +static unsigned int serial8250_tx_empty(struct uart_port *port) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned long flags; + unsigned int ret; + + spin_lock_irqsave(&up->port.lock, flags); + ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0; + spin_unlock_irqrestore(&up->port.lock, flags); + + return ret; +} + +static unsigned int serial8250_get_mctrl(struct uart_port *port) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned long flags; + unsigned char status; + unsigned int ret; + + spin_lock_irqsave(&up->port.lock, flags); + status = serial_in(up, UART_MSR); + spin_unlock_irqrestore(&up->port.lock, flags); + + ret = 0; + if (status & UART_MSR_DCD) + ret |= TIOCM_CAR; + if (status & UART_MSR_RI) + ret |= TIOCM_RNG; + if (status & UART_MSR_DSR) + ret |= TIOCM_DSR; + if (status & UART_MSR_CTS) + ret |= TIOCM_CTS; + return ret; +} + +static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned char mcr = ALPHA_KLUDGE_MCR; + + if (mctrl & TIOCM_RTS) + mcr |= UART_MCR_RTS; + if (mctrl & TIOCM_DTR) + mcr |= UART_MCR_DTR; + if (mctrl & TIOCM_OUT1) + mcr |= UART_MCR_OUT1; + if (mctrl & TIOCM_OUT2) + mcr |= UART_MCR_OUT2; + if (mctrl & TIOCM_LOOP) + mcr |= UART_MCR_LOOP; + + serial_out(up, UART_MCR, mcr); +} + +static void serial8250_break_ctl(struct uart_port *port, int break_state) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned long flags; + + spin_lock_irqsave(&up->port.lock, flags); + if (break_state == -1) + up->lcr |= UART_LCR_SBC; + else + up->lcr &= ~UART_LCR_SBC; + serial_out(up, UART_LCR, up->lcr); + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static int serial8250_startup(struct uart_port *port) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned long flags; + int retval; + + if (up->port.type == PORT_16C950) { + /* Wake up and initialize UART */ + up->acr = 0; + serial_outp(up, UART_LCR, 0xBF); + serial_outp(up, UART_EFR, UART_EFR_ECB); + serial_outp(up, UART_IER, 0); + serial_outp(up, UART_LCR, 0); + serial_icr_write(up, UART_CSR, 0); /* Reset the UART */ + serial_outp(up, UART_LCR, 0xBF); + serial_outp(up, UART_EFR, UART_EFR_ECB); + serial_outp(up, UART_LCR, 0); + } + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * If this is an RSA port, see if we can kick it up to the + * higher speed clock. + */ + enable_rsa(up); +#endif + + /* + * Clear the FIFO buffers and disable them. + * (they will be reeanbled in change_speed()) + */ + if (uart_config[up->port.type].flags & UART_CLEAR_FIFO) { + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + serial_outp(up, UART_FCR, 0); + } + + /* + * Clear the interrupt registers. + */ + (void) serial_inp(up, UART_LSR); + (void) serial_inp(up, UART_RX); + (void) serial_inp(up, UART_IIR); + (void) serial_inp(up, UART_MSR); + + /* + * At this point, there's no way the LSR could still be 0xff; + * if it is, then bail out, because there's likely no UART + * here. + */ + if (!(up->port.flags & ASYNC_BUGGY_UART) && + (serial_inp(up, UART_LSR) == 0xff)) { + printk("ttyS%d: LSR safety check engaged!\n", up->port.line); + return -ENODEV; + } + + /* + * If the "interrupt" for this port doesn't correspond with any + * hardware interrupt, we use a timer-based system. The original + * driver used to do this with IRQ0. + */ + if (!is_real_interrupt(up->port.irq)) { + unsigned int timeout = up->port.timeout; + + timeout = timeout > 6 ? (timeout / 2 - 2) : 1; + + up->timer.data = (unsigned long)up; + mod_timer(&up->timer, jiffies + timeout); + } else { + retval = serial_link_irq_chain(up); + if (retval) + return retval; + } + + /* + * Now, initialize the UART + */ + serial_outp(up, UART_LCR, UART_LCR_WLEN8); + + spin_lock_irqsave(&up->port.lock, flags); + if (up->port.flags & ASYNC_FOURPORT) { + if (!is_real_interrupt(up->port.irq)) + up->port.mctrl |= TIOCM_OUT1; + } else + /* + * Most PC uarts need OUT2 raised to enable interrupts. + */ + if (is_real_interrupt(up->port.irq)) + up->port.mctrl |= TIOCM_OUT2; + + serial8250_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + + /* + * Finally, enable interrupts. Note: Modem status interrupts + * are set via change_speed(), which will be occuring imminently + * anyway, so we don't enable them here. + */ + up->ier = UART_IER_RLSI | UART_IER_RDI; + serial_outp(up, UART_IER, up->ier); + + if (up->port.flags & ASYNC_FOURPORT) { + unsigned int icp; + /* + * Enable interrupts on the AST Fourport board + */ + icp = (up->port.iobase & 0xfe0) | 0x01f; + outb_p(0x80, icp); + (void) inb_p(icp); + } + + /* + * And clear the interrupt registers again for luck. + */ + (void) serial_inp(up, UART_LSR); + (void) serial_inp(up, UART_RX); + (void) serial_inp(up, UART_IIR); + (void) serial_inp(up, UART_MSR); + + return 0; +} + +static void serial8250_shutdown(struct uart_port *port) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned long flags; + + /* + * Disable interrupts from this port + */ + up->ier = 0; + serial_outp(up, UART_IER, 0); + + spin_lock_irqsave(&up->port.lock, flags); + if (up->port.flags & ASYNC_FOURPORT) { + /* reset interrupts on the AST Fourport board */ + inb((up->port.iobase & 0xfe0) | 0x1f); + up->port.mctrl |= TIOCM_OUT1; + } else + up->port.mctrl &= ~TIOCM_OUT2; + + serial8250_set_mctrl(&up->port, up->port.mctrl); + spin_unlock_irqrestore(&up->port.lock, flags); + + /* + * Disable break condition and FIFOs + */ + serial_out(up, UART_LCR, serial_inp(up, UART_LCR) & ~UART_LCR_SBC); + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT); + serial_outp(up, UART_FCR, 0); + +#ifdef CONFIG_SERIAL_8250_RSA + /* + * Reset the RSA board back to 115kbps compat mode. + */ + disable_rsa(up); +#endif + + /* + * Read data port to reset things, and then unlink from + * the IRQ chain. + */ + (void) serial_in(up, UART_RX); + + if (!is_real_interrupt(up->port.irq)) + del_timer_sync(&up->timer); + else + serial_unlink_irq_chain(up); +} + +static void +serial8250_change_speed(struct uart_port *port, unsigned int cflag, + unsigned int iflag, unsigned int quot) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned char cval, fcr = 0; + unsigned long flags; + + printk("+++ change_speed port %p cflag %08x quot %d\n", port, cflag, quot); + + switch (cflag & CSIZE) { + case CS5: + cval = 0x00; + break; + case CS6: + cval = 0x01; + break; + case CS7: + cval = 0x02; + break; + default: + case CS8: + cval = 0x03; + break; + } + + if (cflag & CSTOPB) + cval |= 0x04; + if (cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(cflag & PARODD)) + cval |= UART_LCR_EPAR; +#ifdef CMSPAR + if (cflag & CMSPAR) + cval |= UART_LCR_SPAR; +#endif + + /* + * Work around a bug in the Oxford Semiconductor 952 rev B + * chip which causes it to seriously miscalculate baud rates + * when DLL is 0. + */ + if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 && + up->rev == 0x5201) + quot ++; + + if (uart_config[up->port.type].flags & UART_USE_FIFO) { + if ((up->port.uartclk / quot) < (2400 * 16)) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; +#ifdef CONFIG_SERIAL_8250_RSA + else if (up->port.type == PORT_RSA) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14; +#endif + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; + } + if (up->port.type == PORT_16750) + fcr |= UART_FCR7_64BYTE; + + up->port.read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; + if (iflag & IGNPAR) + up->port.read_status_mask |= UART_LSR_FE | UART_LSR_PE; + if (iflag & (BRKINT | PARMRK)) + up->port.read_status_mask |= UART_LSR_BI; + + /* + * Characteres to ignore + */ + up->port.ignore_status_mask = 0; + if (iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; + if (iflag & IGNBRK) { + up->port.ignore_status_mask |= UART_LSR_BI; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (iflag & IGNPAR) + up->port.ignore_status_mask |= UART_LSR_OE; + } + + /* + * ignore all characters if CREAD is not set + */ + if ((cflag & CREAD) == 0) + up->port.ignore_status_mask |= UART_LSR_DR; + + /* + * CTS flow control flag and modem status interrupts + */ + up->ier &= ~UART_IER_MSI; + if (UART_ENABLE_MS(&up->port, cflag)) + up->ier |= UART_IER_MSI; + + /* + * Ok, we're now changing the port state. Do it with + * interrupts disabled. + */ + spin_lock_irqsave(&up->port.lock, flags); + serial_out(up, UART_IER, up->ier); + + if (uart_config[up->port.type].flags & UART_STARTECH) { + serial_outp(up, UART_LCR, 0xBF); + serial_outp(up, UART_EFR, cflag & CRTSCTS ? UART_EFR_CTS :0); + } + serial_outp(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ + serial_outp(up, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_outp(up, UART_DLM, quot >> 8); /* MS of divisor */ + if (up->port.type == PORT_16750) + serial_outp(up, UART_FCR, fcr); /* set fcr */ + serial_outp(up, UART_LCR, cval); /* reset DLAB */ + up->lcr = cval; /* Save LCR */ + if (up->port.type != PORT_16750) { + if (fcr & UART_FCR_ENABLE_FIFO) { + /* emulated UARTs (Lucent Venus 167x) need two steps */ + serial_outp(up, UART_FCR, UART_FCR_ENABLE_FIFO); + } + serial_outp(up, UART_FCR, fcr); /* set fcr */ + } + spin_unlock_irqrestore(&up->port.lock, flags); +} + +static void +serial8250_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + if (state) { + /* sleep */ + if (uart_config[up->port.type].flags & UART_STARTECH) { + /* Arrange to enter sleep mode */ + serial_outp(up, UART_LCR, 0xBF); + serial_outp(up, UART_EFR, UART_EFR_ECB); + serial_outp(up, UART_LCR, 0); + serial_outp(up, UART_IER, UART_IERX_SLEEP); + serial_outp(up, UART_LCR, 0xBF); + serial_outp(up, UART_EFR, 0); + serial_outp(up, UART_LCR, 0); + } + if (up->port.type == PORT_16750) { + /* Arrange to enter sleep mode */ + serial_outp(up, UART_IER, UART_IERX_SLEEP); + } + + if (up->pm) + up->pm(port, state, oldstate); + } else { + /* wake */ + if (uart_config[up->port.type].flags & UART_STARTECH) { + /* Wake up UART */ + serial_outp(up, UART_LCR, 0xBF); + serial_outp(up, UART_EFR, UART_EFR_ECB); + /* + * Turn off LCR == 0xBF so we actually set the IER + * register on the XR16C850 + */ + serial_outp(up, UART_LCR, 0); + serial_outp(up, UART_IER, 0); + /* + * Now reset LCR so we can turn off the ECB bit + */ + serial_outp(up, UART_LCR, 0xBF); + serial_outp(up, UART_EFR, 0); + /* + * For a XR16C850, we need to set the trigger levels + */ + if (up->port.type == PORT_16850) { + unsigned char fctr; + + fctr = serial_inp(up, UART_FCTR) & + ~(UART_FCTR_RX | UART_FCTR_TX); + serial_outp(up, UART_FCTR, fctr | + UART_FCTR_TRGD | + UART_FCTR_RX); + serial_outp(up, UART_TRG, UART_TRG_96); + serial_outp(up, UART_FCTR, fctr | + UART_FCTR_TRGD | + UART_FCTR_TX); + serial_outp(up, UART_TRG, UART_TRG_96); + } + serial_outp(up, UART_LCR, 0); + } + + if (up->port.type == PORT_16750) { + /* Wake up UART */ + serial_outp(up, UART_IER, 0); + } + + if (up->pm) + up->pm(port, state, oldstate); + } +} + +/* + * Resource handling. This is complicated by the fact that resources + * depend on the port type. Maybe we should be claiming the standard + * 8250 ports, and then trying to get other resources as necessary? + */ +static int +serial8250_request_std_resource(struct uart_8250_port *up, struct resource **res) +{ + unsigned int size = 8 << up->port.regshift; + int ret = 0; + + switch (up->port.iotype) { + case SERIAL_IO_MEM: + if (up->port.mapbase) { + *res = request_mem_region(up->port.mapbase, size, "serial"); + if (!*res) + ret = -EBUSY; + } + break; + + case SERIAL_IO_HUB6: + case SERIAL_IO_PORT: + *res = request_region(up->port.iobase, size, "serial"); + if (!*res) + ret = -EBUSY; + break; + } + return ret; +} + +static int +serial8250_request_rsa_resource(struct uart_8250_port *up, struct resource **res) +{ + unsigned int size = 8 << up->port.regshift; + unsigned long start; + int ret = 0; + + switch (up->port.iotype) { + case SERIAL_IO_MEM: + if (up->port.mapbase) { + start = up->port.mapbase; + start += UART_RSA_BASE << up->port.regshift; + *res = request_mem_region(start, size, "serial-rsa"); + if (!*res) + ret = -EBUSY; + } + break; + + case SERIAL_IO_HUB6: + case SERIAL_IO_PORT: + start = up->port.iobase; + start += UART_RSA_BASE << up->port.regshift; + *res = request_region(start, size, "serial-rsa"); + if (!*res) + ret = -EBUSY; + break; + } + + return ret; +} + +static void serial8250_release_port(struct uart_port *port) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + unsigned long start, offset = 0, size = 0; + + if (up->port.type == PORT_RSA) { + offset = UART_RSA_BASE << up->port.regshift; + size = 8; + } + + size <<= up->port.regshift; + + switch (up->port.iotype) { + case SERIAL_IO_MEM: + if (up->port.mapbase) { + /* + * Unmap the area. + */ + iounmap(up->port.membase); + up->port.membase = NULL; + + start = up->port.mapbase; + + if (size) + release_mem_region(start + offset, size); + release_mem_region(start, 8 << up->port.regshift); + } + break; + + case SERIAL_IO_HUB6: + case SERIAL_IO_PORT: + start = up->port.iobase; + + if (size) + release_region(start + offset, size); + release_region(start + offset, 8 << up->port.regshift); + break; + + default: + break; + } +} + +static int serial8250_request_port(struct uart_port *port) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + struct resource *res = NULL, *res_rsa = NULL; + int ret = -EBUSY; + + if (up->port.type == PORT_RSA) { + ret = serial8250_request_rsa_resource(up, &res_rsa); + if (ret) + return ret; + } + + ret = serial8250_request_std_resource(up, &res); + + /* + * If we have a mapbase, then request that as well. + */ + if (res != NULL && up->port.iotype == SERIAL_IO_MEM && + up->port.mapbase) { + int size = res->end - res->start + 1; + + up->port.membase = ioremap(up->port.mapbase, size); + if (!up->port.membase) + ret = -ENOMEM; + } + + if (ret) { + if (res_rsa) + release_resource(res_rsa); + if (res) + release_resource(res); + } + return ret; +} + +static void serial8250_config_port(struct uart_port *port, int flags) +{ + struct uart_8250_port *up = (struct uart_8250_port *)port; + struct resource *res_std = NULL, *res_rsa = NULL; + int probeflags = PROBE_ANY; + int ret; + +#ifdef CONFIG_MCA + /* + * Don't probe for MCA ports on non-MCA machines. + */ + if (up->port.flags & ASYNC_BOOT_ONLYMCA && !MCA_bus) + return; +#endif + + /* + * Find the region that we can probe for. This in turn + * tells us whether we can probe for the type of port. + */ + ret = serial8250_request_std_resource(up, &res_std); + if (ret) + return; + + ret = serial8250_request_rsa_resource(up, &res_rsa); + if (ret) + probeflags &= ~PROBE_RSA; + + if (flags & UART_CONFIG_TYPE) + autoconfig(up, probeflags); + if (up->port.type != PORT_UNKNOWN && flags & UART_CONFIG_IRQ) + autoconfig_irq(up); + + /* + * If the port wasn't an RSA port, release the resource. + */ + if (up->port.type != PORT_RSA && res_rsa) + release_resource(res_rsa); + + if (up->port.type == PORT_UNKNOWN) + release_resource(res_std); +} + +static int +serial8250_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + if (ser->irq >= NR_IRQS || ser->irq < 0 || + ser->baud_base < 9600 || ser->type < PORT_UNKNOWN || + ser->type > PORT_MAX_8250 || ser->type == PORT_CIRRUS || + ser->type == PORT_STARTECH) + return -EINVAL; + return 0; +} + +static const char * +serial8250_type(struct uart_port *port) +{ + int type = port->type; + + if (type >= ARRAY_SIZE(uart_config)) + type = 0; + return uart_config[type].name; +} + +static struct uart_ops serial8250_pops = { + tx_empty: serial8250_tx_empty, + set_mctrl: serial8250_set_mctrl, + get_mctrl: serial8250_get_mctrl, + stop_tx: serial8250_stop_tx, + start_tx: serial8250_start_tx, + stop_rx: serial8250_stop_rx, + enable_ms: serial8250_enable_ms, + break_ctl: serial8250_break_ctl, + startup: serial8250_startup, + shutdown: serial8250_shutdown, + change_speed: serial8250_change_speed, + pm: serial8250_pm, + type: serial8250_type, + release_port: serial8250_release_port, + request_port: serial8250_request_port, + config_port: serial8250_config_port, + verify_port: serial8250_verify_port, +}; + +static struct uart_8250_port serial8250_ports[UART_NR]; + +static void __init serial8250_isa_init_ports(void) +{ + static int first = 1; + int i; + + if (!first) + return; + first = 0; + + for (i = 0; i < ARRAY_SIZE(old_serial_port); i++) { + serial8250_ports[i].port.iobase = old_serial_port[i].port; + serial8250_ports[i].port.irq = irq_cannonicalize(old_serial_port[i].irq); + serial8250_ports[i].port.uartclk = old_serial_port[i].base_baud * 16; + serial8250_ports[i].port.flags = old_serial_port[i].flags; + serial8250_ports[i].port.ops = &serial8250_pops; + } +} + +static void __init serial8250_register_ports(struct uart_driver *drv) +{ + int i; + + serial8250_isa_init_ports(); + + for (i = 0; i < UART_NR; i++) { + serial8250_ports[i].port.line = i; + serial8250_ports[i].port.ops = &serial8250_pops; + init_timer(&serial8250_ports[i].timer); + serial8250_ports[i].timer.function = serial8250_timeout; + uart_add_one_port(drv, &serial8250_ports[i].port); + } +} + +#ifdef CONFIG_SERIAL_8250_CONSOLE + +#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) + +/* + * Wait for transmitter & holding register to empty + */ +static inline void wait_for_xmitr(struct uart_8250_port *up) +{ + unsigned int status, tmout = 10000; + + /* Wait up to 10ms for the character(s) to be sent. */ + do { + status = serial_in(up, UART_LSR); + + if (status & UART_LSR_BI) + up->lsr_break_flag = UART_LSR_BI; + + if (--tmout == 0) + break; + udelay(1); + } while ((status & BOTH_EMPTY) != BOTH_EMPTY); + + /* Wait up to 1s for flow control if necessary */ + if (up->port.flags & ASYNC_CONS_FLOW) { + tmout = 1000000; + while (--tmout && + ((serial_in(up, UART_MSR) & UART_MSR_CTS) == 0)) + udelay(1); + } +} + +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + */ +static void +serial8250_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_8250_port *up = &serial8250_ports[co->index]; + unsigned int ier; + int i; + + /* + * First save the UER then disable the interrupts + */ + ier = serial_in(up, UART_IER); + serial_out(up, UART_IER, 0); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++, s++) { + wait_for_xmitr(up); + + /* + * Send the character out. + * If a LF, also do CR... + */ + serial_out(up, UART_TX, *s); + if (*s == 10) { + wait_for_xmitr(up); + serial_out(up, UART_TX, 13); + } + } + + /* + * Finally, wait for transmitter to become empty + * and restore the IER + */ + wait_for_xmitr(up); + serial_out(up, UART_IER, ier); +} + +static kdev_t serial8250_console_device(struct console *co) +{ + return mk_kdev(TTY_MAJOR, 64 + co->index); +} + +static int __init serial8250_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= UART_NR) + co->index = 0; + port = &serial8250_ports[co->index].port; + printk("+++ index %d port %p iobase %x\n", co->index, port, port->iobase); + + /* + * Temporary fix. + */ + spin_lock_init(&port->lock); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + printk("+++ baud %d bits %d parity %c flow %c\n", baud, parity, bits, flow); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console serial8250_console = { + name: "ttyS", + write: serial8250_console_write, + device: serial8250_console_device, + setup: serial8250_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +void __init serial8250_console_init(void) +{ + serial8250_isa_init_ports(); + register_console(&serial8250_console); +} + +#define SERIAL8250_CONSOLE &serial8250_console +#else +#define SERIAL8250_CONSOLE NULL +#endif + +static struct uart_driver serial8250_reg = { + owner: THIS_MODULE, + driver_name: "serial", +#ifdef CONFIG_DEVFS_FS + dev_name: "tts/%d", +#else + dev_name: "ttyS", +#endif + major: TTY_MAJOR, + minor: 64, + nr: UART_NR, + cons: SERIAL8250_CONSOLE, +}; + +/* + * register_serial and unregister_serial allows for 16x50 serial ports to be + * configured at run-time, to support PCMCIA modems. + */ + +static int __register_serial(struct serial_struct *req, int line) +{ + struct uart_port port; + + port.iobase = req->port; + port.membase = req->iomem_base; + port.irq = req->irq; + port.uartclk = req->baud_base * 16; + port.fifosize = req->xmit_fifo_size; + port.regshift = req->iomem_reg_shift; + port.iotype = req->io_type; + port.flags = req->flags | ASYNC_BOOT_AUTOCONF; + port.line = line; + + if (HIGH_BITS_OFFSET) + port.iobase |= req->port_high << HIGH_BITS_OFFSET; + + /* + * If a clock rate wasn't specified by the low level + * driver, then default to the standard clock rate. + */ + if (port.uartclk == 0) + port.uartclk = BASE_BAUD * 16; + + return uart_register_port(&serial8250_reg, &port); +} + +/** + * register_serial - configure a 16x50 serial port at runtime + * @req: request structure + * + * Configure the serial port specified by the request. If the + * port exists and is in use an error is returned. If the port + * is not currently in the table it is added. + * + * The port is then probed and if neccessary the IRQ is autodetected + * If this fails an error is returned. + * + * On success the port is ready to use and the line number is returned. + */ +int register_serial(struct serial_struct *req) +{ + return __register_serial(req, -1); +} + +int __init early_serial_setup(struct serial_struct *req) +{ + __register_serial(req, req->line); + return 0; +} + +/** + * unregister_serial - remove a 16x50 serial port at runtime + * @line: serial line number + * + * Remove one serial port. This may be called from interrupt + * context. + */ +void unregister_serial(int line) +{ + uart_unregister_port(&serial8250_reg, line); +} + +/* + * This is for ISAPNP only. + */ +void serial8250_get_irq_map(unsigned int *map) +{ + int i; + + for (i = 0; i < UART_NR; i++) { + if (serial8250_ports[i].port.type != PORT_UNKNOWN && + serial8250_ports[i].port.irq < 16) + *map |= 1 << serial8250_ports[i].port.irq; + } +} + +static int __init serial8250_init(void) +{ + int ret, i; + + printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.80 $ " + "IRQ sharing %sabled\n", share_irqs ? "en" : "dis"); + + for (i = 0; i < NR_IRQS; i++) + spin_lock_init(&irq_lists[i].lock); + + ret = uart_register_driver(&serial8250_reg); + if (ret) + return ret; + + serial8250_register_ports(&serial8250_reg); + return 0; +} + +static void __exit serial8250_exit(void) +{ + int i; + + for (i = 0; i < UART_NR; i++) + uart_remove_one_port(&serial8250_reg, &serial8250_ports[i].port); + + uart_unregister_driver(&serial8250_reg); +} + +module_init(serial8250_init); +module_exit(serial8250_exit); + +EXPORT_SYMBOL(register_serial); +EXPORT_SYMBOL(unregister_serial); +EXPORT_SYMBOL(serial8250_get_irq_map); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic 8250/16x50 serial driver $Revision: 1.80 $"); + +MODULE_PARM(share_irqs, "i"); +MODULE_PARM_DESC(share_irqs, "Share IRQs with other non-8250/16x50 devices" + " (unsafe)"); + +#if defined(CONFIG_SERIAL_8250_RSA) && defined(MODULE) +MODULE_PARM(probe_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); +MODULE_PARM_DESC(probe_rsa, "Probe I/O ports for RSA"); +MODULE_PARM(force_rsa, "1-" __MODULE_STRING(PORT_RSA_MAX) "i"); +MODULE_PARM_DESC(force_rsa, "Force I/O ports for RSA"); +#endif diff --git a/drivers/serial/serial_8250.h b/drivers/serial/serial_8250.h new file mode 100644 index 000000000000..1002d1d3d693 --- /dev/null +++ b/drivers/serial/serial_8250.h @@ -0,0 +1,60 @@ +/* + * linux/drivers/char/serial_8250.h + * + * Driver for 8250/16550-type serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright (C) 2001 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * $Id: serial_8250.h,v 1.7 2002/07/06 16:24:46 rmk Exp $ + */ + +#include <linux/config.h> + +struct serial8250_probe { + struct module *owner; + int (*pci_init_one)(struct pci_dev *dev); + void (*pci_remove_one)(struct pci_dev *dev); + void (*pnp_init)(void); +}; + +int serial8250_register_probe(struct serial8250_probe *probe); +void serial8250_unregister_probe(struct serial8250_probe *probe); +void serial8250_get_irq_map(unsigned int *map); + +struct old_serial_port { + unsigned int uart; + unsigned int base_baud; + unsigned int port; + unsigned int irq; + unsigned int flags; +}; + +#undef SERIAL_DEBUG_PCI + +#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486)) +#define SERIAL_INLINE +#endif + +#ifdef SERIAL_INLINE +#define _INLINE_ inline +#else +#define _INLINE_ +#endif + +#define PROBE_RSA (1 << 0) +#define PROBE_ANY (~0) + +#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) + +#ifdef CONFIG_SERIAL_8250_SHARE_IRQ +#define SERIAL8250_SHARE_IRQS 1 +#else +#define SERIAL8250_SHARE_IRQS 0 +#endif diff --git a/drivers/serial/serial_8250_cs.c b/drivers/serial/serial_8250_cs.c new file mode 100644 index 000000000000..216612335008 --- /dev/null +++ b/drivers/serial/serial_8250_cs.c @@ -0,0 +1,719 @@ +/*====================================================================== + + A driver for PCMCIA serial devices + + serial_cs.c 1.123 2000/08/24 18:46:38 + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is David A. Hinds + <dahinds@users.sourceforge.net>. Portions created by David A. Hinds + are Copyright (C) 1999 David A. Hinds. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU General Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/tty.h> +#include <linux/serial.h> +#include <linux/major.h> +#include <linux/tqueue.h> +#include <asm/io.h> +#include <asm/system.h> + +#include <pcmcia/version.h> +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/ciscode.h> +#include <pcmcia/ds.h> +#include <pcmcia/cisreg.h> + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args) +static char *version = "serial_cs.c 1.123 2000/08/24 18:46:38 (David Hinds)"; +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* Bit map of interrupts to choose from */ +static u_int irq_mask = 0xdeb8; +static int irq_list[4] = { -1 }; + +/* Enable the speaker? */ +static int do_sound = 1; + +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM(do_sound, "i"); + +/*====================================================================*/ + +/* Table of multi-port card ID's */ + +struct multi_id { + u_short manfid; + u_short prodid; + int multi; /* 1 = multifunction, > 1 = # ports */ +}; + +static struct multi_id multi_id[] = { + { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 }, + { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 }, + { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 }, + { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 }, + { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 }, + { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 }, + { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 } +}; +#define MULTI_COUNT (sizeof(multi_id)/sizeof(struct multi_id)) + +typedef struct serial_info { + dev_link_t link; + int ndev; + int multi; + int slave; + int manfid; + dev_node_t node[4]; + int line[4]; + struct tq_struct remove; +} serial_info_t; + +static void serial_config(dev_link_t * link); +static int serial_event(event_t event, int priority, + event_callback_args_t * args); + +static dev_info_t dev_info = "serial_cs"; + +static dev_link_t *serial_attach(void); +static void serial_detach(dev_link_t *); + +static dev_link_t *dev_list = NULL; + +/*====================================================================*/ + +static void +cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + +/*====================================================================== + + After a card is removed, do_serial_release() will unregister + the serial device(s), and release the PCMCIA configuration. + +======================================================================*/ + +/* + * This always runs in process context. + */ +static void do_serial_release(void *arg) +{ + struct serial_info *info = arg; + int i; + + DEBUG(0, "serial_release(0x%p)\n", &info->link); + + /* + * Recheck to see if the device is still configured. + */ + if (info->link.state & DEV_CONFIG) { + for (i = 0; i < info->ndev; i++) + unregister_serial(info->line[i]); + + info->link.dev = NULL; + + if (!info->slave) { + CardServices(ReleaseConfiguration, info->link.handle); + CardServices(ReleaseIO, info->link.handle, &info->link.io); + CardServices(ReleaseIRQ, info->link.handle, &info->link.irq); + } + + info->link.state &= ~DEV_CONFIG; + } +} + +/* + * This may be called from IRQ context. + */ +static void serial_remove(dev_link_t *link) +{ + struct serial_info *info = link->priv; + + link->state &= ~DEV_PRESENT; + + /* + * FIXME: Since the card has probably been removed, + * we should call into the serial layer and hang up + * the ports on the card immediately. + */ + + if (link->state & DEV_CONFIG) + schedule_task(&info->remove); +} + +/*====================================================================== + + serial_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + +======================================================================*/ + +static dev_link_t *serial_attach(void) +{ + serial_info_t *info; + client_reg_t client_reg; + dev_link_t *link; + int i, ret; + + DEBUG(0, "serial_attach()\n"); + + /* Create new serial device */ + info = kmalloc(sizeof (*info), GFP_KERNEL); + if (!info) + return NULL; + memset(info, 0, sizeof (*info)); + link = &info->link; + link->priv = info; + + INIT_TQUEUE(&info->remove, do_serial_release, info); + + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.NumPorts1 = 8; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + if (do_sound) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &serial_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + serial_detach(link); + return NULL; + } + + return link; +} + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + +======================================================================*/ + +static void serial_detach(dev_link_t * link) +{ + serial_info_t *info = link->priv; + dev_link_t **linkp; + int ret; + + DEBUG(0, "serial_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp == NULL) + return; + + /* + * Ensure any outstanding scheduled tasks are completed. + */ + flush_scheduled_tasks(); + + /* + * Ensure that the ports have been released. + */ + do_serial_release(info); + + if (link->handle) { + ret = CardServices(DeregisterClient, link->handle); + if (ret != CS_SUCCESS) + cs_error(link->handle, DeregisterClient, ret); + } + + /* Unlink device structure, free bits */ + *linkp = link->next; + kfree(info); +} + +/*====================================================================*/ + +static int setup_serial(serial_info_t * info, ioaddr_t port, int irq) +{ + struct serial_struct serial; + int line; + + memset(&serial, 0, sizeof (serial)); + serial.port = port; + serial.irq = irq; + serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ; + line = register_serial(&serial); + if (line < 0) { + printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04lx," + " irq %d failed\n", (u_long) serial.port, serial.irq); + return -1; + } + + info->line[info->ndev] = line; + sprintf(info->node[info->ndev].dev_name, "ttyS%d", line); + info->node[info->ndev].major = TTY_MAJOR; + info->node[info->ndev].minor = 0x40 + line; + if (info->ndev > 0) + info->node[info->ndev - 1].next = &info->node[info->ndev]; + info->ndev++; + + return 0; +} + +/*====================================================================*/ + +static int +get_tuple(int fn, client_handle_t handle, tuple_t * tuple, cisparse_t * parse) +{ + int i; + i = CardServices(fn, handle, tuple); + if (i != CS_SUCCESS) + return CS_NO_MORE_ITEMS; + i = CardServices(GetTupleData, handle, tuple); + if (i != CS_SUCCESS) + return i; + return CardServices(ParseTuple, handle, tuple, parse); +} + +#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c) +#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c) + +/*====================================================================*/ + +static int simple_config(dev_link_t * link) +{ + static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 }; + client_handle_t handle = link->handle; + serial_info_t *info = link->priv; + tuple_t tuple; + u_char buf[256]; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + config_info_t config; + int i, j, try; + + /* If the card is already configured, look up the port and irq */ + i = CardServices(GetConfigurationInfo, handle, &config); + if ((i == CS_SUCCESS) && (config.Attributes & CONF_VALID_CLIENT)) { + ioaddr_t port = 0; + if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) { + port = config.BasePort2; + info->slave = 1; + } else if ((info->manfid == MANFID_OSITECH) && + (config.NumPorts1 == 0x40)) { + port = config.BasePort1 + 0x28; + info->slave = 1; + } + if (info->slave) + return setup_serial(info, port, config.AssignedIRQ); + } + link->conf.Vcc = config.Vcc; + + /* First pass: look for a config entry that looks normal. */ + tuple.TupleData = (cisdata_t *) buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + /* Two tries: without IO aliases, then with aliases */ + for (try = 0; try < 2; try++) { + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if (i != CS_SUCCESS) + goto next_entry; + if (cf->vpp1.present & (1 << CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + cf->vpp1.param[CISTPL_POWER_VNOM] / 10000; + if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) && + (cf->io.win[0].base != 0)) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.IOAddrLines = (try == 0) ? + 16 : cf->io.flags & CISTPL_IO_LINES_MASK; + i = + CardServices(RequestIO, link->handle, + &link->io); + if (i == CS_SUCCESS) + goto found_port; + } + next_entry: + i = next_tuple(handle, &tuple, &parse); + } + } + + /* Second pass: try to find an entry that isn't picky about + its base address, then try to grab any standard serial port + address, and finally try to get any free port. */ + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if ((i == CS_SUCCESS) && (cf->io.nwin > 0) && + ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) { + link->conf.ConfigIndex = cf->index; + for (j = 0; j < 5; j++) { + link->io.BasePort1 = base[j]; + link->io.IOAddrLines = base[j] ? 16 : 3; + i = CardServices(RequestIO, link->handle, + &link->io); + if (i == CS_SUCCESS) + goto found_port; + } + } + i = next_tuple(handle, &tuple, &parse); + } + + found_port: + if (i != CS_SUCCESS) { + printk(KERN_NOTICE + "serial_cs: no usable port range found, giving up\n"); + cs_error(link->handle, RequestIO, i); + return -1; + } + + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIRQ, i); + link->irq.AssignedIRQ = 0; + } + if (info->multi && (info->manfid == MANFID_3COM)) + link->conf.ConfigIndex &= ~(0x08); + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + return -1; + } + + return setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); +} + +static int multi_config(dev_link_t * link) +{ + client_handle_t handle = link->handle; + serial_info_t *info = link->priv; + tuple_t tuple; + u_char buf[256]; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + int i, base2 = 0; + + tuple.TupleData = (cisdata_t *) buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + + /* First, look for a generic full-sized window */ + link->io.NumPorts1 = info->multi * 8; + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + /* The quad port cards have bad CIS's, so just look for a + window larger than 8 ports and assume it will be right */ + if ((i == CS_SUCCESS) && (cf->io.nwin == 1) && + (cf->io.win[0].len > 8)) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.IOAddrLines = + cf->io.flags & CISTPL_IO_LINES_MASK; + i = CardServices(RequestIO, link->handle, &link->io); + base2 = link->io.BasePort1 + 8; + if (i == CS_SUCCESS) + break; + } + i = next_tuple(handle, &tuple, &parse); + } + + /* If that didn't work, look for two windows */ + if (i != CS_SUCCESS) { + link->io.NumPorts1 = link->io.NumPorts2 = 8; + info->multi = 2; + i = first_tuple(handle, &tuple, &parse); + while (i != CS_NO_MORE_ITEMS) { + if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) { + link->conf.ConfigIndex = cf->index; + link->io.BasePort1 = cf->io.win[0].base; + link->io.BasePort2 = cf->io.win[1].base; + link->io.IOAddrLines = + cf->io.flags & CISTPL_IO_LINES_MASK; + i = + CardServices(RequestIO, link->handle, + &link->io); + base2 = link->io.BasePort2; + if (i == CS_SUCCESS) + break; + } + i = next_tuple(handle, &tuple, &parse); + } + } + + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestIO, i); + return -1; + } + + i = CardServices(RequestIRQ, link->handle, &link->irq); + if (i != CS_SUCCESS) { + printk(KERN_NOTICE + "serial_cs: no usable port range found, giving up\n"); + cs_error(link->handle, RequestIRQ, i); + link->irq.AssignedIRQ = 0; + } + /* Socket Dual IO: this enables irq's for second port */ + if (info->multi && (info->manfid == MANFID_SOCKET)) { + link->conf.Present |= PRESENT_EXT_STATUS; + link->conf.ExtStatus = ESR_REQ_ATTN_ENA; + } + i = CardServices(RequestConfiguration, link->handle, &link->conf); + if (i != CS_SUCCESS) { + cs_error(link->handle, RequestConfiguration, i); + return -1; + } + + setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ); + /* The Nokia cards are not really multiport cards */ + if (info->manfid == MANFID_NOKIA) + return 0; + for (i = 0; i < info->multi - 1; i++) + setup_serial(info, base2 + (8 * i), link->irq.AssignedIRQ); + + return 0; +} + +/*====================================================================== + + serial_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + serial device available to the system. + +======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +void serial_config(dev_link_t * link) +{ + client_handle_t handle = link->handle; + serial_info_t *info = link->priv; + tuple_t tuple; + u_short buf[128]; + cisparse_t parse; + cistpl_cftable_entry_t *cf = &parse.cftable_entry; + int i, last_ret, last_fn; + + DEBUG(0, "serial_config(0x%p)\n", link); + + tuple.TupleData = (cisdata_t *) buf; + tuple.TupleOffset = 0; + tuple.TupleDataMax = 255; + tuple.Attributes = 0; + /* Get configuration register information */ + tuple.DesiredTuple = CISTPL_CONFIG; + last_ret = first_tuple(handle, &tuple, &parse); + if (last_ret != CS_SUCCESS) { + last_fn = ParseTuple; + goto cs_failed; + } + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* Is this a compliant multifunction card? */ + tuple.DesiredTuple = CISTPL_LONGLINK_MFC; + tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK; + info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS); + + /* Is this a multiport card? */ + tuple.DesiredTuple = CISTPL_MANFID; + if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { + info->manfid = le16_to_cpu(buf[0]); + for (i = 0; i < MULTI_COUNT; i++) + if ((info->manfid == multi_id[i].manfid) && + (le16_to_cpu(buf[1]) == multi_id[i].prodid)) + break; + if (i < MULTI_COUNT) + info->multi = multi_id[i].multi; + } + + /* Another check for dual-serial cards: look for either serial or + multifunction cards that ask for appropriate IO port ranges */ + tuple.DesiredTuple = CISTPL_FUNCID; + if ((info->multi == 0) && + ((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) || + (parse.funcid.func == CISTPL_FUNCID_MULTI) || + (parse.funcid.func == CISTPL_FUNCID_SERIAL))) { + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) { + if ((cf->io.nwin == 1) && (cf->io.win[0].len % 8 == 0)) + info->multi = cf->io.win[0].len >> 3; + if ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) && + (cf->io.win[1].len == 8)) + info->multi = 2; + } + } + + if (info->multi > 1) + multi_config(link); + else + simple_config(link); + + if (info->ndev == 0) + goto failed; + + if (info->manfid == MANFID_IBM) { + conf_reg_t reg = { 0, CS_READ, 0x800, 0 }; + CS_CHECK(AccessConfigurationRegister, link->handle, ®); + reg.Action = CS_WRITE; + reg.Value = reg.Value | 1; + CS_CHECK(AccessConfigurationRegister, link->handle, ®); + } + + link->dev = &info->node[0]; + link->state &= ~DEV_CONFIG_PENDING; + return; + + cs_failed: + cs_error(link->handle, last_fn, last_ret); + failed: + do_serial_release(info); +} + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. A CARD_REMOVAL event + also sets some flags to discourage the serial drivers from + talking to the ports. + +======================================================================*/ + +static int +serial_event(event_t event, int priority, event_callback_args_t * args) +{ + dev_link_t *link = args->client_data; + serial_info_t *info = link->priv; + + DEBUG(1, "serial_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + serial_remove(link); + break; + + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + serial_config(link); + break; + + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if ((link->state & DEV_CONFIG) && !info->slave) + CardServices(ReleaseConfiguration, link->handle); + break; + + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (DEV_OK(link) && !info->slave) + CardServices(RequestConfiguration, link->handle, + &link->conf); + break; + } + return 0; +} + +/*====================================================================*/ + +static int __init init_serial_cs(void) +{ + servinfo_t serv; + DEBUG(0, "%s\n", version); + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_NOTICE "serial_cs: Card Services release " + "does not match!\n"); + return -1; + } + register_pccard_driver(&dev_info, &serial_attach, &serial_detach); + return 0; +} + +static void __exit exit_serial_cs(void) +{ + DEBUG(0, "serial_cs: unloading\n"); + unregister_pccard_driver(&dev_info); + while (dev_list != NULL) + serial_detach(dev_list); +} + +module_init(init_serial_cs); +module_exit(exit_serial_cs); + +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_8250_pci.c b/drivers/serial/serial_8250_pci.c new file mode 100644 index 000000000000..5b20507bbbc8 --- /dev/null +++ b/drivers/serial/serial_8250_pci.c @@ -0,0 +1,1138 @@ +/* + * linux/drivers/char/serial_8250_pci.c + * + * Probe module for 8250/16550-type PCI serial ports. + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright (C) 2001 Russell King, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * + * $Id: serial_8250_pci.c,v 1.18 2002/03/10 22:32:08 rmk Exp $ + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/sched.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/serial.h> + +/* 2.4.6 compatibility cruft - to be removed with the old serial.c code */ +#define pci_board __pci_board +#include <linux/serialP.h> +#undef pci_board + +#include <asm/bitops.h> +#include <asm/byteorder.h> +#include <asm/serial.h> + +#include "serial_8250.h" + + +#ifndef IS_PCI_REGION_IOPORT +#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \ + IORESOURCE_IO) +#endif +#ifndef IS_PCI_REGION_IOMEM +#define IS_PCI_REGION_IOMEM(dev, r) (pci_resource_flags((dev), (r)) & \ + IORESOURCE_MEM) +#endif +#ifndef PCI_IRQ_RESOURCE +#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start) +#endif + +#ifndef pci_get_subvendor +#define pci_get_subvendor(dev) ((dev)->subsystem_vendor) +#define pci_get_subdevice(dev) ((dev)->subsystem_device) +#endif + +struct serial_private { + unsigned int nr; + struct pci_board *board; + int line[0]; +}; + +struct pci_board { + int flags; + int num_ports; + int base_baud; + int uart_offset; + int reg_shift; + int (*init_fn)(struct pci_dev *dev, struct pci_board *board, + int enable); + int first_uart_offset; +}; + +static int +get_pci_port(struct pci_dev *dev, struct pci_board *board, + struct serial_struct *req, int idx) +{ + unsigned long port; + int base_idx; + int max_port; + int offset; + + base_idx = SPCI_FL_GET_BASE(board->flags); + if (board->flags & SPCI_FL_BASE_TABLE) + base_idx += idx; + + if (board->flags & SPCI_FL_REGION_SZ_CAP) { + max_port = pci_resource_len(dev, base_idx) / 8; + if (idx >= max_port) + return 1; + } + + offset = board->first_uart_offset; + + /* + * Timedia/SUNIX uses a mixture of BARs and offsets + * Ugh, this is ugly as all hell --- TYT + */ + if (dev->vendor == PCI_VENDOR_ID_TIMEDIA) + switch(idx) { + case 0: + base_idx = 0; + break; + case 1: + base_idx = 0; + offset = 8; + break; + case 2: + base_idx = 1; + break; + case 3: + base_idx = 1; + offset = 8; + break; + case 4: /* BAR 2 */ + case 5: /* BAR 3 */ + case 6: /* BAR 4 */ + case 7: /* BAR 5 */ + base_idx = idx - 2; + } + + /* AFAVLAB uses a different mixture of BARs and offsets */ + /* Not that ugly ;) -- HW */ + if (dev->vendor == PCI_VENDOR_ID_AFAVLAB && idx >= 4) { + base_idx = 4; + offset = (idx - 4) * 8; + } + + /* Some Titan cards are also a little weird */ + if (dev->vendor == PCI_VENDOR_ID_TITAN && + (dev->device == PCI_DEVICE_ID_TITAN_400L || + dev->device == PCI_DEVICE_ID_TITAN_800L)) { + switch (idx) { + case 0: base_idx = 1; + break; + case 1: base_idx = 2; + break; + default: + base_idx = 4; + offset = 8 * (idx - 2); + } + } + + port = pci_resource_start(dev, base_idx) + offset; + + if ((board->flags & SPCI_FL_BASE_TABLE) == 0) + port += idx * (board->uart_offset ? board->uart_offset : 8); + + if (IS_PCI_REGION_IOPORT(dev, base_idx)) { + req->port = port; + if (HIGH_BITS_OFFSET) + req->port_high = port >> HIGH_BITS_OFFSET; + else + req->port_high = 0; + return 0; + } + req->io_type = SERIAL_IO_MEM; + req->iomem_base = ioremap(port, board->uart_offset); + if (req->iomem_base == NULL) + return -ENOMEM; + req->iomem_reg_shift = board->reg_shift; + req->port = 0; + return 0; +} + +static _INLINE_ int +get_pci_irq(struct pci_dev *dev, struct pci_board *board, int idx) +{ + int base_idx; + + if ((board->flags & SPCI_FL_IRQRESOURCE) == 0) + return dev->irq; + + base_idx = SPCI_FL_GET_IRQBASE(board->flags); + if (board->flags & SPCI_FL_IRQ_TABLE) + base_idx += idx; + + return PCI_IRQ_RESOURCE(dev, base_idx); +} + +/* + * Some PCI serial cards using the PLX 9050 PCI interface chip require + * that the card interrupt be explicitly enabled or disabled. This + * seems to be mainly needed on card using the PLX which also use I/O + * mapped memory. + */ +static int __devinit +pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable) +{ + u8 *p, irq_config = 0; + + if (enable) { + irq_config = 0x41; + if (dev->vendor == PCI_VENDOR_ID_PANACOM) + irq_config = 0x43; + if ((dev->vendor == PCI_VENDOR_ID_PLX) && + (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) { + /* + * As the megawolf cards have the int pins active + * high, and have 2 UART chips, both ints must be + * enabled on the 9050. Also, the UARTS are set in + * 16450 mode by default, so we have to enable the + * 16C950 'enhanced' mode so that we can use the + * deep FIFOs + */ + irq_config = 0x5b; + } + } + + /* + * enable/disable interrupts + */ + p = ioremap(pci_resource_start(dev, 0), 0x80); + if (p == NULL) + return -ENOMEM; + writel(irq_config, (unsigned long)p + 0x4c); + + /* + * Read the register back to ensure that it took effect. + */ + readl((unsigned long)p + 0x4c); + iounmap(p); + + return 0; +} + + +/* + * SIIG serial cards have an PCI interface chip which also controls + * the UART clocking frequency. Each UART can be clocked independently + * (except cards equiped with 4 UARTs) and initial clocking settings + * are stored in the EEPROM chip. It can cause problems because this + * version of serial driver doesn't support differently clocked UART's + * on single PCI card. To prevent this, initialization functions set + * high frequency clocking for all UART's on given card. It is safe (I + * hope) because it doesn't touch EEPROM settings to prevent conflicts + * with other OSes (like M$ DOS). + * + * SIIG support added by Andrey Panin <pazke@mail.tp.ru>, 10/1999 + * + * There is two family of SIIG serial cards with different PCI + * interface chip and different configuration methods: + * - 10x cards have control registers in IO and/or memory space; + * - 20x cards have control registers in standard PCI configuration space. + */ + +#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc) +#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8) + +static int __devinit +pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable) +{ + u16 data, *p; + + if (!enable) + return 0; + + switch (dev->device & 0xfff8) { + case PCI_DEVICE_ID_SIIG_1S_10x: /* 1S */ + data = 0xffdf; + break; + case PCI_DEVICE_ID_SIIG_2S_10x: /* 2S, 2S1P */ + data = 0xf7ff; + break; + default: /* 1S1P, 4S */ + data = 0xfffb; + break; + } + + p = ioremap(pci_resource_start(dev, 0), 0x80); + if (p == NULL) + return -ENOMEM; + + writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28); + iounmap(p); + return 0; +} + +#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc) +#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc) + +static int __devinit +pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable) +{ + u8 data; + + if (!enable) + return 0; + + /* Change clock frequency for the first UART. */ + pci_read_config_byte(dev, 0x6f, &data); + pci_write_config_byte(dev, 0x6f, data & 0xef); + + /* If this card has 2 UART, we have to do the same with second UART. */ + if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) || + ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) { + pci_read_config_byte(dev, 0x73, &data); + pci_write_config_byte(dev, 0x73, data & 0xef); + } + return 0; +} + +/* Added for EKF Intel i960 serial boards */ +static int __devinit +pci_inteli960ni_fn(struct pci_dev *dev, struct pci_board *board, int enable) +{ + unsigned long oldval; + + if (!(pci_get_subdevice(dev) & 0x1000)) + return -ENODEV; + + if (!enable) /* is there something to deinit? */ + return 0; + + /* is firmware started? */ + pci_read_config_dword(dev, 0x44, (void*) &oldval); + if (oldval == 0x00001000L) { /* RESET value */ + printk(KERN_DEBUG "Local i960 firmware missing"); + return -ENODEV; + } + return 0; +} + +/* + * Timedia has an explosion of boards, and to avoid the PCI table from + * growing *huge*, we use this function to collapse some 70 entries + * in the PCI table into one, for sanity's and compactness's sake. + */ +static unsigned short timedia_single_port[] = { + 0x4025, 0x4027, 0x4028, 0x5025, 0x5027, 0 +}; + +static unsigned short timedia_dual_port[] = { + 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085, + 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, + 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, + 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079, + 0xD079, 0 +}; + +static unsigned short timedia_quad_port[] = { + 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, + 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, + 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056, + 0xB157, 0 +}; + +static unsigned short timedia_eight_port[] = { + 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, + 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 +}; + +static struct timedia_struct { + int num; + unsigned short *ids; +} timedia_data[] = { + { 1, timedia_single_port }, + { 2, timedia_dual_port }, + { 4, timedia_quad_port }, + { 8, timedia_eight_port }, + { 0, 0 } +}; + +static int __devinit +pci_timedia_fn(struct pci_dev *dev, struct pci_board *board, int enable) +{ + int i, j; + unsigned short *ids; + + if (!enable) + return 0; + + for (i = 0; timedia_data[i].num; i++) { + ids = timedia_data[i].ids; + for (j = 0; ids[j]; j++) { + if (pci_get_subdevice(dev) == ids[j]) { + board->num_ports = timedia_data[i].num; + return 0; + } + } + } + return 0; +} + +static int __devinit +pci_xircom_fn(struct pci_dev *dev, struct pci_board *board, int enable) +{ + __set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/10); + return 0; +} + +/* + * This is the configuration table for all of the PCI serial boards + * which we support. It is directly indexed by the pci_board_num_t enum + * value, which is encoded in the pci_device_id PCI probe table's + * driver_data member. + */ +enum pci_board_num_t { + pbn_b0_1_115200, + pbn_default = 0, + + pbn_b0_2_115200, + pbn_b0_4_115200, + + pbn_b0_1_921600, + pbn_b0_2_921600, + pbn_b0_4_921600, + + pbn_b0_bt_1_115200, + pbn_b0_bt_2_115200, + pbn_b0_bt_8_115200, + pbn_b0_bt_1_460800, + pbn_b0_bt_2_460800, + + pbn_b1_1_115200, + pbn_b1_2_115200, + pbn_b1_4_115200, + pbn_b1_8_115200, + + pbn_b1_2_921600, + pbn_b1_4_921600, + pbn_b1_8_921600, + + pbn_b1_2_1382400, + pbn_b1_4_1382400, + pbn_b1_8_1382400, + + pbn_b2_8_115200, + pbn_b2_4_460800, + pbn_b2_8_460800, + pbn_b2_16_460800, + pbn_b2_4_921600, + pbn_b2_8_921600, + + pbn_b2_bt_1_115200, + pbn_b2_bt_2_115200, + pbn_b2_bt_4_115200, + pbn_b2_bt_2_921600, + + pbn_panacom, + pbn_panacom2, + pbn_panacom4, + pbn_plx_romulus, + pbn_oxsemi, + pbn_timedia, + pbn_intel_i960, + pbn_sgi_ioc3, + pbn_nec_nile4, + + pbn_dci_pccom4, + pbn_dci_pccom8, + + pbn_xircom_combo, + + pbn_siig10x_0, + pbn_siig10x_1, + pbn_siig10x_2, + pbn_siig10x_4, + pbn_siig20x_0, + pbn_siig20x_2, + pbn_siig20x_4, + + pbn_computone_4, + pbn_computone_6, + pbn_computone_8, +}; + +static struct pci_board pci_boards[] __devinitdata = { + /* + * PCI Flags, Number of Ports, Base (Maximum) Baud Rate, + * Offset to get to next UART's registers, + * Register shift to use for memory-mapped I/O, + * Initialization function, first UART offset + */ + + /* Generic serial board, pbn_b0_1_115200, pbn_default */ + { SPCI_FL_BASE0, 1, 115200 }, /* pbn_b0_1_115200, + pbn_default */ + + { SPCI_FL_BASE0, 2, 115200 }, /* pbn_b0_2_115200 */ + { SPCI_FL_BASE0, 4, 115200 }, /* pbn_b0_4_115200 */ + + { SPCI_FL_BASE0, 1, 921600 }, /* pbn_b0_1_921600 */ + { SPCI_FL_BASE0, 2, 921600 }, /* pbn_b0_2_921600 */ + { SPCI_FL_BASE0, 4, 921600 }, /* pbn_b0_4_921600 */ + + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b0_bt_1_115200 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b0_bt_2_115200 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 8, 115200 }, /* pbn_b0_bt_8_115200 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 }, /* pbn_b0_bt_1_460800 */ + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 }, /* pbn_b0_bt_2_460800 */ + + { SPCI_FL_BASE1, 1, 115200 }, /* pbn_b1_1_115200 */ + { SPCI_FL_BASE1, 2, 115200 }, /* pbn_b1_2_115200 */ + { SPCI_FL_BASE1, 4, 115200 }, /* pbn_b1_4_115200 */ + { SPCI_FL_BASE1, 8, 115200 }, /* pbn_b1_8_115200 */ + + { SPCI_FL_BASE1, 2, 921600 }, /* pbn_b1_2_921600 */ + { SPCI_FL_BASE1, 4, 921600 }, /* pbn_b1_4_921600 */ + { SPCI_FL_BASE1, 8, 921600 }, /* pbn_b1_8_921600 */ + + { SPCI_FL_BASE1, 2, 1382400 }, /* pbn_b1_2_1382400 */ + { SPCI_FL_BASE1, 4, 1382400 }, /* pbn_b1_4_1382400 */ + { SPCI_FL_BASE1, 8, 1382400 }, /* pbn_b1_8_1382400 */ + + { SPCI_FL_BASE2, 8, 115200 }, /* pbn_b2_8_115200 */ + { SPCI_FL_BASE2, 4, 460800 }, /* pbn_b2_4_460800 */ + { SPCI_FL_BASE2, 8, 460800 }, /* pbn_b2_8_460800 */ + { SPCI_FL_BASE2, 16, 460800 }, /* pbn_b2_16_460800 */ + { SPCI_FL_BASE2, 4, 921600 }, /* pbn_b2_4_921600 */ + { SPCI_FL_BASE2, 8, 921600 }, /* pbn_b2_8_921600 */ + + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 }, /* pbn_b2_bt_1_115200 */ + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 }, /* pbn_b2_bt_2_115200 */ + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 }, /* pbn_b2_bt_4_115200 */ + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 }, /* pbn_b2_bt_2_921600 */ + + { SPCI_FL_BASE2, 2, 921600, /* IOMEM */ /* pbn_panacom */ + 0x400, 7, pci_plx9050_fn }, + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_panacom2 */ + 0x400, 7, pci_plx9050_fn }, + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_panacom4 */ + 0x400, 7, pci_plx9050_fn }, + { SPCI_FL_BASE2, 4, 921600, /* pbn_plx_romulus */ + 0x20, 2, pci_plx9050_fn, 0x03 }, + /* This board uses the size of PCI Base region 0 to + * signal now many ports are available */ + { SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 }, /* pbn_oxsemi */ + { SPCI_FL_BASE_TABLE, 1, 921600, /* pbn_timedia */ + 0, 0, pci_timedia_fn }, + /* EKF addition for i960 Boards form EKF with serial port */ + { SPCI_FL_BASE0, 32, 921600, /* max 256 ports */ /* pbn_intel_i960 */ + 8<<2, 2, pci_inteli960ni_fn, 0x10000}, + { SPCI_FL_BASE0 | SPCI_FL_IRQRESOURCE, /* pbn_sgi_ioc3 */ + 1, 458333, 0, 0, 0, 0x20178 }, + + /* + * NEC Vrc-5074 (Nile 4) builtin UART. + */ + { SPCI_FL_BASE0, 1, 520833, /* pbn_nec_nile4 */ + 64, 3, NULL, 0x300 }, + + { SPCI_FL_BASE3, 4, 115200, 8 }, /* pbn_dci_pccom4 */ + { SPCI_FL_BASE3, 8, 115200, 8 }, /* pbn_dci_pccom8 */ + + { SPCI_FL_BASE0, 1, 115200, /* pbn_xircom_combo */ + 0, 0, pci_xircom_fn }, + + { SPCI_FL_BASE2, 1, 460800, /* pbn_siig10x_0 */ + 0, 0, pci_siig10x_fn }, + { SPCI_FL_BASE2, 1, 921600, /* pbn_siig10x_1 */ + 0, 0, pci_siig10x_fn }, + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siig10x_2 */ + 0, 0, pci_siig10x_fn }, + { SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siig10x_4 */ + 0, 0, pci_siig10x_fn }, + { SPCI_FL_BASE0, 1, 921600, /* pbn_siix20x_0 */ + 0, 0, pci_siig20x_fn }, + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600, /* pbn_siix20x_2 */ + 0, 0, pci_siig20x_fn }, + { SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600, /* pbn_siix20x_4 */ + 0, 0, pci_siig20x_fn }, + + { SPCI_FL_BASE0, 4, 921600, /* IOMEM */ /* pbn_computone_4 */ + 0x40, 2, NULL, 0x200 }, + { SPCI_FL_BASE0, 6, 921600, /* IOMEM */ /* pbn_computone_6 */ + 0x40, 2, NULL, 0x200 }, + { SPCI_FL_BASE0, 8, 921600, /* IOMEM */ /* pbn_computone_8 */ + 0x40, 2, NULL, 0x200 }, +}; + +/* + * Given a complete unknown PCI device, try to use some heuristics to + * guess what the configuration might be, based on the pitiful PCI + * serial specs. Returns 0 on success, 1 on failure. + */ +static int __devinit +serial_pci_guess_board(struct pci_dev *dev, struct pci_board *board) +{ + int num_iomem = 0, num_port = 0, first_port = -1; + int i; + + /* + * If it is not a communications device or the programming + * interface is greater than 6, give up. + * + * (Should we try to make guesses for multiport serial devices + * later?) + */ + if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) && + ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || + (dev->class & 0xff) > 6) + return 1; + + for (i = 0; i < 6; i++) { + if (IS_PCI_REGION_IOPORT(dev, i)) { + num_port++; + if (first_port == -1) + first_port = i; + } + if (IS_PCI_REGION_IOMEM(dev, i)) + num_iomem++; + } + + /* + * If there is 1 or 0 iomem regions, and exactly one port, use + * it. + */ + if (num_iomem <= 1 && num_port == 1) { + board->flags = first_port; + return 0; + } + return 1; +} + +/* + * return an error code to refuse. + * + * serial_struct is 60 bytes. + */ +static int __devinit pci_init_one(struct pci_dev *dev, const struct pci_device_id *ent) +{ + struct serial_private *priv; + struct pci_board *board, tmp; + struct serial_struct serial_req; + int base_baud, rc, k; + + if (ent->driver_data >= ARRAY_SIZE(pci_boards)) { + printk(KERN_ERR "pci_init_one: invalid driver_data: %ld\n", + ent->driver_data); + return -EINVAL; + } + + board = &pci_boards[ent->driver_data]; + + rc = pci_enable_device(dev); + if (rc) + return rc; + + if (ent->driver_data == pbn_default && + serial_pci_guess_board(dev, board)) + return -ENODEV; + else if (serial_pci_guess_board(dev, &tmp) == 0) { + printk(KERN_INFO "Redundant entry in serial pci_table. " + "Please send the output of\n" + "lspci -vv, this message (%d,%d,%d,%d)\n" + "and the manufacturer and name of " + "serial board or modem board\n" + "to serial-pci-info@lists.sourceforge.net.\n", + dev->vendor, dev->device, + pci_get_subvendor(dev), pci_get_subdevice(dev)); + } + + priv = kmalloc(sizeof(struct serial_private) + + sizeof(unsigned int) * board->num_ports, + GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* + * Run the initialization function, if any + */ + if (board->init_fn) { + rc = board->init_fn(dev, board, 1); + if (rc != 0) { + kfree(priv); + return rc; + } + } + + base_baud = board->base_baud; + if (!base_baud) + base_baud = BASE_BAUD; + memset(&serial_req, 0, sizeof(serial_req)); + for (k = 0; k < board->num_ports; k++) { + serial_req.irq = get_pci_irq(dev, board, k); + if (get_pci_port(dev, board, &serial_req, k)) + break; +#ifdef SERIAL_DEBUG_PCI + printk("Setup PCI/PNP port: port %x, irq %d, type %d\n", + serial_req.port, serial_req.irq, serial_req.io_type); +#endif + serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; + serial_req.baud_base = base_baud; + + priv->line[k] = register_serial(&serial_req); + if (priv->line[k] < 0) + break; + } + + priv->board = board; + priv->nr = k; + + pci_set_drvdata(dev, priv); + + return 0; +} + +static void __devexit pci_remove_one(struct pci_dev *dev) +{ + struct serial_private *priv = pci_get_drvdata(dev); + int i; + + pci_set_drvdata(dev, NULL); + + if (priv) { + for (i = 0; i < priv->nr; i++) + unregister_serial(priv->line[i]); + + priv->board->init_fn(dev, priv->board, 0); + + pci_disable_device(dev); + + kfree(priv); + } +} + +static struct pci_device_id serial_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, + pbn_b1_8_1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0, + pbn_b1_4_1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0, + pbn_b1_2_1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232, 0, 0, + pbn_b1_8_1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232, 0, 0, + pbn_b1_4_1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232, 0, 0, + pbn_b1_2_1382400 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485, 0, 0, + pbn_b1_8_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4, 0, 0, + pbn_b1_8_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485, 0, 0, + pbn_b1_4_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2, 0, 0, + pbn_b1_4_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485, 0, 0, + pbn_b1_2_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6, 0, 0, + pbn_b1_8_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1, 0, 0, + pbn_b1_8_921600 }, + { PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V351, + PCI_SUBVENDOR_ID_CONNECT_TECH, + PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1, 0, 0, + pbn_b1_4_921600 }, + + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_1_115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_4_115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_4_115200 }, + { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_8_115200 }, + + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_115200 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_921600 }, + /* VScom SPCOM800, from sl@s.pl */ + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_8_921600 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_4_921600 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_KEYSPAN, + PCI_SUBDEVICE_ID_KEYSPAN_SX2, 0, 0, + pbn_panacom }, + { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_panacom4 }, + { PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_panacom2 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, + pbn_b2_4_460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, + pbn_b2_8_460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, + pbn_b2_16_460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIFAST, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, + pbn_b2_16_460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIRAS, + PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, + pbn_b2_4_460800 }, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, + PCI_SUBVENDOR_ID_CHASE_PCIRAS, + PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, + pbn_b2_8_460800 }, + /* Megawolf Romulus PCI Serial Card, from Mike Hudson */ + /* (Exoray@isys.ca) */ + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_ROMULUS, + 0x10b5, 0x106a, 0, 0, + pbn_plx_romulus }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_4_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_2_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_8_115200 }, + { PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_8_115200 }, + { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_115200 }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_2_115200 }, + + /* Digitan DS560-558, from jimd@esoft.com */ + { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b1_1_115200 }, + + /* 3Com US Robotics 56k Voice Internal PCI model 5610 */ + { PCI_VENDOR_ID_USR, 0x1008, + PCI_ANY_ID, PCI_ANY_ID, }, + + /* Titan Electronic cards */ + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_1_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_2_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_4_921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1, 1, 921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200L, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE1 | SPCI_FL_BASE_TABLE, 2, 921600 }, + /* The 400L and 800L have a custom hack in get_pci_port */ + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400L, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE_TABLE, 4, 921600 }, + { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800L, + PCI_ANY_ID, PCI_ANY_ID, + SPCI_FL_BASE_TABLE, 8, 921600 }, + + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_1 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_1 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_1 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_4 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_4 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig10x_4 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_0 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_2 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_4 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_4 }, + { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_siig20x_4 }, + + /* Computone devices submitted by Doug McNash dmcnash@computone.com */ + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4, + 0, 0, pbn_computone_4 }, + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8, + 0, 0, pbn_computone_8 }, + { PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG, + PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6, + 0, 0, pbn_computone_6 }, + + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_oxsemi }, + { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, + PCI_VENDOR_ID_TIMEDIA, PCI_ANY_ID, 0, 0, pbn_timedia }, + + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_115200 }, + /* AFAVLAB serial card, from Harald Welte <laforge@gnumonks.org> */ + { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_P028, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_8_115200 }, + + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_115200 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_2_460800 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_1_115200 }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b0_bt_1_460800 }, + + /* RAStel 2 port modem, gerg@moreton.com.au */ + { PCI_VENDOR_ID_MORETON, PCI_DEVICE_ID_RASTEL_2PORT, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_b2_bt_2_115200 }, + + /* EKF addition for i960 Boards form EKF with serial port */ + { PCI_VENDOR_ID_INTEL, 0x1960, + 0xE4BF, PCI_ANY_ID, 0, 0, + pbn_intel_i960 }, + + /* Xircom Cardbus/Ethernet combos */ + { PCI_VENDOR_ID_XIRCOM, PCI_DEVICE_ID_XIRCOM_X3201_MDM, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_xircom_combo }, + + /* + * Untested PCI modems, sent in from various folks... + */ + + /* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */ + { PCI_VENDOR_ID_ROCKWELL, 0x1004, + 0x1048, 0x1500, 0, 0, + pbn_b1_1_115200 }, + + { PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC3, + 0xFF00, 0, 0, 0, + pbn_sgi_ioc3 }, + + /* + * NEC Vrc-5074 (Nile 4) builtin UART. + */ + { PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_nec_nile4 }, + + { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM4, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_dci_pccom4 }, + { PCI_VENDOR_ID_DCI, PCI_DEVICE_ID_DCI_PCCOM8, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, + pbn_dci_pccom8 }, + + { PCI_ANY_ID, PCI_ANY_ID, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_SERIAL << 8, + 0xffff00, }, + { PCI_ANY_ID, PCI_ANY_ID, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MODEM << 8, + 0xffff00, }, + { PCI_ANY_ID, PCI_ANY_ID, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, + 0xffff00, }, + { 0, } +}; + +#ifndef __devexit_p +#if defined(MODULE) || defined(CONFIG_HOTPLUG) +#define __devexit_p(x) x +#else +#define __devexit_p(x) NULL +#endif +#endif + +static struct pci_driver serial_pci_driver = { + name: "serial", + probe: pci_init_one, + remove: __devexit_p(pci_remove_one), + id_table: serial_pci_tbl, +}; + +static int __init serial8250_pci_init(void) +{ + return pci_module_init(&serial_pci_driver); +} + +static void __exit serial8250_pci_exit(void) +{ + pci_unregister_driver(&serial_pci_driver); +} + +module_init(serial8250_pci_init); +module_exit(serial8250_pci_exit); + +EXPORT_NO_SYMBOLS; + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic 8250/16x50 PCI serial probe module"); +MODULE_DEVICE_TABLE(pci, serial_pci_tbl); diff --git a/drivers/serial/serial_8250_pnp.c b/drivers/serial/serial_8250_pnp.c new file mode 100644 index 000000000000..37159599913f --- /dev/null +++ b/drivers/serial/serial_8250_pnp.c @@ -0,0 +1,548 @@ +/* + * linux/drivers/char/serial_8250_pnp.c + * + * Probe module for 8250/16550-type ISAPNP serial ports. + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright (C) 2001 Russell King, All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License. + * + * $Id: serial_8250_pnp.c,v 1.9 2002/02/18 19:20:29 rmk Exp $ + */ +#include <linux/module.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/isapnp.h> +#include <linux/string.h> +#include <linux/kernel.h> +#include <linux/serial.h> +#include <linux/serialP.h> + +#include <asm/bitops.h> +#include <asm/byteorder.h> +#include <asm/serial.h> + +#include "serial_8250.h" + +struct pnpbios_device_id +{ + char id[8]; + unsigned long driver_data; +}; + +static const struct pnpbios_device_id pnp_dev_table[] = { + /* Archtek America Corp. */ + /* Archtek SmartLink Modem 3334BT Plug & Play */ + { "AAC000F", 0 }, + /* Anchor Datacomm BV */ + /* SXPro 144 External Data Fax Modem Plug & Play */ + { "ADC0001", 0 }, + /* SXPro 288 External Data Fax Modem Plug & Play */ + { "ADC0002", 0 }, + /* Rockwell 56K ACF II Fax+Data+Voice Modem */ + { "AKY1021", SPCI_FL_NO_SHIRQ }, + /* AZT3005 PnP SOUND DEVICE */ + { "AZT4001", 0 }, + /* Best Data Products Inc. Smart One 336F PnP Modem */ + { "BDP3336", 0 }, + /* Boca Research */ + /* Boca Complete Ofc Communicator 14.4 Data-FAX */ + { "BRI0A49", 0 }, + /* Boca Research 33,600 ACF Modem */ + { "BRI1400", 0 }, + /* Boca 33.6 Kbps Internal FD34FSVD */ + { "BRI3400", 0 }, + /* Boca 33.6 Kbps Internal FD34FSVD */ + { "BRI0A49", 0 }, + /* Best Data Products Inc. Smart One 336F PnP Modem */ + { "BDP3336", 0 }, + /* Computer Peripherals Inc */ + /* EuroViVa CommCenter-33.6 SP PnP */ + { "CPI4050", 0 }, + /* Creative Labs */ + /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */ + { "CTL3001", 0 }, + /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */ + { "CTL3011", 0 }, + /* Creative */ + /* Creative Modem Blaster Flash56 DI5601-1 */ + { "DMB1032", 0 }, + /* Creative Modem Blaster V.90 DI5660 */ + { "DMB2001", 0 }, + /* FUJITSU */ + /* Fujitsu 33600 PnP-I2 R Plug & Play */ + { "FUJ0202", 0 }, + /* Fujitsu FMV-FX431 Plug & Play */ + { "FUJ0205", 0 }, + /* Fujitsu 33600 PnP-I4 R Plug & Play */ + { "FUJ0206", 0 }, + /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */ + { "FUJ0209", 0 }, + /* Archtek America Corp. */ + /* Archtek SmartLink Modem 3334BT Plug & Play */ + { "GVC000F", 0 }, + /* Hayes */ + /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */ + { "HAY0001", 0 }, + /* Hayes Optima 336 V.34 + FAX + Voice PnP */ + { "HAY000C", 0 }, + /* Hayes Optima 336B V.34 + FAX + Voice PnP */ + { "HAY000D", 0 }, + /* Hayes Accura 56K Ext Fax Modem PnP */ + { "HAY5670", 0 }, + /* Hayes Accura 56K Ext Fax Modem PnP */ + { "HAY5674", 0 }, + /* Hayes Accura 56K Fax Modem PnP */ + { "HAY5675", 0 }, + /* Hayes 288, V.34 + FAX */ + { "HAYF000", 0 }, + /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */ + { "HAYF001", 0 }, + /* IBM */ + /* IBM Thinkpad 701 Internal Modem Voice */ + { "IBM0033", 0 }, + /* Intertex */ + /* Intertex 28k8 33k6 Voice EXT PnP */ + { "IXDC801", 0 }, + /* Intertex 33k6 56k Voice EXT PnP */ + { "IXDC901", 0 }, + /* Intertex 28k8 33k6 Voice SP EXT PnP */ + { "IXDD801", 0 }, + /* Intertex 33k6 56k Voice SP EXT PnP */ + { "IXDD901", 0 }, + /* Intertex 28k8 33k6 Voice SP INT PnP */ + { "IXDF401", 0 }, + /* Intertex 28k8 33k6 Voice SP EXT PnP */ + { "IXDF801", 0 }, + /* Intertex 33k6 56k Voice SP EXT PnP */ + { "IXDF901", 0 }, + /* Kortex International */ + /* KORTEX 28800 Externe PnP */ + { "KOR4522", 0 }, + /* KXPro 33.6 Vocal ASVD PnP */ + { "KORF661", 0 }, + /* Lasat */ + /* LASAT Internet 33600 PnP */ + { "LAS4040", 0 }, + /* Lasat Safire 560 PnP */ + { "LAS4540", 0 }, + /* Lasat Safire 336 PnP */ + { "LAS5440", 0 }, + /* Microcom, Inc. */ + /* Microcom TravelPorte FAST V.34 Plug & Play */ + { "MNP0281", 0 }, + /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */ + { "MNP0336", 0 }, + /* Microcom DeskPorte FAST EP 28.8 Plug & Play */ + { "MNP0339", 0 }, + /* Microcom DeskPorte 28.8P Plug & Play */ + { "MNP0342", 0 }, + /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ + { "MNP0500", 0 }, + /* Microcom DeskPorte FAST ES 28.8 Plug & Play */ + { "MNP0501", 0 }, + /* Microcom DeskPorte 28.8S Internal Plug & Play */ + { "MNP0502", 0 }, + /* Motorola */ + /* Motorola BitSURFR Plug & Play */ + { "MOT1105", 0 }, + /* Motorola TA210 Plug & Play */ + { "MOT1111", 0 }, + /* Motorola HMTA 200 (ISDN) Plug & Play */ + { "MOT1114", 0 }, + /* Motorola BitSURFR Plug & Play */ + { "MOT1115", 0 }, + /* Motorola Lifestyle 28.8 Internal */ + { "MOT1190", 0 }, + /* Motorola V.3400 Plug & Play */ + { "MOT1501", 0 }, + /* Motorola Lifestyle 28.8 V.34 Plug & Play */ + { "MOT1502", 0 }, + /* Motorola Power 28.8 V.34 Plug & Play */ + { "MOT1505", 0 }, + /* Motorola ModemSURFR External 28.8 Plug & Play */ + { "MOT1509", 0 }, + /* Motorola Premier 33.6 Desktop Plug & Play */ + { "MOT150A", 0 }, + /* Motorola VoiceSURFR 56K External PnP */ + { "MOT150F", 0 }, + /* Motorola ModemSURFR 56K External PnP */ + { "MOT1510", 0 }, + /* Motorola ModemSURFR 56K Internal PnP */ + { "MOT1550", 0 }, + /* Motorola ModemSURFR Internal 28.8 Plug & Play */ + { "MOT1560", 0 }, + /* Motorola Premier 33.6 Internal Plug & Play */ + { "MOT1580", 0 }, + /* Motorola OnlineSURFR 28.8 Internal Plug & Play */ + { "MOT15B0", 0 }, + /* Motorola VoiceSURFR 56K Internal PnP */ + { "MOT15F0", 0 }, + /* Com 1 */ + /* Deskline K56 Phone System PnP */ + { "MVX00A1", 0 }, + /* PC Rider K56 Phone System PnP */ + { "MVX00F2", 0 }, + /* Pace 56 Voice Internal Plug & Play Modem */ + { "PMC2430", 0 }, + /* Generic */ + /* Generic standard PC COM port */ + { "PNP0500", 0 }, + /* Generic 16550A-compatible COM port */ + { "PNP0501", 0 }, + /* Compaq 14400 Modem */ + { "PNPC000", 0 }, + /* Compaq 2400/9600 Modem */ + { "PNPC001", 0 }, + /* Dial-Up Networking Serial Cable between 2 PCs */ + { "PNPC031", 0 }, + /* Dial-Up Networking Parallel Cable between 2 PCs */ + { "PNPC032", 0 }, + /* Standard 9600 bps Modem */ + { "PNPC100", 0 }, + /* Standard 14400 bps Modem */ + { "PNPC101", 0 }, + /* Standard 28800 bps Modem*/ + { "PNPC102", 0 }, + /* Standard Modem*/ + { "PNPC103", 0 }, + /* Standard 9600 bps Modem*/ + { "PNPC104", 0 }, + /* Standard 14400 bps Modem*/ + { "PNPC105", 0 }, + /* Standard 28800 bps Modem*/ + { "PNPC106", 0 }, + /* Standard Modem */ + { "PNPC107", 0 }, + /* Standard 9600 bps Modem */ + { "PNPC108", 0 }, + /* Standard 14400 bps Modem */ + { "PNPC109", 0 }, + /* Standard 28800 bps Modem */ + { "PNPC10A", 0 }, + /* Standard Modem */ + { "PNPC10B", 0 }, + /* Standard 9600 bps Modem */ + { "PNPC10C", 0 }, + /* Standard 14400 bps Modem */ + { "PNPC10D", 0 }, + /* Standard 28800 bps Modem */ + { "PNPC10E", 0 }, + /* Standard Modem */ + { "PNPC10F", 0 }, + /* Standard PCMCIA Card Modem */ + { "PNP2000", 0 }, + /* Rockwell */ + /* Modular Technology */ + /* Rockwell 33.6 DPF Internal PnP */ + /* Modular Technology 33.6 Internal PnP */ + { "ROK0030", 0 }, + /* Kortex International */ + /* KORTEX 14400 Externe PnP */ + { "ROK0100", 0 }, + /* Viking Components, Inc */ + /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */ + { "ROK4920", 0 }, + /* Rockwell */ + /* British Telecom */ + /* Modular Technology */ + /* Rockwell 33.6 DPF External PnP */ + /* BT Prologue 33.6 External PnP */ + /* Modular Technology 33.6 External PnP */ + { "RSS00A0", 0 }, + /* Viking 56K FAX INT */ + { "RSS0262", 0 }, + /* SupraExpress 28.8 Data/Fax PnP modem */ + { "SUP1310", 0 }, + /* SupraExpress 33.6 Data/Fax PnP modem */ + { "SUP1421", 0 }, + /* SupraExpress 33.6 Data/Fax PnP modem */ + { "SUP1590", 0 }, + /* SupraExpress 33.6 Data/Fax PnP modem */ + { "SUP1760", 0 }, + /* Phoebe Micro */ + /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */ + { "TEX0011", 0 }, + /* Archtek America Corp. */ + /* Archtek SmartLink Modem 3334BT Plug & Play */ + { "UAC000F", 0 }, + /* 3Com Corp. */ + /* Gateway Telepath IIvi 33.6 */ + { "USR0000", 0 }, + /* Sportster Vi 14.4 PnP FAX Voicemail */ + { "USR0004", 0 }, + /* U.S. Robotics 33.6K Voice INT PnP */ + { "USR0006", 0 }, + /* U.S. Robotics 33.6K Voice EXT PnP */ + { "USR0007", 0 }, + /* U.S. Robotics 33.6K Voice INT PnP */ + { "USR2002", 0 }, + /* U.S. Robotics 56K Voice INT PnP */ + { "USR2070", 0 }, + /* U.S. Robotics 56K Voice EXT PnP */ + { "USR2080", 0 }, + /* U.S. Robotics 56K FAX INT */ + { "USR3031", 0 }, + /* U.S. Robotics 56K Voice INT PnP */ + { "USR3070", 0 }, + /* U.S. Robotics 56K Voice EXT PnP */ + { "USR3080", 0 }, + /* U.S. Robotics 56K Voice INT PnP */ + { "USR3090", 0 }, + /* U.S. Robotics 56K Message */ + { "USR9100", 0 }, + /* U.S. Robotics 56K FAX EXT PnP*/ + { "USR9160", 0 }, + /* U.S. Robotics 56K FAX INT PnP*/ + { "USR9170", 0 }, + /* U.S. Robotics 56K Voice EXT PnP*/ + { "USR9180", 0 }, + /* U.S. Robotics 56K Voice INT PnP*/ + { "USR9190", 0 }, + { "", 0 } +}; + +static void inline avoid_irq_share(struct pci_dev *dev) +{ + unsigned int map = 0x1FF8; + struct isapnp_irq *irq; + struct isapnp_resources *res = dev->sysdata; + + serial8250_get_irq_map(&map); + + for ( ; res; res = res->alt) + for (irq = res->irq; irq; irq = irq->next) + irq->map = map; +} + +static char *modem_names[] __devinitdata = { + "MODEM", "Modem", "modem", "FAX", "Fax", "fax", + "56K", "56k", "K56", "33.6", "28.8", "14.4", + "33,600", "28,800", "14,400", "33.600", "28.800", "14.400", + "33600", "28800", "14400", "V.90", "V.34", "V.32", 0 +}; + +static int __devinit check_name(char *name) +{ + char **tmp; + + for (tmp = modem_names; *tmp; tmp++) + if (strstr(name, *tmp)) + return 1; + + return 0; +} + +static int inline check_compatible_id(struct pci_dev *dev) +{ + int i; + for (i = 0; i < DEVICE_COUNT_COMPATIBLE; i++) + if ((dev->vendor_compatible[i] == + ISAPNP_VENDOR('P', 'N', 'P')) && + (swab16(dev->device_compatible[i]) >= 0xc000) && + (swab16(dev->device_compatible[i]) <= 0xdfff)) + return 0; + return 1; +} + +/* + * Given a complete unknown ISA PnP device, try to use some heuristics to + * detect modems. Currently use such heuristic set: + * - dev->name or dev->bus->name must contain "modem" substring; + * - device must have only one IO region (8 byte long) with base adress + * 0x2e8, 0x3e8, 0x2f8 or 0x3f8. + * + * Such detection looks very ugly, but can detect at least some of numerous + * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[] + * table. + */ +static int serial_pnp_guess_board(struct pci_dev *dev, int *flags) +{ + struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata; + struct isapnp_resources *resa; + + if (!(check_name(dev->name) || check_name(dev->bus->name)) && + !(check_compatible_id(dev))) + return -ENODEV; + + if (!res || res->next) + return -ENODEV; + + for (resa = res->alt; resa; resa = resa->alt) { + struct isapnp_port *port; + for (port = res->port; port; port = port->next) + if ((port->size == 8) && + ((port->min == 0x2f8) || + (port->min == 0x3f8) || + (port->min == 0x2e8) || + (port->min == 0x3e8))) + return 0; + } + + return -ENODEV; +} + +static int +pnp_init_one(struct pci_dev *dev, const struct pnpbios_device_id *ent, + char *slot_name) +{ + struct serial_struct serial_req; + int ret, line, flags = ent ? ent->driver_data : 0; + + if (!ent) { + ret = serial_pnp_guess_board(dev, &flags); + if (ret) + return ret; + } + + if (dev->prepare(dev) < 0) { + printk("serial: PNP device '%s' prepare failed\n", + slot_name); + return -ENODEV; + } + + if (dev->active) + return -ENODEV; + + if (flags & SPCI_FL_NO_SHIRQ) + avoid_irq_share(dev); + + if (dev->activate(dev) < 0) { + printk("serial: PNP device '%s' activate failed\n", + slot_name); + return -ENODEV; + } + + memset(&serial_req, 0, sizeof(serial_req)); + serial_req.irq = dev->irq_resource[0].start; + serial_req.port = pci_resource_start(dev, 0); + if (HIGH_BITS_OFFSET) + serial_req.port = pci_resource_start(dev, 0) >> HIGH_BITS_OFFSET; + +#ifdef SERIAL_DEBUG_PNP + printk("Setup PNP port: port %x, irq %d, type %d\n", + serial_req.port, serial_req.irq, serial_req.io_type); +#endif + + serial_req.flags = ASYNC_SKIP_TEST | ASYNC_AUTOPROBE; + serial_req.baud_base = 115200; + line = register_serial(&serial_req); + + if (line >= 0) { + pci_set_drvdata(dev, (void *)(line + 1)); + + /* + * Public health warning: remove this once the 2.5 + * pnpbios_module_init() stuff is incorporated. + */ + dev->driver = (void *)pnp_dev_table; + } else + dev->deactivate(dev); + + return line >= 0 ? 0 : -ENODEV; +} + +static void pnp_remove_one(struct pci_dev *dev) +{ + int line = (int)pci_get_drvdata(dev); + + if (line) { + pci_set_drvdata(dev, NULL); + + unregister_serial(line - 1); + + dev->deactivate(dev); + } +} + +static char hex[] = "0123456789ABCDEF"; + +/* + * This function should vanish when 2.5 comes around and + * we have pnpbios_module_init() + */ +static int pnp_init(void) +{ + const struct pnpbios_device_id *id; + struct pci_dev *dev = NULL; + int nr = 0, rc = -ENODEV; + +#ifdef SERIAL_DEBUG_PNP + printk("Entered probe_serial_pnp()\n"); +#endif + + isapnp_for_each_dev(dev) { + char slot_name[8]; + u32 pnpid; + + if (dev->active) + continue; + + pnpid = dev->vendor << 16 | dev->device; + pnpid = cpu_to_le32(pnpid); + +#define HEX(id,a) hex[((id)>>a) & 15] +#define CHAR(id,a) (0x40 + (((id)>>a) & 31)) + slot_name[0] = CHAR(pnpid, 26); + slot_name[1] = CHAR(pnpid, 21); + slot_name[2] = CHAR(pnpid, 16); + slot_name[3] = HEX(pnpid, 12); + slot_name[4] = HEX(pnpid, 8); + slot_name[5] = HEX(pnpid, 4); + slot_name[6] = HEX(pnpid, 0); + slot_name[7] = '\0'; + + for (id = pnp_dev_table; id->id[0]; id++) + if (memcmp(id->id, slot_name, 7) == 0) + break; + + if (id->id[0]) + rc = pnp_init_one(dev, id, slot_name); + else + rc = pnp_init_one(dev, NULL, slot_name); + + if (rc == 0) + nr++; + } + +#ifdef SERIAL_DEBUG_PNP + printk("Leaving probe_serial_pnp() (probe finished)\n"); +#endif + + return nr == 0 ? rc : 0; +} + +static int __init serial8250_pnp_init(void) +{ + if (!isapnp_present()) { +#ifdef SERIAL_DEBUG_PNP + printk("Leaving probe_serial_pnp() (no isapnp)\n"); +#endif + return -ENODEV; + } + return pnp_init(); +} + +static void __exit serial8250_pnp_exit(void) +{ + struct pci_dev *dev = NULL; + + isapnp_for_each_dev(dev) { + if (dev->driver != (void *)pnp_dev_table) + continue; + pnp_remove_one(dev); + } +} + +module_init(serial8250_pnp_init); +module_exit(serial8250_pnp_exit); + +EXPORT_NO_SYMBOLS; + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic 8250/16x50 PNPBIOS serial probe module"); +MODULE_DEVICE_TABLE(pnpbios, pnp_dev_table); diff --git a/drivers/serial/serial_amba.c b/drivers/serial/serial_amba.c new file mode 100644 index 000000000000..016f717c7242 --- /dev/null +++ b/drivers/serial/serial_amba.c @@ -0,0 +1,783 @@ +/* + * linux/drivers/char/serial_amba.c + * + * Driver for AMBA serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: serial_amba.c,v 1.35 2002/07/21 08:57:55 rmk Exp $ + * + * This is a generic driver for ARM AMBA-type serial ports. They + * have a lot of 16550-like features, but are not register compatable. + * Note that although they do have CTS, DCD and DSR inputs, they do + * not have an RI input, nor do they have DTR or RTS outputs. If + * required, these have to be supplied via some other means (eg, GPIO) + * and hooked into this driver. + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/circ_buf.h> +#include <linux/serial.h> +#include <linux/console.h> +#include <linux/sysrq.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/bitops.h> + +#if defined(CONFIG_SERIAL_AMBA_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/serial_core.h> + +#include <asm/hardware/serial_amba.h> + +#define UART_NR 2 + +#define SERIAL_AMBA_MAJOR 204 +#define SERIAL_AMBA_MINOR 16 +#define SERIAL_AMBA_NR UART_NR + +#define AMBA_ISR_PASS_LIMIT 256 + +/* + * Access macros for the AMBA UARTs + */ +#define UART_GET_INT_STATUS(p) readb((p)->membase + AMBA_UARTIIR) +#define UART_PUT_ICR(p, c) writel((c), (p)->membase + AMBA_UARTICR) +#define UART_GET_FR(p) readb((p)->membase + AMBA_UARTFR) +#define UART_GET_CHAR(p) readb((p)->membase + AMBA_UARTDR) +#define UART_PUT_CHAR(p, c) writel((c), (p)->membase + AMBA_UARTDR) +#define UART_GET_RSR(p) readb((p)->membase + AMBA_UARTRSR) +#define UART_GET_CR(p) readb((p)->membase + AMBA_UARTCR) +#define UART_PUT_CR(p,c) writel((c), (p)->membase + AMBA_UARTCR) +#define UART_GET_LCRL(p) readb((p)->membase + AMBA_UARTLCR_L) +#define UART_PUT_LCRL(p,c) writel((c), (p)->membase + AMBA_UARTLCR_L) +#define UART_GET_LCRM(p) readb((p)->membase + AMBA_UARTLCR_M) +#define UART_PUT_LCRM(p,c) writel((c), (p)->membase + AMBA_UARTLCR_M) +#define UART_GET_LCRH(p) readb((p)->membase + AMBA_UARTLCR_H) +#define UART_PUT_LCRH(p,c) writel((c), (p)->membase + AMBA_UARTLCR_H) +#define UART_RX_DATA(s) (((s) & AMBA_UARTFR_RXFE) == 0) +#define UART_TX_READY(s) (((s) & AMBA_UARTFR_TXFF) == 0) +#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & AMBA_UARTFR_TMSK) == 0) + +#define UART_DUMMY_RSR_RX 256 +#define UART_PORT_SIZE 64 + +/* + * On the Integrator platform, the port RTS and DTR are provided by + * bits in the following SC_CTRLS register bits: + * RTS DTR + * UART0 7 6 + * UART1 5 4 + */ +#define SC_CTRLC (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLC_OFFSET) +#define SC_CTRLS (IO_ADDRESS(INTEGRATOR_SC_BASE) + INTEGRATOR_SC_CTRLS_OFFSET) + +/* + * We wrap our port structure around the generic uart_port. + */ +struct uart_amba_port { + struct uart_port port; + unsigned int dtr_mask; + unsigned int rts_mask; + unsigned int old_status; +}; + +static void __ambauart_stop_tx(struct uart_port *port) +{ + unsigned int cr; + + cr = UART_GET_CR(port); + cr &= ~AMBA_UARTCR_TIE; + UART_PUT_CR(port, cr); +} + +static void ambauart_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + __ambauart_stop_tx(port); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void ambauart_start_tx(struct uart_port *port, unsigned int tty_start) +{ + unsigned int cr; + + cr = UART_GET_CR(port); + cr |= AMBA_UARTCR_TIE; + UART_PUT_CR(port, cr); +} + +static void ambauart_stop_rx(struct uart_port *port) +{ + unsigned long flags; + unsigned int cr; + + spin_lock_irqsave(&port->lock, flags); + cr = UART_GET_CR(port); + cr &= ~(AMBA_UARTCR_RIE | AMBA_UARTCR_RTIE); + UART_PUT_CR(port, cr); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void ambauart_enable_ms(struct uart_port *port) +{ + unsigned long flags; + unsigned int cr; + + spin_lock_irqsave(&port->lock, flags); + cr = UART_GET_CR(port); + cr |= AMBA_UARTCR_MSIE; + UART_PUT_CR(port, cr); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void +#ifdef SUPPORT_SYSRQ +ambauart_rx_chars(struct uart_port *port, struct pt_regs *regs) +#else +ambauart_rx_chars(struct uart_port *port) +#endif +{ + struct tty_struct *tty = port->info->tty; + unsigned int status, ch, rsr, max_count = 256; + + status = UART_GET_FR(port); + while (UART_RX_DATA(status) && max_count--) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty->flip.tqueue.routine((void *)tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + printk(KERN_WARNING "TTY_DONT_FLIP set\n"); + return; + } + } + + ch = UART_GET_CHAR(port); + + *tty->flip.char_buf_ptr = ch; + *tty->flip.flag_buf_ptr = TTY_NORMAL; + port->icount.rx++; + + /* + * Note that the error handling code is + * out of the main execution path + */ + rsr = UART_GET_RSR(port) | UART_DUMMY_RSR_RX; + if (rsr & AMBA_UARTRSR_ANY) { + if (rsr & AMBA_UARTRSR_BE) { + rsr &= ~(AMBA_UARTRSR_FE | AMBA_UARTRSR_PE); + port->icount.brk++; + if (uart_handle_break(port)) + goto ignore_char; + } else if (rsr & AMBA_UARTRSR_PE) + port->icount.parity++; + else if (rsr & AMBA_UARTRSR_FE) + port->icount.frame++; + if (rsr & AMBA_UARTRSR_OE) + port->icount.overrun++; + + rsr &= port->read_status_mask; + + if (rsr & AMBA_UARTRSR_BE) + *tty->flip.flag_buf_ptr = TTY_BREAK; + else if (rsr & AMBA_UARTRSR_PE) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (rsr & AMBA_UARTRSR_FE) + *tty->flip.flag_buf_ptr = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, ch, regs)) + goto ignore_char; + + if ((rsr & port->ignore_status_mask) == 0) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + if ((rsr & AMBA_UARTRSR_OE) && + tty->flip.count < TTY_FLIPBUF_SIZE) { + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character + */ + *tty->flip.char_buf_ptr++ = 0; + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + tty->flip.count++; + } + ignore_char: + status = UART_GET_FR(port); + } + tty_flip_buffer_push(tty); + return; +} + +static void ambauart_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + int count; + + if (port->x_char) { + UART_PUT_CHAR(port, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + __ambauart_stop_tx(port); + return; + } + + count = port->fifosize >> 1; + do { + UART_PUT_CHAR(port, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_event(port, EVT_WRITE_WAKEUP); + + if (uart_circ_empty(xmit)) + __ambauart_stop_tx(port); +} + +static void ambauart_modem_status(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int status, delta; + + UART_PUT_ICR(&uap->port, 0); + + status = UART_GET_FR(&uap->port) & AMBA_UARTFR_MODEM_ANY; + + delta = status ^ uap->old_status; + uap->old_status = status; + + if (!delta) + return; + + if (delta & AMBA_UARTFR_DCD) + uart_handle_dcd_change(&uap->port, status & AMBA_UARTFR_DCD); + + if (delta & AMBA_UARTFR_DSR) + uap->port.icount.dsr++; + + if (delta & AMBA_UARTFR_CTS) + uart_handle_cts_change(&uap->port, status & AMBA_UARTFR_CTS); + + wake_up_interruptible(&uap->port.info->delta_msr_wait); +} + +static void ambauart_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct uart_port *port = dev_id; + unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; + + status = UART_GET_INT_STATUS(port); + do { + if (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS)) +#ifdef SUPPORT_SYSRQ + ambauart_rx_chars(port, regs); +#else + ambauart_rx_chars(port); +#endif + if (status & AMBA_UARTIIR_MIS) + ambauart_modem_status(port); + if (status & AMBA_UARTIIR_TIS) + ambauart_tx_chars(port); + + if (pass_counter-- == 0) + break; + + status = UART_GET_INT_STATUS(port); + } while (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS | + AMBA_UARTIIR_TIS)); +} + +static unsigned int ambauart_tx_empty(struct uart_port *port) +{ + return UART_GET_FR(port) & AMBA_UARTFR_BUSY ? 0 : TIOCSER_TEMT; +} + +static unsigned int ambauart_get_mctrl(struct uart_port *port) +{ + unsigned int result = 0; + unsigned int status; + + status = UART_GET_FR(port); + if (status & AMBA_UARTFR_DCD) + result |= TIOCM_CAR; + if (status & AMBA_UARTFR_DSR) + result |= TIOCM_DSR; + if (status & AMBA_UARTFR_CTS) + result |= TIOCM_CTS; + + return result; +} + +static void ambauart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + unsigned int ctrls = 0, ctrlc = 0; + + if (mctrl & TIOCM_RTS) + ctrlc |= uap->rts_mask; + else + ctrls |= uap->rts_mask; + + if (mctrl & TIOCM_DTR) + ctrlc |= uap->dtr_mask; + else + ctrls |= uap->dtr_mask; + + __raw_writel(ctrls, SC_CTRLS); + __raw_writel(ctrlc, SC_CTRLC); +} + +static void ambauart_break_ctl(struct uart_port *port, int break_state) +{ + unsigned long flags; + unsigned int lcr_h; + + spin_lock_irqsave(&port->lock, flags); + lcr_h = UART_GET_LCRH(port); + if (break_state == -1) + lcr_h |= AMBA_UARTLCR_H_BRK; + else + lcr_h &= ~AMBA_UARTLCR_H_BRK; + UART_PUT_LCRH(port, lcr_h); + spin_unlock_irqrestore(&port->lock, flags); +} + +static int ambauart_startup(struct uart_port *port) +{ + struct uart_amba_port *uap = (struct uart_amba_port *)port; + int retval; + + /* + * Allocate the IRQ + */ + retval = request_irq(port->irq, ambauart_int, 0, "amba", port); + if (retval) + return retval; + + /* + * initialise the old status of the modem signals + */ + uap->old_status = UART_GET_FR(port) & AMBA_UARTFR_MODEM_ANY; + + /* + * Finally, enable interrupts + */ + UART_PUT_CR(port, AMBA_UARTCR_UARTEN | AMBA_UARTCR_RIE | + AMBA_UARTCR_RTIE); + + return 0; +} + +static void ambauart_shutdown(struct uart_port *port) +{ + /* + * Free the interrupt + */ + free_irq(port->irq, port); + + /* + * disable all interrupts, disable the port + */ + UART_PUT_CR(port, 0); + + /* disable break condition and fifos */ + UART_PUT_LCRH(port, UART_GET_LCRH(port) & + ~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN)); +} + +static void +ambauart_change_speed(struct uart_port *port, unsigned int cflag, + unsigned int iflag, unsigned int quot) +{ + unsigned int lcr_h, old_cr; + unsigned long flags; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: + lcr_h = AMBA_UARTLCR_H_WLEN_5; + break; + case CS6: + lcr_h = AMBA_UARTLCR_H_WLEN_6; + break; + case CS7: + lcr_h = AMBA_UARTLCR_H_WLEN_7; + break; + default: // CS8 + lcr_h = AMBA_UARTLCR_H_WLEN_8; + break; + } + if (cflag & CSTOPB) + lcr_h |= AMBA_UARTLCR_H_STP2; + if (cflag & PARENB) { + lcr_h |= AMBA_UARTLCR_H_PEN; + if (!(cflag & PARODD)) + lcr_h |= AMBA_UARTLCR_H_EPS; + } + if (port->fifosize > 1) + lcr_h |= AMBA_UARTLCR_H_FEN; + + port->read_status_mask = AMBA_UARTRSR_OE; + if (iflag & INPCK) + port->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; + if (iflag & (BRKINT | PARMRK)) + port->read_status_mask |= AMBA_UARTRSR_BE; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (iflag & IGNPAR) + port->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; + if (iflag & IGNBRK) { + port->ignore_status_mask |= AMBA_UARTRSR_BE; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (iflag & IGNPAR) + port->ignore_status_mask |= AMBA_UARTRSR_OE; + } + + /* + * Ignore all characters if CREAD is not set. + */ + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= UART_DUMMY_RSR_RX; + + /* first, disable everything */ + spin_lock_irqsave(&port->lock, flags); + old_cr = UART_GET_CR(port) & ~AMBA_UARTCR_MSIE; + + if (UART_ENABLE_MS(port, cflag)) + old_cr |= AMBA_UARTCR_MSIE; + + UART_PUT_CR(port, 0); + + /* Set baud rate */ + quot -= 1; + UART_PUT_LCRM(port, ((quot & 0xf00) >> 8)); + UART_PUT_LCRL(port, (quot & 0xff)); + + /* + * ----------v----------v----------v----------v----- + * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L + * ----------^----------^----------^----------^----- + */ + UART_PUT_LCRH(port, lcr_h); + UART_PUT_CR(port, old_cr); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *ambauart_type(struct uart_port *port) +{ + return port->type == PORT_AMBA ? "AMBA" : NULL; +} + +/* + * Release the memory region(s) being used by 'port' + */ +static void ambauart_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, UART_PORT_SIZE); +} + +/* + * Request the memory region(s) being used by 'port' + */ +static int ambauart_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_amba") + != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void ambauart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_AMBA; + ambauart_request_port(port); + } +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int ambauart_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= NR_IRQS) + ret = -EINVAL; + if (ser->baud_base < 9600) + ret = -EINVAL; + return ret; +} + +static struct uart_ops amba_pops = { + tx_empty: ambauart_tx_empty, + set_mctrl: ambauart_set_mctrl, + get_mctrl: ambauart_get_mctrl, + stop_tx: ambauart_stop_tx, + start_tx: ambauart_start_tx, + stop_rx: ambauart_stop_rx, + enable_ms: ambauart_enable_ms, + break_ctl: ambauart_break_ctl, + startup: ambauart_startup, + shutdown: ambauart_shutdown, + change_speed: ambauart_change_speed, + type: ambauart_type, + release_port: ambauart_release_port, + request_port: ambauart_request_port, + config_port: ambauart_config_port, + verify_port: ambauart_verify_port, +}; + +static struct uart_amba_port amba_ports[UART_NR] = { + { + port: { + membase: (void *)IO_ADDRESS(INTEGRATOR_UART0_BASE), + mapbase: INTEGRATOR_UART0_BASE, + iotype: SERIAL_IO_MEM, + irq: IRQ_UARTINT0, + uartclk: 14745600, + fifosize: 16, + ops: &amba_pops, + flags: ASYNC_BOOT_AUTOCONF, + line: 0, + }, + dtr_mask: 1 << 5, + rts_mask: 1 << 4, + }, + { + port: { + membase: (void *)IO_ADDRESS(INTEGRATOR_UART1_BASE), + mapbase: INTEGRATOR_UART1_BASE, + iotype: SERIAL_IO_MEM, + irq: IRQ_UARTINT1, + uartclk: 14745600, + fifosize: 16, + ops: &amba_pops, + flags: ASYNC_BOOT_AUTOCONF, + line: 1, + }, + dtr_mask: 1 << 7, + rts_mask: 1 << 6, + } +}; + +#ifdef CONFIG_SERIAL_AMBA_CONSOLE + +static void +ambauart_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port = &amba_ports[co->index].port; + unsigned int status, old_cr; + int i; + + /* + * First save the CR then disable the interrupts + */ + old_cr = UART_GET_CR(port); + UART_PUT_CR(port, AMBA_UARTCR_UARTEN); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + do { + status = UART_GET_FR(port); + } while (!UART_TX_READY(status)); + UART_PUT_CHAR(port, s[i]); + if (s[i] == '\n') { + do { + status = UART_GET_FR(port); + } while (!UART_TX_READY(status)); + UART_PUT_CHAR(port, '\r'); + } + } + + /* + * Finally, wait for transmitter to become empty + * and restore the TCR + */ + do { + status = UART_GET_FR(port); + } while (status & AMBA_UARTFR_BUSY); + UART_PUT_CR(port, old_cr); +} + +static kdev_t ambauart_console_device(struct console *co) +{ + return mk_kdev(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + co->index); +} + +static void __init +ambauart_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + if (UART_GET_CR(port) & AMBA_UARTCR_UARTEN) { + unsigned int lcr_h, quot; + lcr_h = UART_GET_LCRH(port); + + *parity = 'n'; + if (lcr_h & AMBA_UARTLCR_H_PEN) { + if (lcr_h & AMBA_UARTLCR_H_EPS) + *parity = 'e'; + else + *parity = 'o'; + } + + if ((lcr_h & 0x60) == AMBA_UARTLCR_H_WLEN_7) + *bits = 7; + else + *bits = 8; + + quot = UART_GET_LCRL(port) | UART_GET_LCRM(port) << 8; + *baud = port->uartclk / (16 * (quot + 1)); + } +} + +static int __init ambauart_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= UART_NR) + co->index = 0; + port = &amba_ports[co->index].port; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + ambauart_console_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console amba_console = { + name: "ttyAM", + write: ambauart_console_write, + device: ambauart_console_device, + setup: ambauart_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +void __init ambauart_console_init(void) +{ + register_console(&amba_console); +} + +#define AMBA_CONSOLE &amba_console +#else +#define AMBA_CONSOLE NULL +#endif + +static struct uart_driver amba_reg = { + owner: THIS_MODULE, + driver_name: "ttyAM", +#ifdef CONFIG_DEVFS_FS + dev_name: "ttyAM%d", +#else + dev_name: "ttyAM", +#endif + major: SERIAL_AMBA_MAJOR, + minor: SERIAL_AMBA_MINOR, + nr: UART_NR, + cons: AMBA_CONSOLE, +}; + +static int __init ambauart_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: AMBA driver $Revision: 1.35 $\n"); + + ret = uart_register_driver(&amba_reg); + if (ret == 0) { + int i; + + for (i = 0; i < UART_NR; i++) + uart_add_one_port(&amba_reg, &amba_ports[i].port); + } + return ret; +} + +static void __exit ambauart_exit(void) +{ + int i; + + for (i = 0; i < UART_NR; i++) + uart_remove_one_port(&amba_reg, &amba_ports[i].port); + + uart_unregister_driver(&amba_reg); +} + +module_init(ambauart_init); +module_exit(ambauart_exit); + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); +MODULE_DESCRIPTION("ARM AMBA serial port driver $Revision: 1.35 $"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_anakin.c b/drivers/serial/serial_anakin.c new file mode 100644 index 000000000000..f9ee4c2bb2a4 --- /dev/null +++ b/drivers/serial/serial_anakin.c @@ -0,0 +1,546 @@ +/* + * linux/drivers/char/serial_anakin.c + * + * Based on driver for AMBA serial ports, by ARM Limited, + * Deep Blue Solutions Ltd., Linus Torvalds and Theodore Ts'o. + * + * Copyright (C) 2001 Aleph One Ltd. for Acunia N.V. + * + * Copyright (C) 2001 Blue Mug, Inc. for Acunia N.V. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 20-Apr-2001 TTC Created + * 05-May-2001 W/TTC Updated for serial_core.c + * 27-Jun-2001 jonm Minor changes; add mctrl support, switch to + * SA_INTERRUPT. Works reliably now. No longer requires + * changes to the serial_core API. + * + * $Id: serial_anakin.c,v 1.27 2002/07/20 17:10:03 rmk Exp $ + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/circ_buf.h> +#include <linux/serial.h> +#include <linux/console.h> +#include <linux/sysrq.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/bitops.h> + +#include <linux/serial_core.h> + +#include <asm/arch/serial_reg.h> + +#define UART_NR 5 + +#define SERIAL_ANAKIN_NAME "ttyAN" +#define SERIAL_ANAKIN_MAJOR 204 +#define SERIAL_ANAKIN_MINOR 32 + +static unsigned int txenable[NR_IRQS]; /* Software interrupt register */ + +static inline unsigned int +anakin_in(struct uart_port *port, unsigned int offset) +{ + return __raw_readl(port->base + offset); +} + +static inline void +anakin_out(struct uart_port *port, unsigned int offset, unsigned int value) +{ + __raw_writel(value, port->base + offset); +} + +static void +anakin_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ + txenable[port->irq] = 0; +} + +static inline void +anakin_transmit_buffer(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + + while (!(anakin_in(port, 0x10) & TXEMPTY)); + anakin_out(port, 0x14, xmit->buf[xmit->tail]); + anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1); + port->icount.tx++; + + if (uart_circ_empty(xmit)) + anakin_stop_tx(port, 0); +} + +static inline void +anakin_transmit_x_char(struct uart_port *port) +{ + anakin_out(port, 0x14, port->x_char); + anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST); + port->icount.tx++; + port->x_char = 0; +} + +static void +anakin_start_tx(struct uart_port *port, unsigned int tty_start) +{ + unsigned int flags; + + spin_lock_irqsave(&port->lock, flags); + + // is it this... or below + if (!txenable[port->irq]) { + txenable[port->irq] = TXENABLE; + + if ((anakin_in(port, 0x10) & TXEMPTY)) { + anakin_transmit_buffer(port); + } + } + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void +anakin_stop_rx(struct uart_port *port) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + while (anakin_in(port, 0x10) & RXRELEASE) + anakin_in(port, 0x14); + anakin_out(port, 0x18, anakin_in(port, 0x18) | BLOCKRX); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void +anakin_enable_ms(struct uart_port *port) +{ +} + +static inline void +anakin_rx_chars(struct uart_port *port) +{ + unsigned int ch; + struct tty_struct *tty = port->info->tty; + + if (!(anakin_in(port, 0x10) & RXRELEASE)) + return; + + ch = anakin_in(port, 0x14) & 0xff; + + if (tty->flip.count < TTY_FLIPBUF_SIZE) { + *tty->flip.char_buf_ptr++ = ch; + *tty->flip.flag_buf_ptr++ = TTY_NORMAL; + port->icount.rx++; + tty->flip.count++; + } + tty_flip_buffer_push(tty); +} + +static inline void +anakin_overrun_chars(struct uart_port *port) +{ + unsigned int ch; + + ch = anakin_in(port, 0x14); + port->icount.overrun++; +} + +static inline void +anakin_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + + if (port->x_char) { + anakin_transmit_x_char(port); + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + anakin_stop_tx(port, 0); + return; + } + + anakin_transmit_buffer(port); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_event(port, EVT_WRITE_WAKEUP); +} + +static void +anakin_int(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int status; + struct uart_port *port = dev_id; + + status = anakin_in(port, 0x1c); + + if (status & RX) + anakin_rx_chars(port); + + if (status & OVERRUN) + anakin_overrun_chars(port); + + if (txenable[port->irq] && (status & TX)) + anakin_tx_chars(port); +} + +static unsigned int +anakin_tx_empty(struct uart_port *port) +{ + return anakin_in(port, 0x10) & TXEMPTY ? TIOCSER_TEMT : 0; +} + +static unsigned int +anakin_get_mctrl(struct uart_port *port) +{ + unsigned int status = 0; + + status |= (anakin_in(port, 0x10) & CTS ? TIOCM_CTS : 0); + status |= (anakin_in(port, 0x18) & DCD ? TIOCM_CAR : 0); + status |= (anakin_in(port, 0x18) & DTR ? TIOCM_DTR : 0); + status |= (anakin_in(port, 0x18) & RTS ? TIOCM_RTS : 0); + + return status; +} + +static void +anakin_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + unsigned int status; + + status = anakin_in(port, 0x18); + + if (mctrl & TIOCM_RTS) + status |= RTS; + else + status &= ~RTS; + + if (mctrl & TIOCM_CAR) + status |= DCD; + else + status &= ~DCD; + + anakin_out(port, 0x18, status); +} + +static void +anakin_break_ctl(struct uart_port *port, int break_state) +{ + unsigned long flags; + unsigned int status; + + spin_lock_irqsave(&port->lock, flags); + status = anakin_in(port, 0x20); + + if (break_state == -1) + status |= SETBREAK; + else + status &= ~SETBREAK; + + anakin_out(port, 0x20, status); + spin_unlock_irqrestore(&port->lock, flags); +} + +static int anakin_startup(struct uart_port *port) +{ + int retval; + unsigned int read,write; + + /* + * Allocate the IRQ + */ + retval = request_irq(port->irq, anakin_int, SA_INTERRUPT, + "serial_anakin", port); + if (retval) + return retval; + + /* + * initialise the old status of the modem signals + */ + port->old_status = 0; + + /* + * Finally, disable IRQ and softIRQs for first byte) + */ + txenable[port->irq] = 0; + read = anakin_in(port, 0x18); + write = (read & ~(RTS | DTR | BLOCKRX)) | IRQENABLE; + anakin_out(port, 0x18, write); + + return 0; +} + +static void anakin_shutdown(struct uart_port *port) +{ + /* + * Free the interrupt + */ + free_irq(port->irq, port); + + /* + * disable all interrupts, disable the port + */ + anakin_out(port, 0x18, anakin_in(port, 0x18) & ~IRQENABLE); +} + +static void +anakin_change_speed(struct uart_port *port, unsigned int cflag, + unsigned int iflag, unsigned int quot) +{ + unsigned int flags; + + spin_lock_irqsave(&port->lock, flags); + while (!(anakin_in(port, 0x10) & TXEMPTY)); + anakin_out(port, 0x10, (anakin_in(port, 0x10) & ~PRESCALER) + | (quot << 3)); + + //parity always set to none + anakin_out(port, 0x18, anakin_in(port, 0x18) & ~PARITY); + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *anakin_type(struct port *port) +{ + return port->type == PORT_ANAKIN ? "ANAKIN" : NULL; +} + +static struct uart_ops anakin_pops = { + tx_empty: anakin_tx_empty, + set_mctrl: anakin_set_mctrl, + get_mctrl: anakin_get_mctrl, + stop_tx: anakin_stop_tx, + start_tx: anakin_start_tx, + stop_rx: anakin_stop_rx, + enable_ms: anakin_enable_ms, + break_ctl: anakin_break_ctl, + startup: anakin_startup, + shutdown: anakin_shutdown, + change_speed: anakin_change_speed, + type: anakin_type, +}; + +static struct uart_port anakin_ports[UART_NR] = { + { + base: IO_BASE + UART0, + irq: IRQ_UART0, + uartclk: 3686400, + fifosize: 0, + ops: &anakin_pops, + flags: ASYNC_BOOT_AUTOCONF, + line: 0, + }, + { + base: IO_BASE + UART1, + irq: IRQ_UART1, + uartclk: 3686400, + fifosize: 0, + ops: &anakin_pops, + flags: ASYNC_BOOT_AUTOCONF, + line: 1, + }, + { + base: IO_BASE + UART2, + irq: IRQ_UART2, + uartclk: 3686400, + fifosize: 0, + ops: &anakin_pops, + flags: ASYNC_BOOT_AUTOCONF, + line: 2, + }, + { + base: IO_BASE + UART3, + irq: IRQ_UART3, + uartclk: 3686400, + fifosize: 0, + ops: &anakin_pops, + flags: ASYNC_BOOT_AUTOCONF, + line: 3, + }, + { + base: IO_BASE + UART4, + irq: IRQ_UART4, + uartclk: 3686400, + fifosize: 0, + ops: &anakin_pops, + flags: ASYNC_BOOT_AUTOCONF, + line: 4, + }, +}; + + +#ifdef CONFIG_SERIAL_ANAKIN_CONSOLE + +static void +anakin_console_write(struct console *co, const char *s, unsigned int count) +{ + struct uart_port *port = &anakin_ports[co->index]; + unsigned int flags, status, i; + + /* + * First save the status then disable the interrupts + */ + local_irq_save(flags); + status = anakin_in(port, 0x18); + anakin_out(port, 0x18, status & ~IRQENABLE); + local_irq_restore(flags); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++, s++) { + while (!(anakin_in(port, 0x10) & TXEMPTY)); + + /* + * Send the character out. + * If a LF, also do CR... + */ + anakin_out(port, 0x14, *s); + anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST); + + if (*s == 10) { + while (!(anakin_in(port, 0x10) & TXEMPTY)); + anakin_out(port, 0x14, 13); + anakin_out(port, 0x18, anakin_in(port, 0x18) + | SENDREQUEST); + } + } + + /* + * Finally, wait for transmitter to become empty + * and restore the interrupts + */ + while (!(anakin_in(port, 0x10) & TXEMPTY)); + + if (status & IRQENABLE) { + local_irq_save(flags); + anakin_out(port, 0x18, anakin_in(port, 0x18) | IRQENABLE); + local_irq_restore(flags); + } +} + +static kdev_t +anakin_console_device(struct console *co) +{ + return mk_kdev(SERIAL_ANAKIN_MAJOR, SERIAL_ANAKIN_MINOR + co->index); +} + +/* + * Read the current UART setup. + */ +static void __init +anakin_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) +{ + int paritycode; + + *baud = GETBAUD (anakin_in(port, 0x10) & PRESCALER); + paritycode = GETPARITY(anakin_in(port, 0x18) & PARITY); + switch (paritycode) { + case NONEPARITY: *parity = 'n'; break; + case ODDPARITY: *parity = 'o'; break; + case EVENPARITY: *parity = 'e'; break; + } + *bits = 8; +} + +static int __init +anakin_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = CONFIG_ANAKIN_DEFAULT_BAUDRATE; + int bits = 8; + int parity = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index >= UART_NR) + co->index = 0; + port = &anakin_ports[co->index]; + + if (options) + uart_parse_options(options, &baud, &parity, &bits); + else + anakin_console_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits); +} + +static struct console anakin_console = { + name: SERIAL_ANAKIN_NAME, + write: anakin_console_write, + device: anakin_console_device, + setup: anakin_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +void __init +anakin_console_init(void) +{ + register_console(&anakin_console); +} + +#define ANAKIN_CONSOLE &anakin_console +#else +#define ANAKIN_CONSOLE NULL +#endif + +static struct uart_register anakin_reg = { + driver_name: SERIAL_ANAKIN_NAME, + dev_name: SERIAL_ANAKIN_NAME, + major: SERIAL_ANAKIN_MAJOR, + minor: SERIAL_ANAKIN_MINOR, + nr: UART_NR, + cons: ANAKIN_CONSOLE, +}; + +static int __init +anakin_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: Anakin driver $Revision: 1.27 $\n"); + + ret = uart_register_driver(&anakin_reg); + if (ret == 0) { + int i; + + for (i = 0; i < UART_NR; i++) + uart_add_one_port(&anakin_reg, &anakin_ports[i]); + } + return ret; +} + +__initcall(anakin_init); + +MODULE_DESCRIPTION("Anakin serial driver"); +MODULE_AUTHOR("Tak-Shing Chan <chan@aleph1.co.uk>"); +MODULE_SUPPORTED_DEVICE("ttyAN"); +MODULE_LICENSE("GPL"); + +EXPORT_NO_SYMBOLS; diff --git a/drivers/serial/serial_clps711x.c b/drivers/serial/serial_clps711x.c new file mode 100644 index 000000000000..500b9a2b9f51 --- /dev/null +++ b/drivers/serial/serial_clps711x.c @@ -0,0 +1,643 @@ +/* + * linux/drivers/char/serial_clps711x.c + * + * Driver for CLPS711x serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: serial_clps711x.c,v 1.38 2002/07/21 08:57:55 rmk Exp $ + * + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/circ_buf.h> +#include <linux/serial.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/spinlock.h> + +#include <asm/bitops.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/uaccess.h> + +#if defined(CONFIG_SERIAL_CLPS711X_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/serial_core.h> + +#include <asm/hardware/clps7111.h> + +#define UART_NR 2 + +#ifndef CONFIG_SERIAL_CLPS711X_OLD_NAME +#define SERIAL_CLPS711X_NAME "ttyCL" +#define SERIAL_CLPS711X_MAJOR 204 +#define SERIAL_CLPS711X_MINOR 40 +#define SERIAL_CLPS711X_NR UART_NR + +#else +#warning The old names/device number for this driver if compatabity is needed +#define SERIAL_CLPS711X_NAME "ttyAM" +#define SERIAL_CLPS711X_MAJOR 204 +#define SERIAL_CLPS711X_MINOR 16 +#define SERIAL_CLPS711X_NR UART_NR + +#endif + +/* + * We use the relevant SYSCON register as a base address for these ports. + */ +#define UBRLCR(port) ((port)->iobase + UBRLCR1 - SYSCON1) +#define UARTDR(port) ((port)->iobase + UARTDR1 - SYSCON1) +#define SYSFLG(port) ((port)->iobase + SYSFLG1 - SYSCON1) +#define SYSCON(port) ((port)->iobase + SYSCON1 - SYSCON1) + +#define TX_IRQ(port) ((port)->irq) +#define RX_IRQ(port) ((port)->irq + 1) + +#define UART_ANY_ERR (UARTDR_FRMERR | UARTDR_PARERR | UARTDR_OVERR) + +#define tx_enabled(port) ((port)->unused[0]) + +static void +__clps711xuart_stop_tx(struct uart_port *port) +{ + if (tx_enabled(port)) { + disable_irq(TX_IRQ(port)); + tx_enabled(port) = 0; + } +} + +static void +clps711xuart_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + __clps711xuart_stop_tx(port); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void +clps711xuart_start_tx(struct uart_port *port, unsigned int tty_start) +{ + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + if (!tx_enabled(port)) { + enable_irq(TX_IRQ(port)); + tx_enabled(port) = 1; + } + spin_unlock_irqrestore(&port->lock, flags); +} + +static void clps711xuart_stop_rx(struct uart_port *port) +{ + disable_irq(RX_IRQ(port)); +} + +static void clps711xuart_enable_ms(struct uart_port *port) +{ +} + +static void clps711xuart_int_rx(int irq, void *dev_id, struct pt_regs *regs) +{ + struct uart_port *port = dev_id; + struct tty_struct *tty = port->info->tty; + unsigned int status, ch, flg, ignored = 0; + + status = clps_readl(SYSFLG(port)); + while (!(status & SYSFLG_URXFE)) { + ch = clps_readl(UARTDR(port)); + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + port->icount.rx++; + + flg = TTY_NORMAL; + + /* + * Note that the error handling code is + * out of the main execution path + */ + if (ch & UART_ANY_ERR) + goto handle_error; + + if (uart_handle_sysrq_char(port, ch, regs)) + goto ignore_char; + + error_return: + *tty->flip.flag_buf_ptr++ = flg; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + ignore_char: + status = clps_readl(SYSFLG(port)); + } + out: + tty_flip_buffer_push(tty); + return; + + handle_error: + if (ch & UARTDR_PARERR) + port->icount.parity++; + else if (ch & UARTDR_FRMERR) + port->icount.frame++; + if (ch & UARTDR_OVERR) + port->icount.overrun++; + + if (ch & port->ignore_status_mask) { + if (++ignored > 100) + goto out; + goto ignore_char; + } + ch &= port->read_status_mask; + + if (ch & UARTDR_PARERR) + flg = TTY_PARITY; + else if (ch & UARTDR_FRMERR) + flg = TTY_FRAME; + + if (ch & UARTDR_OVERR) { + /* + * CHECK: does overrun affect the current character? + * ASSUMPTION: it does not. + */ + *tty->flip.flag_buf_ptr++ = flg; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + ch = 0; + flg = TTY_OVERRUN; + } +#ifdef SUPPORT_SYSRQ + port->sysrq = 0; +#endif + goto error_return; +} + +static void clps711xuart_int_tx(int irq, void *dev_id, struct pt_regs *regs) +{ + struct uart_port *port = dev_id; + struct circ_buf *xmit = &port->info->xmit; + int count; + + if (port->x_char) { + clps_writel(port->x_char, UARTDR(port)); + port->icount.tx++; + port->x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + __clps711xuart_stop_tx(port); + return; + } + + count = port->fifosize >> 1; + do { + clps_writel(xmit->buf[xmit->tail], UARTDR(port)); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_event(port, EVT_WRITE_WAKEUP); + + if (uart_circ_empty(xmit)) + __clps711xuart_stop_tx(port); +} + +static unsigned int clps711xuart_tx_empty(struct uart_port *port) +{ + unsigned int status = clps_readl(SYSFLG(port)); + return status & SYSFLG_UBUSY ? 0 : TIOCSER_TEMT; +} + +static unsigned int clps711xuart_get_mctrl(struct uart_port *port) +{ + unsigned int port_addr; + unsigned int result = 0; + unsigned int status; + + port_addr = SYSFLG(port); + if (port_addr == SYSFLG1) { + status = clps_readl(SYSFLG1); + if (status & SYSFLG1_DCD) + result |= TIOCM_CAR; + if (status & SYSFLG1_DSR) + result |= TIOCM_DSR; + if (status & SYSFLG1_CTS) + result |= TIOCM_CTS; + } + + return result; +} + +static void +clps711xuart_set_mctrl_null(struct uart_port *port, unsigned int mctrl) +{ +} + +static void clps711xuart_break_ctl(struct uart_port *port, int break_state) +{ + unsigned long flags; + unsigned int ubrlcr; + + spin_lock_irqsave(&port->lock, flags); + ubrlcr = clps_readl(UBRLCR(port)); + if (break_state == -1) + ubrlcr |= UBRLCR_BREAK; + else + ubrlcr &= ~UBRLCR_BREAK; + clps_writel(ubrlcr, UBRLCR(port)); + spin_unlock_irqrestore(&port->lock, flags); +} + +static int clps711xuart_startup(struct uart_port *port) +{ + unsigned int syscon; + int retval; + + tx_enabled(port) = 1; + + /* + * Allocate the IRQs + */ + retval = request_irq(TX_IRQ(port), clps711xuart_int_tx, 0, + "clps711xuart_tx", port); + if (retval) + return retval; + + retval = request_irq(RX_IRQ(port), clps711xuart_int_rx, 0, + "clps711xuart_rx", port); + if (retval) { + free_irq(TX_IRQ(port), port); + return retval; + } + + /* + * enable the port + */ + syscon = clps_readl(SYSCON(port)); + syscon |= SYSCON_UARTEN; + clps_writel(syscon, SYSCON(port)); + + return 0; +} + +static void clps711xuart_shutdown(struct uart_port *port) +{ + unsigned int ubrlcr, syscon; + + /* + * Free the interrupt + */ + free_irq(TX_IRQ(port), port); /* TX interrupt */ + free_irq(RX_IRQ(port), port); /* RX interrupt */ + + /* + * disable the port + */ + syscon = clps_readl(SYSCON(port)); + syscon &= ~SYSCON_UARTEN; + clps_writel(syscon, SYSCON(port)); + + /* + * disable break condition and fifos + */ + ubrlcr = clps_readl(UBRLCR(port)); + ubrlcr &= ~(UBRLCR_FIFOEN | UBRLCR_BREAK); + clps_writel(ubrlcr, UBRLCR(port)); +} + +static void +clps711xuart_change_speed(struct uart_port *port, unsigned int cflag, + unsigned int iflag, unsigned int quot) +{ + unsigned int ubrlcr; + unsigned long flags; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: + ubrlcr = UBRLCR_WRDLEN5; + break; + case CS6: + ubrlcr = UBRLCR_WRDLEN6; + break; + case CS7: + ubrlcr = UBRLCR_WRDLEN7; + break; + default: // CS8 + ubrlcr = UBRLCR_WRDLEN8; + break; + } + if (cflag & CSTOPB) + ubrlcr |= UBRLCR_XSTOP; + if (cflag & PARENB) { + ubrlcr |= UBRLCR_PRTEN; + if (!(cflag & PARODD)) + ubrlcr |= UBRLCR_EVENPRT; + } + if (port->fifosize > 1) + ubrlcr |= UBRLCR_FIFOEN; + + port->read_status_mask = UARTDR_OVERR; + if (iflag & INPCK) + port->read_status_mask |= UARTDR_PARERR | UARTDR_FRMERR; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (iflag & IGNPAR) + port->ignore_status_mask |= UARTDR_FRMERR | UARTDR_PARERR; + if (iflag & IGNBRK) { + /* + * If we're ignoring parity and break indicators, + * ignore overruns to (for real raw support). + */ + if (iflag & IGNPAR) + port->ignore_status_mask |= UARTDR_OVERR; + } + + quot -= 1; + + /* first, disable everything */ + spin_lock_irqsave(&port->lock, flags); + + clps_writel(ubrlcr | quot, UBRLCR(port)); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *clps711xuart_type(struct uart_port *port) +{ + return port->type == PORT_CLPS711X ? "CLPS711x" : NULL; +} + +/* + * Configure/autoconfigure the port. + */ +static void clps711xuart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) + port->type = PORT_CLPS711X; +} + +static void clps711xuart_release_port(struct uart_port *port) +{ +} + +static int clps711xuart_request_port(struct uart_port *port) +{ + return 0; +} + +static struct uart_ops clps711x_pops = { + tx_empty: clps711xuart_tx_empty, + set_mctrl: clps711xuart_set_mctrl_null, + get_mctrl: clps711xuart_get_mctrl, + stop_tx: clps711xuart_stop_tx, + start_tx: clps711xuart_start_tx, + stop_rx: clps711xuart_stop_rx, + enable_ms: clps711xuart_enable_ms, + break_ctl: clps711xuart_break_ctl, + startup: clps711xuart_startup, + shutdown: clps711xuart_shutdown, + change_speed: clps711xuart_change_speed, + type: clps711xuart_type, + config_port: clps711xuart_config_port, + release_port: clps711xuart_release_port, + request_port: clps711xuart_request_port, +}; + +static struct uart_port clps711x_ports[UART_NR] = { + { + iobase: SYSCON1, + irq: IRQ_UTXINT1, /* IRQ_URXINT1, IRQ_UMSINT */ + uartclk: 3686400, + fifosize: 16, + ops: &clps711x_pops, + flags: ASYNC_BOOT_AUTOCONF, + }, + { + iobase: SYSCON2, + irq: IRQ_UTXINT2, /* IRQ_URXINT2 */ + uartclk: 3686400, + fifosize: 16, + ops: &clps711x_pops, + flags: ASYNC_BOOT_AUTOCONF, + } +}; + +#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE +/* + * Print a string to the serial port trying not to disturb + * any possible real use of the port... + * + * The console_lock must be held when we get here. + * + * Note that this is called with interrupts already disabled + */ +static void +clps711xuart_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_port *port = clps711x_ports + co->index; + unsigned int status, syscon; + int i; + + /* + * Ensure that the port is enabled. + */ + syscon = clps_readl(SYSCON(port)); + clps_writel(syscon | SYSCON_UARTEN, SYSCON(port)); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + do { + status = clps_readl(SYSFLG(port)); + } while (status & SYSFLG_UTXFF); + clps_writel(s[i], UARTDR(port)); + if (s[i] == '\n') { + do { + status = clps_readl(SYSFLG(port)); + } while (status & SYSFLG_UTXFF); + clps_writel('\r', UARTDR(port)); + } + } + + /* + * Finally, wait for transmitter to become empty + * and restore the uart state. + */ + do { + status = clps_readl(SYSFLG(port)); + } while (status & SYSFLG_UBUSY); + + clps_writel(syscon, SYSCON(port)); +} + +static kdev_t clps711xuart_console_device(struct console *co) +{ + return mk_kdev(SERIAL_CLPS711X_MAJOR, SERIAL_CLPS711X_MINOR + co->index); +} + +static void __init +clps711xuart_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + if (clps_readl(SYSCON(port)) & SYSCON_UARTEN) { + unsigned int ubrlcr, quot; + + ubrlcr = clps_readl(UBRLCR(port)); + + *parity = 'n'; + if (ubrlcr & UBRLCR_PRTEN) { + if (ubrlcr & UBRLCR_EVENPRT) + *parity = 'e'; + else + *parity = 'o'; + } + + if ((ubrlcr & UBRLCR_WRDLEN_MASK) == UBRLCR_WRDLEN7) + *bits = 7; + else + *bits = 8; + + quot = ubrlcr & UBRLCR_BAUD_MASK; + *baud = port->uartclk / (16 * (quot + 1)); + } +} + +static int __init clps711xuart_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + port = uart_get_console(clps711x_ports, UART_NR, co); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + clps711xuart_console_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console clps711x_console = { + name: SERIAL_CLPS711X_NAME, + write: clps711xuart_console_write, + device: clps711xuart_console_device, + setup: clps711xuart_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +void __init clps711xuart_console_init(void) +{ + register_console(&clps711x_console); +} + +#define CLPS711X_CONSOLE &clps711x_console +#else +#define CLPS711X_CONSOLE NULL +#endif + +static struct uart_driver clps711x_reg = { + driver_name: "ttyCL", +#ifdef CONFIG_DEVFS_FS + dev_name: SERIAL_CLPS711X_NAME, +#else + dev_name: SERIAL_CLPS711X_NAME, +#endif + + major: SERIAL_CLPS711X_MAJOR, + minor: SERIAL_CLPS711X_MINOR, + nr: UART_NR, + + cons: CLPS711X_CONSOLE, +}; + +static int __init clps711xuart_init(void) +{ + int ret, i; + + printk(KERN_INFO "Serial: CLPS711x driver $Revision: 1.38 $\n"); + + ret = uart_register_driver(&clps711x_reg); + if (ret) + return ret; + + for (i = 0; i < UART_NR; i++) + uart_add_one_port(&clps711x_reg, &clps711x_ports[i]); + + return 0; +} + +static void __exit clps711xuart_exit(void) +{ + int i; + + for (i = 0; i < UART_NR; i++) + uart_remove_one_port(&clps711x_reg, &clps711x_ports[i]); + + uart_unregister_driver(&clps711x_reg); +} + +module_init(clps711xuart_init); +module_exit(clps711xuart_exit); + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Deep Blue Solutions Ltd"); +MODULE_DESCRIPTION("CLPS-711x generic serial driver $Revision: 1.38 $"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c new file mode 100644 index 000000000000..c6d354329e02 --- /dev/null +++ b/drivers/serial/serial_core.c @@ -0,0 +1,2467 @@ +/* + * linux/drivers/char/serial_core.c + * + * Driver core for serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright 1999 ARM Limited + * Copyright (C) 2000-2001 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: serial_core.c,v 1.89 2002/07/20 18:07:32 rmk Exp $ + * + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/circ_buf.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/pm.h> +#include <linux/serial_core.h> +#include <linux/smp_lock.h> +#include <linux/serial.h> /* for serial_state and serial_icounter_struct */ + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/bitops.h> + +#undef DEBUG +#ifdef DEBUG +#define DPRINTK(x...) printk(x) +#else +#define DPRINTK(x...) do { } while (0) +#endif + +#ifndef CONFIG_PM +#define pm_access(pm) do { } while (0) +#define pm_unregister(pm) do { } while (0) +#endif + +/* + * This is used to lock changes in serial line configuration. + */ +static DECLARE_MUTEX(port_sem); + +#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8) + +static void uart_change_speed(struct uart_info *info, struct termios *old_termios); +static void uart_wait_until_sent(struct tty_struct *tty, int timeout); + +/* + * This routine is used by the interrupt handler to schedule processing in + * the software interrupt portion of the driver. + */ +void uart_event(struct uart_port *port, int event) +{ + struct uart_info *info = port->info; + + set_bit(0, &info->event); + tasklet_schedule(&info->tlet); +} + +static void uart_stop(struct tty_struct *tty) +{ + struct uart_info *info = tty->driver_data; + struct uart_port *port = info->port; + + port->ops->stop_tx(port, 1); +} + +static void __uart_start(struct tty_struct *tty) +{ + struct uart_info *info = tty->driver_data; + struct uart_port *port = info->port; + + if (!uart_circ_empty(&info->xmit) && info->xmit.buf && + !tty->stopped && !tty->hw_stopped) + port->ops->start_tx(port, 1); +} + +static void uart_start(struct tty_struct *tty) +{ + struct uart_info *info = tty->driver_data; + unsigned long flags; + + pm_access(info->state->pm); + + spin_lock_irqsave(&info->port->lock, flags); + __uart_start(tty); + spin_unlock_irqrestore(&info->port->lock, flags); +} + +static void uart_tasklet_action(unsigned long data) +{ + struct uart_info *info = (struct uart_info *)data; + struct tty_struct *tty; + + tty = info->tty; + if (!tty || !test_and_clear_bit(EVT_WRITE_WAKEUP, &info->event)) + return; + + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); +} + +static inline void +uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) +{ + unsigned long flags; + unsigned int old; + + spin_lock_irqsave(&port->lock, flags); + old = port->mctrl; + port->mctrl = (old & ~clear) | set; + if (old != port->mctrl) + port->ops->set_mctrl(port, port->mctrl); + spin_unlock_irqrestore(&port->lock, flags); +} + +#define uart_set_mctrl(port,set) uart_update_mctrl(port,set,0) +#define uart_clear_mctrl(port,clear) uart_update_mctrl(port,0,clear) + +static inline void uart_update_altspeed(struct uart_info *info) +{ + unsigned int flags = info->port->flags & UPF_SPD_MASK; + + if (flags == UPF_SPD_HI) + info->tty->alt_speed = 57600; + if (flags == UPF_SPD_VHI) + info->tty->alt_speed = 115200; + if (flags == UPF_SPD_SHI) + info->tty->alt_speed = 230400; + if (flags == UPF_SPD_WARP) + info->tty->alt_speed = 460800; +} + +/* + * Startup the port. This will be called once per open. All calls + * will be serialised by the global port semaphore. + */ +static int uart_startup(struct uart_info *info, int init_hw) +{ + struct uart_port *port = info->port; + unsigned long page; + int retval = 0; + + if (info->flags & UIF_INITIALIZED) + return 0; + + /* + * Set the TTY IO error marker - we will only clear this + * once we have successfully opened the port. Also set + * up the tty->alt_speed kludge + */ + if (info->tty) { + set_bit(TTY_IO_ERROR, &info->tty->flags); + uart_update_altspeed(info); + } + + if (port->type == PORT_UNKNOWN) + return 0; + + /* + * Initialise and allocate the transmit and temporary + * buffer. + */ + if (!info->xmit.buf) { + page = get_zeroed_page(GFP_KERNEL); + if (!page) + return -ENOMEM; + + info->xmit.buf = (unsigned char *) page; + info->tmpbuf = info->xmit.buf + UART_XMIT_SIZE; + init_MUTEX(&info->tmpbuf_sem); + uart_circ_clear(&info->xmit); + } + + port->mctrl = 0; + + retval = port->ops->startup(port); + if (retval == 0) { + if (init_hw) { + /* + * Initialise the hardware port settings. + */ + uart_change_speed(info, NULL); + + /* + * Setup the RTS and DTR signals once the + * port is open and ready to respond. + */ + if (info->tty->termios->c_cflag & CBAUD) + uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); + } + + info->flags |= UIF_INITIALIZED; + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + } + + if (retval && capable(CAP_SYS_ADMIN)) + retval = 0; + + return retval; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. Calls to + * uart_shutdown are serialised by port_sem. + */ +static void uart_shutdown(struct uart_info *info) +{ + struct uart_port *port = info->port; + + if (!(info->flags & UIF_INITIALIZED)) + return; + + /* + * Turn off DTR and RTS early. + */ + if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) + uart_clear_mctrl(info->port, TIOCM_DTR | TIOCM_RTS); + + /* + * clear delta_msr_wait queue to avoid mem leaks: we may free + * the irq here so the queue might never be woken up. Note + * that we won't end up waiting on delta_msr_wait again since + * any outstanding file descriptors should be pointing at + * hung_up_tty_fops now. + */ + wake_up_interruptible(&info->delta_msr_wait); + + /* + * Free the IRQ and disable the port. + */ + port->ops->shutdown(port); + + /* + * Ensure that the IRQ handler isn't running on another CPU. + */ + synchronize_irq(port->irq); + + /* + * Free the transmit buffer page. + */ + if (info->xmit.buf) { + free_page((unsigned long)info->xmit.buf); + info->xmit.buf = NULL; + info->tmpbuf = NULL; + } + + /* + * kill off our tasklet + */ + tasklet_kill(&info->tlet); + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~UIF_INITIALIZED; +} + +static inline +unsigned int uart_calculate_quot(struct uart_info *info, unsigned int baud) +{ + struct uart_port *port = info->port; + unsigned int quot; + + /* Special case: B0 rate */ + if (baud == 0) + baud = 9600; + + /* Old HI/VHI/custom speed handling */ + if (baud == 38400 && + ((port->flags & UPF_SPD_MASK) == UPF_SPD_CUST)) + quot = info->state->custom_divisor; + else + quot = port->uartclk / (16 * baud); + + return quot; +} + +static void +uart_change_speed(struct uart_info *info, struct termios *old_termios) +{ + struct uart_port *port = info->port; + unsigned int quot, cflag, bits, try; + + /* + * If we have no tty, termios, or the port does not exist, + * then we can't set the parameters for this port. + */ + if (!info->tty || !info->tty->termios || port->type == PORT_UNKNOWN) + return; + + /* + * Set flags based on termios cflag + */ + cflag = info->tty->termios->c_cflag; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: + bits = 7; + break; + case CS6: + bits = 8; + break; + case CS7: + bits = 9; + break; + default: + bits = 10; + break; // CS8 + } + + if (cflag & CSTOPB) + bits++; + if (cflag & PARENB) + bits++; + + for (try = 0; try < 3; try ++) { + unsigned int baud; + + /* Determine divisor based on baud rate */ + baud = tty_get_baud_rate(info->tty); + quot = uart_calculate_quot(info, baud); + if (quot) + break; + + /* + * Oops, the quotient was zero. Try again with + * the old baud rate if possible. + */ + info->tty->termios->c_cflag &= ~CBAUD; + if (old_termios) { + info->tty->termios->c_cflag |= + (old_termios->c_cflag & CBAUD); + old_termios = NULL; + continue; + } + + /* + * As a last resort, if the quotient is zero, + * default to 9600 bps + */ + info->tty->termios->c_cflag |= B9600; + } + + /* + * The total number of bits to be transmitted in the fifo. + */ + bits = bits * port->fifosize; + + /* + * Figure the timeout to send the above number of bits. + * Add .02 seconds of slop + */ + port->timeout = (HZ * bits) / (port->uartclk / (16 * quot)) + HZ/50; + + if (cflag & CRTSCTS) + info->flags |= UIF_CTS_FLOW; + else + info->flags &= ~UIF_CTS_FLOW; + if (cflag & CLOCAL) + info->flags &= ~UIF_CHECK_CD; + else + info->flags |= UIF_CHECK_CD; + + port->ops->change_speed(port, cflag, info->tty->termios->c_iflag, quot); +} + +static inline void +__uart_put_char(struct uart_port *port, struct circ_buf *circ, unsigned char c) +{ + unsigned long flags; + + if (!circ->buf) + return; + + spin_lock_irqsave(&port->lock, flags); + if (uart_circ_chars_free(circ) != 0) { + circ->buf[circ->head] = c; + circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); + } + spin_unlock_irqrestore(&port->lock, flags); +} + +static inline int +__uart_user_write(struct uart_port *port, struct circ_buf *circ, + const unsigned char *buf, int count) +{ + unsigned long flags; + int c, ret = 0; + + if (down_interruptible(&port->info->tmpbuf_sem)) + return -EINTR; + + while (1) { + int c1; + c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) + break; + + c -= copy_from_user(port->info->tmpbuf, buf, c); + if (!c) { + if (!ret) + ret = -EFAULT; + break; + } + spin_lock_irqsave(&port->lock, flags); + c1 = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); + if (c1 < c) + c = c1; + memcpy(circ->buf + circ->head, port->info->tmpbuf, c); + circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); + spin_unlock_irqrestore(&port->lock, flags); + buf += c; + count -= c; + ret += c; + } + up(&port->info->tmpbuf_sem); + + return ret; +} + +static inline int +__uart_kern_write(struct uart_port *port, struct circ_buf *circ, + const unsigned char *buf, int count) +{ + unsigned long flags; + int c, ret = 0; + + spin_lock_irqsave(&port->lock, flags); + while (1) { + c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); + if (count < c) + c = count; + if (c <= 0) + break; + memcpy(circ->buf + circ->head, buf, c); + circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); + buf += c; + count -= c; + ret += c; + } + spin_unlock_irqrestore(&port->lock, flags); + + return ret; +} + +static void uart_put_char(struct tty_struct *tty, unsigned char ch) +{ + struct uart_info *info = tty->driver_data; + + if (tty) + __uart_put_char(info->port, &info->xmit, ch); +} + +static void uart_flush_chars(struct tty_struct *tty) +{ + uart_start(tty); +} + +static int +uart_write(struct tty_struct *tty, int from_user, const unsigned char * buf, + int count) +{ + struct uart_info *info = tty->driver_data; + int ret; + + if (!tty || !info->xmit.buf) + return 0; + + if (from_user) + ret = __uart_user_write(info->port, &info->xmit, buf, count); + else + ret = __uart_kern_write(info->port, &info->xmit, buf, count); + + uart_start(tty); + return ret; +} + +static int uart_write_room(struct tty_struct *tty) +{ + struct uart_info *info = tty->driver_data; + + return uart_circ_chars_free(&info->xmit); +} + +static int uart_chars_in_buffer(struct tty_struct *tty) +{ + struct uart_info *info = tty->driver_data; + + return uart_circ_chars_pending(&info->xmit); +} + +static void uart_flush_buffer(struct tty_struct *tty) +{ + struct uart_info *info = tty->driver_data; + unsigned long flags; + + DPRINTK("uart_flush_buffer(%d) called\n", + MINOR(tty->device) - tty->driver.minor_start); + + spin_lock_irqsave(&info->port->lock, flags); + uart_circ_clear(&info->xmit); + spin_unlock_irqrestore(&info->port->lock, flags); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * This function is used to send a high-priority XON/XOFF character to + * the device + */ +static void uart_send_xchar(struct tty_struct *tty, char ch) +{ + struct uart_info *info = tty->driver_data; + struct uart_port *port = info->port; + + if (port->ops->send_xchar) + port->ops->send_xchar(port, ch); + else { + port->x_char = ch; + if (ch) + port->ops->start_tx(port, 0); + } +} + +static void uart_throttle(struct tty_struct *tty) +{ + struct uart_info *info = tty->driver_data; + + if (I_IXOFF(tty)) + uart_send_xchar(tty, STOP_CHAR(tty)); + + if (tty->termios->c_cflag & CRTSCTS) + uart_clear_mctrl(info->port, TIOCM_RTS); +} + +static void uart_unthrottle(struct tty_struct *tty) +{ + struct uart_info *info = tty->driver_data; + struct uart_port *port = info->port; + + if (I_IXOFF(tty)) { + if (port->x_char) + port->x_char = 0; + else + uart_send_xchar(tty, START_CHAR(tty)); + } + + if (tty->termios->c_cflag & CRTSCTS) + uart_set_mctrl(port, TIOCM_RTS); +} + +static int uart_get_info(struct uart_info *info, struct serial_struct *retinfo) +{ + struct uart_state *state = info->state; + struct uart_port *port = info->port; + struct serial_struct tmp; + + memset(&tmp, 0, sizeof(tmp)); + tmp.type = port->type; + tmp.line = port->line; + tmp.port = port->iobase; + if (HIGH_BITS_OFFSET) + tmp.port_high = port->iobase >> HIGH_BITS_OFFSET; + tmp.irq = port->irq; + tmp.flags = port->flags | info->flags; + tmp.xmit_fifo_size = port->fifosize; + tmp.baud_base = port->uartclk / 16; + tmp.close_delay = state->close_delay; + tmp.closing_wait = state->closing_wait; + tmp.custom_divisor = state->custom_divisor; + tmp.hub6 = port->hub6; + tmp.io_type = port->iotype; + tmp.iomem_reg_shift = port->regshift; + tmp.iomem_base = (void *)port->mapbase; + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int +uart_set_info(struct uart_info *info, struct serial_struct *newinfo) +{ + struct serial_struct new_serial; + struct uart_state *state = info->state; + struct uart_port *port = info->port; + unsigned long new_port; + unsigned int change_irq, change_port, old_flags; + unsigned int old_custom_divisor; + int retval = 0; + + if (copy_from_user(&new_serial, newinfo, sizeof(new_serial))) + return -EFAULT; + + new_port = new_serial.port; + if (HIGH_BITS_OFFSET) + new_port += (unsigned long) new_serial.port_high << HIGH_BITS_OFFSET; + + new_serial.irq = irq_cannonicalize(new_serial.irq); + + /* + * This semaphore protects state->count. It is also + * very useful to prevent opens. Also, take the + * port configuration semaphore to make sure that a + * module insertion/removal doesn't change anything + * under us. + */ + down(&port_sem); + + change_irq = new_serial.irq != port->irq; + + /* + * Since changing the 'type' of the port changes its resource + * allocations, we should treat type changes the same as + * IO port changes. + */ + change_port = new_port != port->iobase || + (unsigned long)new_serial.iomem_base != port->mapbase || + new_serial.hub6 != port->hub6 || + new_serial.io_type != port->iotype || + new_serial.iomem_reg_shift != port->regshift || + new_serial.type != port->type; + + old_flags = port->flags; + old_custom_divisor = state->custom_divisor; + + if (!capable(CAP_SYS_ADMIN)) { + retval = -EPERM; + if (change_irq || change_port || + (new_serial.baud_base != port->uartclk / 16) || + (new_serial.close_delay != state->close_delay) || + (new_serial.closing_wait != state->closing_wait) || + (new_serial.xmit_fifo_size != port->fifosize) || + (((new_serial.flags ^ old_flags) & ~UPF_USR_MASK) != 0)) + goto exit; + port->flags = ((port->flags & ~UPF_USR_MASK) | + (new_serial.flags & UPF_USR_MASK)); + state->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + /* + * Ask the low level driver to verify the settings. + */ + if (port->ops->verify_port) + retval = port->ops->verify_port(port, &new_serial); + + if ((new_serial.irq >= NR_IRQS) || (new_serial.irq < 0) || + (new_serial.baud_base < 9600)) + retval = -EINVAL; + + if (retval) + goto exit; + + if (change_port || change_irq) { + retval = -EBUSY; + + /* + * Make sure that we are the sole user of this port. + */ + if (state->count > 1 || info->blocked_open != 0) + goto exit; + + /* + * We need to shutdown the serial port at the old + * port/type/irq combination. + */ + uart_shutdown(info); + } + + if (change_port) { + unsigned long old_iobase, old_mapbase; + unsigned int old_type, old_iotype, old_hub6, old_shift; + + old_iobase = port->iobase; + old_mapbase = port->mapbase; + old_type = port->type; + old_hub6 = port->hub6; + old_iotype = port->iotype; + old_shift = port->regshift; + + /* + * Free and release old regions + */ + if (old_type != PORT_UNKNOWN) + port->ops->release_port(port); + + port->iobase = new_port; + port->type = new_serial.type; + port->hub6 = new_serial.hub6; + port->iotype = new_serial.io_type; + port->regshift = new_serial.iomem_reg_shift; + port->mapbase = (unsigned long)new_serial.iomem_base; + + /* + * Claim and map the new regions + */ + if (port->type != PORT_UNKNOWN) + retval = port->ops->request_port(port); + + /* + * If we fail to request resources for the + * new port, try to restore the old settings. + */ + if (retval && old_type != PORT_UNKNOWN) { + port->iobase = old_iobase; + port->type = old_type; + port->hub6 = old_hub6; + port->iotype = old_iotype; + port->regshift = old_shift; + port->mapbase = old_mapbase; + retval = port->ops->request_port(port); + /* + * If we failed to restore the old settings, + * we fail like this. + */ + if (retval) + port->type = PORT_UNKNOWN; + + /* + * We failed anyway. + */ + retval = -EBUSY; + } + } + + port->irq = new_serial.irq; + port->uartclk = new_serial.baud_base * 16; + port->flags = new_serial.flags & UPF_FLAGS; + state->custom_divisor = new_serial.custom_divisor; + state->close_delay = new_serial.close_delay * HZ / 100; + state->closing_wait = new_serial.closing_wait * HZ / 100; + port->fifosize = new_serial.xmit_fifo_size; + info->tty->low_latency = (port->flags & UPF_LOW_LATENCY) ? 1 : 0; + + check_and_exit: + retval = 0; + if (port->type == PORT_UNKNOWN) + goto exit; + if (info->flags & UIF_INITIALIZED) { + if (((old_flags ^ port->flags) & UPF_SPD_MASK) || + old_custom_divisor != state->custom_divisor) { + uart_update_altspeed(info); + uart_change_speed(info, NULL); + } + } else + retval = uart_startup(info, 1); + exit: + up(&port_sem); + return retval; +} + + +/* + * uart_get_lsr_info - get line status register info + */ +static int uart_get_lsr_info(struct uart_info *info, unsigned int *value) +{ + struct uart_port *port = info->port; + unsigned int result; + + result = port->ops->tx_empty(port); + + /* + * If we're about to load something into the transmit + * register, we'll pretend the transmitter isn't empty to + * avoid a race condition (depending on when the transmit + * interrupt happens). + */ + if (info->port->x_char || + ((uart_circ_chars_pending(&info->xmit) > 0) && + !info->tty->stopped && !info->tty->hw_stopped)) + result &= ~TIOCSER_TEMT; + + return put_user(result, value); +} + +static int uart_get_modem_info(struct uart_port *port, unsigned int *value) +{ + unsigned int result = port->mctrl; + + result |= port->ops->get_mctrl(port); + + return put_user(result, value); +} + +static int +uart_set_modem_info(struct uart_port *port, unsigned int cmd, + unsigned int *value) +{ + unsigned int arg, set, clear; + int ret = 0; + + if (get_user(arg, value)) + return -EFAULT; + + set = clear = 0; + switch (cmd) { + case TIOCMBIS: + set = arg; + break; + case TIOCMBIC: + clear = arg; + break; + case TIOCMSET: + set = arg; + clear = ~arg; + break; + default: + ret = -EINVAL; + break; + } + if (ret == 0) + uart_update_mctrl(port, set, clear); + return ret; +} + +static void uart_break_ctl(struct tty_struct *tty, int break_state) +{ + struct uart_info *info = tty->driver_data; + struct uart_port *port = info->port; + + BUG_ON(!kernel_locked()); + + if (port->type != PORT_UNKNOWN) + port->ops->break_ctl(port, break_state); +} + +static int uart_do_autoconfig(struct uart_info *info) +{ + struct uart_port *port = info->port; + int flags, ret; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + /* + * Take the 'count' lock. This prevents count + * from incrementing, and hence any extra opens + * of the port while we're auto-configging. + */ + if (down_interruptible(&port_sem)) + return -ERESTARTSYS; + + ret = -EBUSY; + if (info->state->count == 1 && info->blocked_open == 0) { + uart_shutdown(info); + + /* + * If we already have a port type configured, + * we must release its resources. + */ + if (port->type != PORT_UNKNOWN) + port->ops->release_port(port); + + flags = UART_CONFIG_TYPE; + if (port->flags & UPF_AUTO_IRQ) + flags |= UART_CONFIG_IRQ; + + /* + * This will claim the ports resources if + * a port is found. + */ + port->ops->config_port(port, flags); + + ret = uart_startup(info, 1); + } + up(&port_sem); + return ret; +} + +static int +uart_wait_modem_status(struct uart_info *info, unsigned long arg) +{ + struct uart_port *port = info->port; + DECLARE_WAITQUEUE(wait, current); + struct uart_icount cprev, cnow; + int ret; + + /* + * note the counters on entry + */ + spin_lock_irq(&port->lock); + memcpy(&cprev, &port->icount, sizeof(struct uart_icount)); + spin_unlock_irq(&port->lock); + + /* + * Force modem status interrupts on + */ + port->ops->enable_ms(port); + + add_wait_queue(&info->delta_msr_wait, &wait); + for (;;) { + spin_lock_irq(&port->lock); + memcpy(&cnow, &port->icount, sizeof(struct uart_icount)); + spin_unlock_irq(&port->lock); + + set_current_state(TASK_INTERRUPTIBLE); + + if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || + ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || + ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || + ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { + ret = 0; + break; + } + + schedule(); + + /* see if a signal did it */ + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + + cprev = cnow; + } + + current->state = TASK_RUNNING; + remove_wait_queue(&info->delta_msr_wait, &wait); + + return ret; +} + +/* + * Called via sys_ioctl under the BKL. We can use spin_lock_irq() here. + */ +static int +uart_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct uart_info *info = tty->driver_data; + struct serial_icounter_struct icount; + struct uart_icount cnow; + int ret = -ENOIOCTLCMD; + + BUG_ON(!kernel_locked()); + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && + (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TIOCMGET: + ret = uart_get_modem_info(info->port, + (unsigned int *)arg); + break; + + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + ret = uart_set_modem_info(info->port, cmd, + (unsigned int *)arg); + break; + + case TIOCGSERIAL: + ret = uart_get_info(info, (struct serial_struct *)arg); + break; + + case TIOCSSERIAL: + ret = uart_set_info(info, (struct serial_struct *)arg); + break; + + case TIOCSERCONFIG: + ret = uart_do_autoconfig(info); + break; + + case TIOCSERGETLSR: /* Get line status register */ + ret = uart_get_lsr_info(info, (unsigned int *)arg); + break; + + /* + * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change + * - mask passed in arg for lines of interest + * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) + * Caller should use TIOCGICOUNT to see which one it was + */ + case TIOCMIWAIT: + ret = uart_wait_modem_status(info, arg); + break; + + /* + * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) + * Return: write counters to the user passed counter struct + * NB: both 1->0 and 0->1 transitions are counted except for + * RI where only 0->1 is counted. + */ + case TIOCGICOUNT: + spin_lock_irq(&info->port->lock); + memcpy(&cnow, &info->port->icount, + sizeof(struct uart_icount)); + spin_unlock_irq(&info->port->lock); + + icount.cts = cnow.cts; + icount.dsr = cnow.dsr; + icount.rng = cnow.rng; + icount.dcd = cnow.dcd; + icount.rx = cnow.rx; + icount.tx = cnow.tx; + icount.frame = cnow.frame; + icount.overrun = cnow.overrun; + icount.parity = cnow.parity; + icount.brk = cnow.brk; + icount.buf_overrun = cnow.buf_overrun; + + ret = copy_to_user((void *)arg, &icount, sizeof(icount)) + ? -EFAULT : 0; + break; + + case TIOCSERGWILD: /* obsolete */ + case TIOCSERSWILD: /* obsolete */ + ret = 0; + break; + + default: { + struct uart_port *port = info->port; + if (port->ops->ioctl) + ret = port->ops->ioctl(port, cmd, arg); + break; + } + } + return ret; +} + +static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct uart_info *info = tty->driver_data; + unsigned long flags; + unsigned int cflag = tty->termios->c_cflag; + + BUG_ON(!kernel_locked()); + + /* + * These are the bits that are used to setup various + * flags in the low level driver. + */ +#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) + + if ((cflag ^ old_termios->c_cflag) == 0 && + RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) + return; + + uart_change_speed(info, old_termios); + + /* Handle transition to B0 status */ + if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) + uart_clear_mctrl(info->port, TIOCM_RTS | TIOCM_DTR); + + /* Handle transition away from B0 status */ + if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { + unsigned int mask = TIOCM_DTR; + if (!(cflag & CRTSCTS) || + !test_bit(TTY_THROTTLED, &tty->flags)) + mask |= TIOCM_RTS; + uart_set_mctrl(info->port, mask); + } + + /* Handle turning off CRTSCTS */ + if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { + spin_lock_irqsave(&info->port->lock, flags); + tty->hw_stopped = 0; + __uart_start(tty); + spin_unlock_irqrestore(&info->port->lock, flags); + } + +#if 0 + /* + * No need to wake up processes in open wait, since they + * sample the CLOCAL flag once, and don't recheck it. + * XXX It's not clear whether the current behavior is correct + * or not. Hence, this may change..... + */ + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); +#endif +} + +/* + * In 2.4.5, calls to this will be serialized via the BKL in + * linux/drivers/char/tty_io.c:tty_release() + * linux/drivers/char/tty_io.c:do_tty_handup() + */ +static void uart_close(struct tty_struct *tty, struct file *filp) +{ + struct uart_driver *drv = (struct uart_driver *)tty->driver.driver_state; + struct uart_info *info = tty->driver_data; + struct uart_port *port = info->port; + struct uart_state *state; + unsigned long flags; + + BUG_ON(!kernel_locked()); + + if (!info) + return; + + state = info->state; + + DPRINTK("uart_close() called\n"); + + /* + * This is safe, as long as the BKL exists in + * do_tty_hangup(), and we're protected by the BKL. + */ + if (tty_hung_up_p(filp)) + goto done; + + spin_lock_irqsave(&info->port->lock, flags); + if ((tty->count == 1) && (state->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. state->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("uart_close: bad serial port count; tty->count is 1, " + "state->count is %d\n", state->count); + state->count = 1; + } + if (--state->count < 0) { + printk("rs_close: bad serial port count for %s%d: %d\n", + tty->driver.name, info->port->line, state->count); + state->count = 0; + } + if (state->count) { + spin_unlock_irqrestore(&info->port->lock, flags); + goto done; + } + + /* + * The UIF_CLOSING flag protects us against further opens + * of this port. + */ + info->flags |= UIF_CLOSING; + spin_unlock_irqrestore(&info->port->lock, flags); + + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->state->closing_wait != USF_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->state->closing_wait); + + /* + * At this point, we stop accepting input. To do this, we + * disable the receive line status interrupts. + */ + if (info->flags & UIF_INITIALIZED) { + port->ops->stop_rx(port); + /* + * Before we drop DTR, make sure the UART transmitter + * has completely drained; this is especially + * important if there is a transmit FIFO! + */ + uart_wait_until_sent(tty, port->timeout); + } + down(&port_sem); + uart_shutdown(info); + up(&port_sem); + uart_flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = NULL; + if (info->blocked_open) { + if (info->state->close_delay) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(info->state->close_delay); + set_current_state(TASK_RUNNING); + } + } else { +#ifdef CONFIG_PM + /* + * Put device into D3 state. + */ + pm_send(info->state->pm, PM_SUSPEND, (void *)3); +#else + if (port->ops->pm) + port->ops->pm(port, 3, 0); +#endif + } + + /* + * Wake up anyone trying to open this port. + */ + info->flags &= ~(UIF_NORMAL_ACTIVE|UIF_CLOSING); + wake_up_interruptible(&info->open_wait); + + done: + if (drv->owner) + __MOD_DEC_USE_COUNT(drv->owner); +} + +static void uart_wait_until_sent(struct tty_struct *tty, int timeout) +{ + struct uart_info *info = tty->driver_data; + struct uart_port *port = info->port; + unsigned long char_time, expire; + + BUG_ON(!kernel_locked()); + + if (port->type == PORT_UNKNOWN || port->fifosize == 0) + return; + + /* + * Set the check interval to be 1/5 of the estimated time to + * send a single character, and make it at least 1. The check + * interval should also be less than the timeout. + * + * Note: we have to use pretty tight timings here to satisfy + * the NIST-PCTS. + */ + char_time = (port->timeout - HZ/50) / port->fifosize; + char_time = char_time / 5; + if (char_time == 0) + char_time = 1; + if (timeout && timeout < char_time) + char_time = timeout; + + /* + * If the transmitter hasn't cleared in twice the approximate + * amount of time to send the entire FIFO, it probably won't + * ever clear. This assumes the UART isn't doing flow + * control, which is currently the case. Hence, if it ever + * takes longer than port->timeout, this is probably due to a + * UART bug of some kind. So, we clamp the timeout parameter at + * 2*port->timeout. + */ + if (timeout == 0 || timeout > 2 * port->timeout) + timeout = 2 * port->timeout; + + expire = jiffies + timeout; + + DPRINTK("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n", + port->line, jiffies, expire); + + /* + * Check whether the transmitter is empty every 'char_time'. + * 'timeout' / 'expire' give us the maximum amount of time + * we wait. + */ + while (!port->ops->tx_empty(port)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(char_time); + if (signal_pending(current)) + break; + if (time_after(jiffies, expire)) + break; + } + set_current_state(TASK_RUNNING); /* might not be needed */ +} + +/* + * This is called with the BKL held in + * linux/drivers/char/tty_io.c:do_tty_hangup() + * We're called from the eventd thread, so we can sleep for + * a _short_ time only. + */ +static void uart_hangup(struct tty_struct *tty) +{ + struct uart_info *info = tty->driver_data; + struct uart_state *state = info->state; + + BUG_ON(!kernel_locked()); + + uart_flush_buffer(tty); + down(&port_sem); + if (info->flags & UIF_CLOSING) { + up(&port_sem); + return; + } + uart_shutdown(info); + info->event = 0; + state->count = 0; + info->flags &= ~UIF_NORMAL_ACTIVE; + info->tty = NULL; + up(&port_sem); + wake_up_interruptible(&info->open_wait); +} + +/* + * Copy across the serial console cflag setting into the termios settings + * for the initial open of the port. This allows continuity between the + * kernel settings, and the settings init adopts when it opens the port + * for the first time. + */ +static void uart_update_termios(struct uart_info *info) +{ + struct tty_struct *tty = info->tty; + +#ifdef CONFIG_SERIAL_CORE_CONSOLE + struct console *c = info->port->cons; + + if (c && c->cflag && c->index == info->port->line) { + tty->termios->c_cflag = c->cflag; + c->cflag = 0; + } +#endif + + /* + * If the device failed to grab its irq resources, + * or some other error occurred, don't try to talk + * to the port hardware. + */ + if (!(tty->flags & (1 << TTY_IO_ERROR))) { + /* + * Make termios settings take effect. + */ + uart_change_speed(info, NULL); + + /* + * And finally enable the RTS and DTR signals. + */ + if (tty->termios->c_cflag & CBAUD) + uart_set_mctrl(info->port, TIOCM_DTR | TIOCM_RTS); + } +} + +static int +uart_block_til_ready(struct file *filp, struct uart_info *info) +{ + DECLARE_WAITQUEUE(wait, current); + struct uart_state *state = info->state; + struct uart_port *port = info->port; + + info->blocked_open++; + state->count--; + + add_wait_queue(&info->open_wait, &wait); + while (1) { + set_current_state(TASK_INTERRUPTIBLE); + + /* + * If we have been hung up, tell userspace/restart open. + */ + if (tty_hung_up_p(filp)) + break; + + /* + * If the device is in the middle of being closed, block + * until it's done. We will need to re-initialise the + * port. Hmm, is it legal to block a non-blocking open? + */ + if (info->flags & UIF_CLOSING) + goto wait; + + /* + * If the port has been closed, tell userspace/restart open. + */ + if (!(info->flags & UIF_INITIALIZED)) + break; + + /* + * If non-blocking mode is set, or CLOCAL mode is set, + * we don't want to wait for the modem status lines to + * indicate that the port is ready. + * + * Also, if the port is not enabled/configured, we want + * to allow the open to succeed here. Note that we will + * have set TTY_IO_ERROR for a non-existant port. + */ + if ((filp->f_flags & O_NONBLOCK) || + (info->tty->termios->c_cflag & CLOCAL) || + (info->tty->flags & (1 << TTY_IO_ERROR))) { + break; + } + + /* + * Set DTR to allow modem to know we're waiting. Do + * not set RTS here - we want to make sure we catch + * the data from the modem. + */ + if (info->tty->termios->c_cflag & CBAUD) + uart_set_mctrl(info->port, TIOCM_DTR); + + /* + * and wait for the carrier to indicate that the + * modem is ready for us. + */ + if (port->ops->get_mctrl(port) & TIOCM_CAR) + break; + + wait: + schedule(); + + if (signal_pending(current)) + break; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&info->open_wait, &wait); + + state->count++; + info->blocked_open--; + + if (signal_pending(current)) + return -ERESTARTSYS; + + if (tty_hung_up_p(filp) || !(info->flags & UIF_INITIALIZED)) + return (port->flags & UPF_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS; + + return 0; +} + +static struct uart_info *uart_get(struct uart_driver *drv, int line) +{ + struct uart_state *state = drv->state + line; + struct uart_info *info = NULL; + + down(&port_sem); + if (!state->port) + goto out; + + state->count++; + info = state->info; + + if (!info) { + info = kmalloc(sizeof(struct uart_info), GFP_KERNEL); + if (info) { + memset(info, 0, sizeof(struct uart_info)); + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->delta_msr_wait); + + /* + * Link the info into the other structures. + */ + info->port = state->port; + info->state = state; + state->port->info = info; + + tasklet_init(&info->tlet, uart_tasklet_action, + (unsigned long)info); + state->info = info; + } else + state->count--; + } + + out: + up(&port_sem); + return info; +} + +/* + * In 2.4.5, calls to uart_open are serialised by the BKL in + * linux/fs/devices.c:chrdev_open() + * Note that if this fails, then uart_close() _will_ be called. + * + * In time, we want to scrap the "opening nonpresent ports" + * behaviour and implement an alternative way for setserial + * to set base addresses/ports/types. This will allow us to + * get rid of a certain amount of extra tests. + */ +static int uart_open(struct tty_struct *tty, struct file *filp) +{ + struct uart_driver *drv = (struct uart_driver *)tty->driver.driver_state; + struct uart_info *info; + int retval, line = minor(tty->device) - tty->driver.minor_start; + + BUG_ON(!kernel_locked()); + + DPRINTK("uart_open(%d) called\n", line); + + /* + * tty->driver.num won't change, so we won't fail here with + * tty->driver_data set to something non-NULL (and therefore + * we won't get caught by uart_close()). + */ + retval = -ENODEV; + if (line >= tty->driver.num) + goto fail; + + /* + * If we fail to increment the module use count, we can't have + * any other users of this tty (since this implies that the module + * is about to be unloaded). Therefore, it is safe to set + * tty->driver_data to be NULL, so uart_close() doesn't bite us. + */ + if (!try_inc_mod_count(drv->owner)) { + tty->driver_data = NULL; + goto fail; + } + + /* + * FIXME: This one isn't fun. We can't guarantee that the tty isn't + * already in open, nor can we guarantee the state of tty->driver_data + */ + info = uart_get(drv, line); + retval = -ENOMEM; + if (!info) { + if (tty->driver_data) + goto fail; + else + goto out; + } + + /* + * Once we set tty->driver_data here, we are guaranteed that + * uart_close() will decrement the driver module use count. + * Any failures from here onwards should not touch the count. + */ + tty->driver_data = info; + info->tty = tty; + info->tty->low_latency = (info->port->flags & UPF_LOW_LATENCY) ? 1 : 0; + + /* + * If the port is in the middle of closing, bail out now. + */ + if (tty_hung_up_p(filp) || (info->flags & UIF_CLOSING)) { + wait_event_interruptible(info->open_wait, + !(info->flags & UIF_CLOSING)); + retval = (info->port->flags & UPF_HUP_NOTIFY) ? + -EAGAIN : -ERESTARTSYS; + goto fail; + } + + /* + * Make sure the device is in D0 state. + */ + if (info->state->count == 1) { +#ifdef CONFIG_PM + pm_send(info->state->pm, PM_RESUME, (void *)0); +#else + struct uart_port *port = info->port; + if (port->ops->pm) + port->ops->pm(port, 0, 3); +#endif + } + + /* + * Start up the serial port. We have this semaphore here to + * prevent uart_startup or uart_shutdown being re-entered if + * we sleep while requesting an IRQ. + */ + down(&port_sem); + retval = uart_startup(info, 0); + up(&port_sem); + if (retval) + goto fail; + + /* + * Wait until the port is ready. + */ + retval = uart_block_til_ready(filp, info); + + /* + * If this is the first open to succeed, adjust things to suit. + */ + if (retval == 0 && !(info->flags & UIF_NORMAL_ACTIVE)) { + info->flags |= UIF_NORMAL_ACTIVE; + + uart_update_termios(info); + } + + return retval; + + out: + if (drv->owner) + __MOD_DEC_USE_COUNT(drv->owner); + fail: + return retval; +} + +#ifdef CONFIG_PROC_FS + +static const char *uart_type(struct uart_port *port) +{ + const char *str = NULL; + + if (port->ops->type) + str = port->ops->type(port); + + if (!str) + str = "unknown"; + + return str; +} + +static int uart_line_info(char *buf, struct uart_driver *drv, int i) +{ + struct uart_state *state = drv->state + i; + struct uart_port *port = state->port; + char stat_buf[32]; + unsigned int status; + int ret; + + if (!port) + return 0; + + ret = sprintf(buf, "%d: uart:%s port:%08X irq:%d", + port->line, uart_type(port), + port->iobase, port->irq); + + if (port->type == PORT_UNKNOWN) { + strcat(buf, "\n"); + return ret + 1; + } + + status = port->ops->get_mctrl(port); + + ret += sprintf(buf + ret, " tx:%d rx:%d", + port->icount.tx, port->icount.rx); + if (port->icount.frame) + ret += sprintf(buf + ret, " fe:%d", + port->icount.frame); + if (port->icount.parity) + ret += sprintf(buf + ret, " pe:%d", + port->icount.parity); + if (port->icount.brk) + ret += sprintf(buf + ret, " brk:%d", + port->icount.brk); + if (port->icount.overrun) + ret += sprintf(buf + ret, " oe:%d", + port->icount.overrun); + +#define INFOBIT(bit,str) \ + if (port->mctrl & (bit)) \ + strncat(stat_buf, (str), sizeof(stat_buf) - \ + strlen(stat_buf) - 2) +#define STATBIT(bit,str) \ + if (status & (bit)) \ + strncat(stat_buf, (str), sizeof(stat_buf) - \ + strlen(stat_buf) - 2) + + stat_buf[0] = '\0'; + stat_buf[1] = '\0'; + INFOBIT(TIOCM_RTS, "|RTS"); + STATBIT(TIOCM_CTS, "|CTS"); + INFOBIT(TIOCM_DTR, "|DTR"); + STATBIT(TIOCM_DSR, "|DSR"); + STATBIT(TIOCM_CAR, "|CD"); + STATBIT(TIOCM_RNG, "|RI"); + if (stat_buf[0]) + stat_buf[0] = ' '; + strcat(stat_buf, "\n"); + + ret += sprintf(buf + ret, stat_buf); + return ret; +} + +static int uart_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct tty_driver *ttydrv = data; + struct uart_driver *drv = ttydrv->driver_state; + int i, len = 0, l; + off_t begin = 0; + + len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n", + "", "", ""); + for (i = 0; i < drv->nr && len < PAGE_SIZE - 96; i++) { + l = uart_line_info(page + len, drv, i); + len += l; + if (len + begin > off + count) + goto done; + if (len + begin < off) { + begin += len; + len = 0; + } + } + *eof = 1; + done: + if (off >= len + begin) + return 0; + *start = page + (off - begin); + return (count < begin + len - off) ? count : (begin + len - off); +} +#endif + +#ifdef CONFIG_SERIAL_CORE_CONSOLE +/* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ +struct uart_port * __init +uart_get_console(struct uart_port *ports, int nr, struct console *co) +{ + int idx = co->index; + + if (idx < 0 || idx >= nr || (ports[idx].iobase == 0 && + ports[idx].membase == NULL)) + for (idx = 0; idx < nr; idx++) + if (ports[idx].iobase != 0 || + ports[idx].membase != NULL) + break; + + co->index = idx; + + return ports + idx; +} + +/** + * uart_parse_options - Parse serial port baud/parity/bits/flow contro. + * @options: pointer to option string + * @baud: pointer to an 'int' variable for the baud rate. + * @parity: pointer to an 'int' variable for the parity. + * @bits: pointer to an 'int' variable for the number of data bits. + * @flow: pointer to an 'int' variable for the flow control character. + * + * uart_parse_options decodes a string containing the serial console + * options. The format of the string is <baud><parity><bits><flow>, + * eg: 115200n8r + */ +void __init +uart_parse_options(char *options, int *baud, int *parity, int *bits, int *flow) +{ + char *s = options; + + *baud = simple_strtoul(s, NULL, 10); + while (*s >= '0' && *s <= '9') + s++; + if (*s) + *parity = *s++; + if (*s) + *bits = *s++ - '0'; + if (*s) + *flow = *s; +} + +struct baud_rates { + unsigned int rate; + unsigned int cflag; +}; + +static struct baud_rates baud_rates[] = { + { 921600, B921600 }, + { 460800, B460800 }, + { 230400, B230400 }, + { 115200, B115200 }, + { 57600, B57600 }, + { 38400, B38400 }, + { 19200, B19200 }, + { 9600, B9600 }, + { 4800, B4800 }, + { 2400, B2400 }, + { 1200, B1200 }, + { 0, B38400 } +}; + +/** + * uart_set_options - setup the serial console parameters + * @port: pointer to the serial ports uart_port structure + * @co: console pointer + * @baud: baud rate + * @parity: parity character - 'n' (none), 'o' (odd), 'e' (even) + * @bits: number of data bits + * @flow: flow control character - 'r' (rts) + */ +int __init +uart_set_options(struct uart_port *port, struct console *co, + int baud, int parity, int bits, int flow) +{ + unsigned int cflag = CREAD | HUPCL | CLOCAL; + unsigned int quot; + int i; + + /* + * Construct a cflag setting. + */ + for (i = 0; baud_rates[i].rate; i++) + if (baud_rates[i].rate <= baud) + break; + + cflag |= baud_rates[i].cflag; + + if (bits == 7) + cflag |= CS7; + else + cflag |= CS8; + + switch (parity) { + case 'o': case 'O': + cflag |= PARODD; + /*fall through*/ + case 'e': case 'E': + cflag |= PARENB; + break; + } + + if (flow == 'r') + cflag |= CRTSCTS; + + co->cflag = cflag; + quot = (port->uartclk / (16 * baud)); + port->ops->change_speed(port, cflag, 0, quot); + + return 0; +} + +extern void ambauart_console_init(void); +extern void anakin_console_init(void); +extern void clps711xuart_console_init(void); +extern void rs285_console_init(void); +extern void sa1100_rs_console_init(void); +extern void serial8250_console_init(void); +extern void uart00_console_init(void); + +/* + * Central "initialise all serial consoles" container. Needs to be killed. + */ +void __init uart_console_init(void) +{ +#ifdef CONFIG_SERIAL_AMBA_CONSOLE + ambauart_console_init(); +#endif +#ifdef CONFIG_SERIAL_ANAKIN_CONSOLE + anakin_console_init(); +#endif +#ifdef CONFIG_SERIAL_CLPS711X_CONSOLE + clps711xuart_console_init(); +#endif +#ifdef CONFIG_SERIAL_21285_CONSOLE + rs285_console_init(); +#endif +#ifdef CONFIG_SERIAL_SA1100_CONSOLE + sa1100_rs_console_init(); +#endif +#ifdef CONFIG_SERIAL_8250_CONSOLE + serial8250_console_init(); +#endif +#ifdef CONFIG_SERIAL_UART00_CONSOLE + uart00_console_init(); +#endif +} +#endif /* CONFIG_SERIAL_CORE_CONSOLE */ + +#ifdef CONFIG_PM +/* + * Serial port power management. + * + * This is pretty coarse at the moment - either all on or all off. We + * should probably some day do finer power management here some day. + * + * We don't actually save any state; the serial driver already has the + * state held internally to re-setup the port when we come out of D3. + */ +static int uart_pm_set_state(struct uart_state *state, int pm_state, int oldstate) +{ + struct uart_port *port; + struct uart_ops *ops; + int running = state->info && + state->info->flags & UIF_INITIALIZED; + + down(&port_sem); + + if (!state->port || state->port->type == PORT_UNKNOWN) { + up(&port_sem); + return 0; + } + + port = state->port; + ops = port->ops; + + DPRINTK("pm: %08x: %d -> %d, %srunning\n", + port->iobase, dev->state, pm_state, running ? "" : "not "); + + if (pm_state == 0) { + if (ops->pm) + ops->pm(port, pm_state, oldstate); + if (running) { + /* + * The port lock isn't taken here - + * the port isn't initialised. + */ + ops->set_mctrl(port, 0); + ops->startup(port); + uart_change_speed(state->info, NULL); + spin_lock_irq(&port->lock); + ops->set_mctrl(port, port->mctrl); + ops->start_tx(port, 0); + spin_unlock_irq(&port->lock); + } + + /* + * Re-enable the console device after suspending. + */ + if (port->cons && port->cons->index == port->line) + port->cons->flags |= CON_ENABLED; + } else if (pm_state == 1) { + if (ops->pm) + ops->pm(port, pm_state, oldstate); + } else { + /* + * Disable the console device before suspending. + */ + if (port->cons && port->cons->index == port->line) + port->cons->flags &= ~CON_ENABLED; + + if (running) { + ops->stop_tx(port, 0); + spin_lock_irq(&port->lock); + ops->set_mctrl(port, 0); + spin_unlock_irq(&port->lock); + ops->stop_rx(port); + ops->shutdown(port); + } + if (ops->pm) + ops->pm(port, pm_state, oldstate); + } + up(&port_sem); + + return 0; +} + +/* + * Wakeup support. + */ +static int uart_pm_set_wakeup(struct uart_state *state, int data) +{ + int err = 0; + + if (state->port->ops->set_wake) + err = state->port->ops->set_wake(state->port, data); + + return err; +} + +static int uart_pm(struct pm_dev *dev, pm_request_t rqst, void *data) +{ + struct uart_state *state = dev->data; + int err = 0; + + switch (rqst) { + case PM_SUSPEND: + case PM_RESUME: + err = uart_pm_set_state(state, (int)data, dev->state); + break; + + case PM_SET_WAKEUP: + err = uart_pm_set_wakeup(state, (int)data); + break; + } + return err; +} +#endif + +static inline void +uart_report_port(struct uart_driver *drv, struct uart_port *port) +{ + printk("%s%d at ", drv->dev_name, port->line); + switch (port->iotype) { + case UPIO_PORT: + printk("I/O 0x%x", port->iobase); + break; + case UPIO_HUB6: + printk("I/O 0x%x offset 0x%x", port->iobase, port->hub6); + break; + case UPIO_MEM: + printk("MMIO 0x%lx", port->mapbase); + break; + } + printk(" (irq = %d) is a %s\n", port->irq, uart_type(port)); +} + +static void +__uart_register_port(struct uart_driver *drv, struct uart_state *state, + struct uart_port *port) +{ + unsigned int flags; + + state->port = port; + + spin_lock_init(&port->lock); + port->type = PORT_UNKNOWN; + port->cons = drv->cons; + port->info = state->info; + + /* + * If there isn't a port here, don't do anything further. + */ + if (!port->iobase && !port->mapbase) + return; + + /* + * Now do the auto configuration stuff. Note that config_port + * is expected to claim the resources and map the port for us. + */ + flags = UART_CONFIG_TYPE; + if (port->flags & UPF_AUTO_IRQ) + flags |= UART_CONFIG_IRQ; + if (port->flags & UPF_BOOT_AUTOCONF) + port->ops->config_port(port, flags); + + /* + * Register the port whether it's detected or not. This allows + * setserial to be used to alter this ports parameters. + */ + tty_register_devfs(drv->tty_driver, 0, drv->minor + port->line); + + if (port->type != PORT_UNKNOWN) { + unsigned long flags; + + uart_report_port(drv, port); + + /* + * Ensure that the modem control lines are de-activated. + * We probably don't need a spinlock around this, but + */ + spin_lock_irqsave(&port->lock, flags); + port->ops->set_mctrl(port, 0); + spin_unlock_irqrestore(&port->lock, flags); + +#ifdef CONFIG_PM + /* + * Power down all ports by default, except the + * console if we have one. We need to drop the + * port semaphore here. + */ + if (state->pm && (!drv->cons || port->line != drv->cons->index)) { + up(&port_sem); + pm_send(state->pm, PM_SUSPEND, (void *)3); + down(&port_sem); + } +#endif + } +} + +/* + * Hangup the port. This must be done outside the port_sem + * since uart_hangup() grabs this same semaphore. Grr. + */ +static void +__uart_hangup_port(struct uart_driver *drv, struct uart_state *state) +{ + struct uart_info *info = state->info; + + if (info && info->tty) + tty_vhangup(info->tty); +} + +/* + * This reverses the affects of __uart_register_port. + */ +static void +__uart_unregister_port(struct uart_driver *drv, struct uart_state *state) +{ + struct uart_port *port = state->port; + struct uart_info *info = state->info; + + state->info = NULL; + + /* + * Remove the devices from devfs + */ + tty_unregister_devfs(drv->tty_driver, drv->minor + port->line); + + /* + * Free the port IO and memory resources, if any. + */ + if (port->type != PORT_UNKNOWN) + port->ops->release_port(port); + + /* + * Indicate that there isn't a port here anymore. + */ + port->type = PORT_UNKNOWN; + + /* + * Kill the tasklet, and free resources. + */ + if (info) { + tasklet_kill(&info->tlet); + kfree(info); + } +} + +/** + * uart_register_driver - register a driver with the uart core layer + * @drv: low level driver structure + * + * Register a uart driver with the core driver. We in turn register + * with the tty layer, and initialise the core driver per-port state. + * + * We have a proc file in /proc/tty/driver which is named after the + * normal driver. + * + * drv->port should be NULL, and the per-port structures should be + * registered using uart_add_one_port after this call has succeeded. + */ +int uart_register_driver(struct uart_driver *drv) +{ + struct tty_driver *normal = NULL; + struct termios **termios = NULL; + int i, retval; + + BUG_ON(drv->state); + + /* + * Maybe we should be using a slab cache for this, especially if + * we have a large number of ports to handle. Note that we also + * allocate space for an integer for reference counting. + */ + drv->state = kmalloc(sizeof(struct uart_state) * drv->nr + + sizeof(int), GFP_KERNEL); + retval = -ENOMEM; + if (!drv->state) + goto out; + + memset(drv->state, 0, sizeof(struct uart_state) * drv->nr + + sizeof(int)); + + termios = kmalloc(sizeof(struct termios *) * drv->nr * 2 + + sizeof(struct tty_struct *) * drv->nr, GFP_KERNEL); + if (!termios) + goto out; + + memset(termios, 0, sizeof(struct termios *) * drv->nr * 2 + + sizeof(struct tty_struct *) * drv->nr); + + normal = kmalloc(sizeof(struct tty_driver), GFP_KERNEL); + if (!normal) + goto out; + + memset(normal, 0, sizeof(struct tty_driver)); + + drv->tty_driver = normal; + + normal->magic = TTY_DRIVER_MAGIC; + normal->driver_name = drv->driver_name; + normal->name = drv->dev_name; + normal->major = drv->major; + normal->minor_start = drv->minor; + normal->num = drv->nr; + normal->type = TTY_DRIVER_TYPE_SERIAL; + normal->subtype = SERIAL_TYPE_NORMAL; + normal->init_termios = tty_std_termios; + normal->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + normal->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; + normal->refcount = (int *)(drv->state + drv->nr); + normal->termios = termios; + normal->termios_locked = termios + drv->nr; + normal->table = (struct tty_struct **)(termios + drv->nr * 2); + normal->driver_state = drv; + + normal->open = uart_open; + normal->close = uart_close; + normal->write = uart_write; + normal->put_char = uart_put_char; + normal->flush_chars = uart_flush_chars; + normal->write_room = uart_write_room; + normal->chars_in_buffer = uart_chars_in_buffer; + normal->flush_buffer = uart_flush_buffer; + normal->ioctl = uart_ioctl; + normal->throttle = uart_throttle; + normal->unthrottle = uart_unthrottle; + normal->send_xchar = uart_send_xchar; + normal->set_termios = uart_set_termios; + normal->stop = uart_stop; + normal->start = uart_start; + normal->hangup = uart_hangup; + normal->break_ctl = uart_break_ctl; + normal->wait_until_sent = uart_wait_until_sent; +#ifdef CONFIG_PROC_FS + normal->read_proc = uart_read_proc; +#endif + + /* + * Initialise the UART state(s). + */ + for (i = 0; i < drv->nr; i++) { + struct uart_state *state = drv->state + i; + + state->close_delay = 5 * HZ / 10; + state->closing_wait = 30 * HZ; +#ifdef CONFIG_PM + state->pm = pm_register(PM_SYS_DEV, PM_SYS_COM, uart_pm); + if (state->pm) + state->pm->data = state; +#endif + } + + retval = tty_register_driver(normal); + out: + if (retval < 0) { +#ifdef CONFIG_PM + for (i = 0; i < drv->nr; i++) + pm_unregister(drv->state[i].pm); +#endif + kfree(normal); + kfree(drv->state); + kfree(termios); + } + return retval; +} + +/** + * uart_unregister_driver - remove a driver from the uart core layer + * @drv: low level driver structure + * + * Remove all references to a driver from the core driver. The low + * level driver must have removed all its ports via the + * uart_remove_one_port() if it registered them with uart_add_one_port(). + * (ie, drv->port == NULL) + */ +void uart_unregister_driver(struct uart_driver *drv) +{ + int i; + + for (i = 0; i < drv->nr; i++) + pm_unregister(drv->state[i].pm); + + tty_unregister_driver(drv->tty_driver); + + kfree(drv->state); + kfree(drv->tty_driver->termios); + kfree(drv->tty_driver); +} + +/** + * uart_add_one_port - attach a driver-defined port structure + * @drv: pointer to the uart low level driver structure for this port + * @port: uart port structure to use for this port. + * + * This allows the driver to register its own uart_port structure + * with the core driver. The main purpose is to allow the low + * level uart drivers to expand uart_port, rather than having yet + * more levels of structures. + */ +int uart_add_one_port(struct uart_driver *drv, struct uart_port *port) +{ + struct uart_state *state; + + BUG_ON(in_interrupt()); + + if (port->line >= drv->nr) + return -EINVAL; + + state = drv->state + port->line; + + down(&port_sem); + __uart_register_port(drv, state, port); + up(&port_sem); + + return 0; +} + +/** + * uart_remove_one_port - detach a driver defined port structure + * @drv: pointer to the uart low level driver structure for this port + * @port: uart port structure for this port + * + * This unhooks (and hangs up) the specified port structure from the + * core driver. No further calls will be made to the low-level code + * for this port. + */ +int uart_remove_one_port(struct uart_driver *drv, struct uart_port *port) +{ + struct uart_state *state = drv->state + port->line; + + BUG_ON(in_interrupt()); + + if (state->port != port) + printk(KERN_ALERT "Removing wrong port: %p != %p\n", + state->port, port); + + __uart_hangup_port(drv, state); + + down(&port_sem); + __uart_unregister_port(drv, state); + state->port = NULL; + up(&port_sem); + + return 0; +} + +/* + * Are the two ports equivalent? + */ +static int uart_match_port(struct uart_port *port1, struct uart_port *port2) +{ + if (port1->iotype != port2->iotype) + return 0; + + switch (port1->iotype) { + case UPIO_PORT: + return (port1->iobase == port2->iobase); + case UPIO_HUB6: + return (port1->iobase == port2->iobase) && + (port1->hub6 == port2->hub6); + case UPIO_MEM: + return (port1->membase == port2->membase); + } + return 0; +} + +/* + * Try to find an unused uart_state slot for a port. + */ +static struct uart_state * +uart_find_match_or_unused(struct uart_driver *drv, struct uart_port *port) +{ + int i; + + /* + * First, find a port entry which matches. Note: if we do + * find a matching entry, and it has a non-zero use count, + * then we can't register the port. + */ + for (i = 0; i < drv->nr; i++) + if (uart_match_port(drv->state[i].port, port)) + return &drv->state[i]; + + /* + * We didn't find a matching entry, so look for the first + * free entry. We look for one which hasn't been previously + * used (indicated by zero iobase). + */ + for (i = 0; i < drv->nr; i++) + if (drv->state[i].port->type == PORT_UNKNOWN && + drv->state[i].port->iobase == 0 && + drv->state[i].count == 0) + return &drv->state[i]; + + /* + * That also failed. Last resort is to find any currently + * entry which doesn't have a real port associated with it. + */ + for (i = 0; i < drv->nr; i++) + if (drv->state[i].port->type == PORT_UNKNOWN && + drv->state[i].count == 0) + return &drv->state[i]; + + return NULL; +} + +/** + * uart_register_port: register uart settings with a port + * @drv: pointer to the uart low level driver structure for this port + * @port: uart port structure describing the port + * + * Register UART settings with the specified low level driver. Detect + * the type of the port if UPF_BOOT_AUTOCONF is set, and detect the + * IRQ if UPF_AUTO_IRQ is set. + * + * We try to pick the same port for the same IO base address, so that + * when a modem is plugged in, unplugged and plugged back in, it gets + * allocated the same port. + * + * Returns negative error, or positive line number. + */ +int uart_register_port(struct uart_driver *drv, struct uart_port *port) +{ + struct uart_state *state; + int ret; + + down(&port_sem); + + state = uart_find_match_or_unused(drv, port); + + if (state) { + /* + * Ok, we've found a line that we can use. + * + * If we find a port that matches this one, and it appears + * to be in-use (even if it doesn't have a type) we shouldn't + * alter it underneath itself - the port may be open and + * trying to do useful work. + */ + if (state->count != 0 || + (state->info && state->info->blocked_open != 0)) { + ret = -EBUSY; + goto out; + } + + state->port->iobase = port->iobase; + state->port->membase = port->membase; + state->port->irq = port->irq; + state->port->uartclk = port->uartclk; + state->port->fifosize = port->fifosize; + state->port->regshift = port->regshift; + state->port->iotype = port->iotype; + state->port->flags = port->flags; + state->port->line = drv->state - state; + + __uart_register_port(drv, state, state->port); + + ret = state->port->line; + } else + ret = -ENOSPC; + out: + up(&port_sem); + return ret; +} + +/** + * uart_unregister_port - de-allocate a port + * @drv: pointer to the uart low level driver structure for this port + * @line: line index previously returned from uart_register_port() + * + * Hang up the specified line associated with the low level driver, + * and mark the port as unused. + */ +void uart_unregister_port(struct uart_driver *drv, int line) +{ + struct uart_state *state; + + if (line < 0 || line >= drv->nr) { + printk(KERN_ERR "Attempt to unregister %s%d\n", + drv->dev_name, line); + return; + } + + state = drv->state + line; + + __uart_hangup_port(drv, state); + + down(&port_sem); + __uart_unregister_port(drv, state); + up(&port_sem); +} + +EXPORT_SYMBOL(uart_event); +EXPORT_SYMBOL(uart_register_driver); +EXPORT_SYMBOL(uart_unregister_driver); +EXPORT_SYMBOL(uart_register_port); +EXPORT_SYMBOL(uart_unregister_port); + +MODULE_DESCRIPTION("Serial driver core"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_sa1100.c b/drivers/serial/serial_sa1100.c new file mode 100644 index 000000000000..0f578fcdd757 --- /dev/null +++ b/drivers/serial/serial_sa1100.c @@ -0,0 +1,899 @@ +/* + * linux/drivers/char/serial_sa1100.c + * + * Driver for SA11x0 serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: serial_sa1100.c,v 1.41 2002/07/21 08:57:55 rmk Exp $ + * + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/circ_buf.h> +#include <linux/serial.h> +#include <linux/console.h> +#include <linux/sysrq.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/bitops.h> +#include <asm/hardware.h> +#include <asm/mach/serial_sa1100.h> + +#if defined(CONFIG_SERIAL_SA1100_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/serial_core.h> + +/* We've been assigned a range on the "Low-density serial ports" major */ +#define SERIAL_SA1100_MAJOR 204 +#define MINOR_START 5 + +#define NR_PORTS 3 + +#define SA1100_ISR_PASS_LIMIT 256 + +/* + * Convert from ignore_status_mask or read_status_mask to UTSR[01] + */ +#define SM_TO_UTSR0(x) ((x) & 0xff) +#define SM_TO_UTSR1(x) ((x) >> 8) +#define UTSR0_TO_SM(x) ((x)) +#define UTSR1_TO_SM(x) ((x) << 8) + +#define UART_GET_UTCR0(sport) __raw_readl((sport)->port.membase + UTCR0) +#define UART_GET_UTCR1(sport) __raw_readl((sport)->port.membase + UTCR1) +#define UART_GET_UTCR2(sport) __raw_readl((sport)->port.membase + UTCR2) +#define UART_GET_UTCR3(sport) __raw_readl((sport)->port.membase + UTCR3) +#define UART_GET_UTSR0(sport) __raw_readl((sport)->port.membase + UTSR0) +#define UART_GET_UTSR1(sport) __raw_readl((sport)->port.membase + UTSR1) +#define UART_GET_CHAR(sport) __raw_readl((sport)->port.membase + UTDR) + +#define UART_PUT_UTCR0(sport,v) __raw_writel((v),(sport)->port.membase + UTCR0) +#define UART_PUT_UTCR1(sport,v) __raw_writel((v),(sport)->port.membase + UTCR1) +#define UART_PUT_UTCR2(sport,v) __raw_writel((v),(sport)->port.membase + UTCR2) +#define UART_PUT_UTCR3(sport,v) __raw_writel((v),(sport)->port.membase + UTCR3) +#define UART_PUT_UTSR0(sport,v) __raw_writel((v),(sport)->port.membase + UTSR0) +#define UART_PUT_UTSR1(sport,v) __raw_writel((v),(sport)->port.membase + UTSR1) +#define UART_PUT_CHAR(sport,v) __raw_writel((v),(sport)->port.membase + UTDR) + +/* + * This is the size of our serial port register set. + */ +#define UART_PORT_SIZE 0x24 + +/* + * This determines how often we check the modem status signals + * for any change. They generally aren't connected to an IRQ + * so we have to poll them. We also check immediately before + * filling the TX fifo incase CTS has been dropped. + */ +#define MCTRL_TIMEOUT (250*HZ/1000) + +struct sa1100_port { + struct uart_port port; + struct timer_list timer; + unsigned int old_status; +}; + +/* + * Handle any change of modem status signal since we were last called. + */ +static void sa1100_mctrl_check(struct sa1100_port *sport) +{ + unsigned int status, changed; + + status = sport->port.ops->get_mctrl(&sport->port); + changed = status ^ sport->old_status; + + if (changed == 0) + return; + + sport->old_status = status; + + if (changed & TIOCM_RI) + sport->port.icount.rng++; + if (changed & TIOCM_DSR) + sport->port.icount.dsr++; + if (changed & TIOCM_CAR) + uart_handle_dcd_change(&sport->port, status & TIOCM_CAR); + if (changed & TIOCM_CTS) + uart_handle_cts_change(&sport->port, status & TIOCM_CTS); + + wake_up_interruptible(&sport->port.info->delta_msr_wait); +} + +/* + * This is our per-port timeout handler, for checking the + * modem status signals. + */ +static void sa1100_timeout(unsigned long data) +{ + struct sa1100_port *sport = (struct sa1100_port *)data; + unsigned long flags; + + if (sport->port.info) { + spin_lock_irqsave(&sport->port.lock, flags); + sa1100_mctrl_check(sport); + spin_unlock_irqrestore(&sport->port.lock, flags); + + mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); + } +} + +static void __sa1100_stop_tx(struct sa1100_port *sport) +{ + u32 utcr3; + + utcr3 = UART_GET_UTCR3(sport); + UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_TIE); + sport->port.read_status_mask &= ~UTSR0_TO_SM(UTSR0_TFS); +} + +/* + * interrupts disabled on entry + */ +static void sa1100_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + unsigned long flags; + + spin_lock_irqsave(&sport->port.lock, flags); + __sa1100_stop_tx(sport); + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +/* + * interrupts may not be disabled on entry + */ +static void sa1100_start_tx(struct uart_port *port, unsigned int tty_start) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + unsigned long flags; + u32 utcr3; + + spin_lock_irqsave(&sport->port.lock, flags); + utcr3 = UART_GET_UTCR3(sport); + sport->port.read_status_mask |= UTSR0_TO_SM(UTSR0_TFS); + UART_PUT_UTCR3(sport, utcr3 | UTCR3_TIE); + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +/* + * Interrupts enabled + */ +static void sa1100_stop_rx(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + unsigned long flags; + u32 utcr3; + + spin_lock_irqsave(&sport->port.lock, flags); + utcr3 = UART_GET_UTCR3(sport); + UART_PUT_UTCR3(sport, utcr3 & ~UTCR3_RIE); + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +/* + * Set the modem control timer to fire immediately. + */ +static void sa1100_enable_ms(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + mod_timer(&sport->timer, jiffies); +} + +static void +sa1100_rx_chars(struct sa1100_port *sport, struct pt_regs *regs) +{ + struct tty_struct *tty = sport->port.info->tty; + unsigned int status, ch, flg, ignored = 0; + + status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | + UTSR0_TO_SM(UART_GET_UTSR0(sport)); + while (status & UTSR1_TO_SM(UTSR1_RNE)) { + ch = UART_GET_CHAR(sport); + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + sport->port.icount.rx++; + + flg = TTY_NORMAL; + + /* + * note that the error handling code is + * out of the main execution path + */ + if (status & UTSR1_TO_SM(UTSR1_PRE | UTSR1_FRE | UTSR1_ROR)) + goto handle_error; + + if (uart_handle_sysrq_char(&sport->port, ch, regs)) + goto ignore_char; + + error_return: + *tty->flip.flag_buf_ptr++ = flg; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + ignore_char: + status = UTSR1_TO_SM(UART_GET_UTSR1(sport)) | + UTSR0_TO_SM(UART_GET_UTSR0(sport)); + } + out: + tty_flip_buffer_push(tty); + return; + + handle_error: + if (status & UTSR1_TO_SM(UTSR1_PRE)) + sport->port.icount.parity++; + else if (status & UTSR1_TO_SM(UTSR1_FRE)) + sport->port.icount.frame++; + if (status & UTSR1_TO_SM(UTSR1_ROR)) + sport->port.icount.overrun++; + + if (status & sport->port.ignore_status_mask) { + if (++ignored > 100) + goto out; + goto ignore_char; + } + + status &= sport->port.read_status_mask; + + if (status & UTSR1_TO_SM(UTSR1_PRE)) + flg = TTY_PARITY; + else if (status & UTSR1_TO_SM(UTSR1_FRE)) + flg = TTY_FRAME; + + if (status & UTSR1_TO_SM(UTSR1_ROR)) { + /* + * overrun does *not* affect the character + * we read from the FIFO + */ + *tty->flip.flag_buf_ptr++ = flg; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + ch = 0; + flg = TTY_OVERRUN; + } +#ifdef SUPPORT_SYSRQ + sport->port.sysrq = 0; +#endif + goto error_return; +} + +static void sa1100_tx_chars(struct sa1100_port *sport) +{ + struct circ_buf *xmit = &sport->port.info->xmit; + + if (sport->port.x_char) { + UART_PUT_CHAR(sport, sport->port.x_char); + sport->port.icount.tx++; + sport->port.x_char = 0; + return; + } + + /* + * Check the modem control lines before + * transmitting anything. + */ + sa1100_mctrl_check(sport); + + if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { + __sa1100_stop_tx(sport); + return; + } + + /* + * Tried using FIFO (not checking TNF) for fifo fill: + * still had the '4 bytes repeated' problem. + */ + while (UART_GET_UTSR1(sport) & UTSR1_TNF) { + UART_PUT_CHAR(sport, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + sport->port.icount.tx++; + if (uart_circ_empty(xmit)) + break; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_event(&sport->port, EVT_WRITE_WAKEUP); + + if (uart_circ_empty(xmit)) + __sa1100_stop_tx(sport); +} + +static void sa1100_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct sa1100_port *sport = dev_id; + unsigned int status, pass_counter = 0; + + spin_lock(&sport->port.lock); + status = UART_GET_UTSR0(sport); + status &= SM_TO_UTSR0(sport->port.read_status_mask) | ~UTSR0_TFS; + do { + if (status & (UTSR0_RFS | UTSR0_RID)) { + /* Clear the receiver idle bit, if set */ + if (status & UTSR0_RID) + UART_PUT_UTSR0(sport, UTSR0_RID); + sa1100_rx_chars(sport, regs); + } + + /* Clear the relevent break bits */ + if (status & (UTSR0_RBB | UTSR0_REB)) + UART_PUT_UTSR0(sport, status & (UTSR0_RBB | UTSR0_REB)); + + if (status & UTSR0_RBB) + sport->port.icount.brk++; + + if (status & UTSR0_REB) + uart_handle_break(&sport->port); + + if (status & UTSR0_TFS) + sa1100_tx_chars(sport); + if (pass_counter++ > SA1100_ISR_PASS_LIMIT) + break; + status = UART_GET_UTSR0(sport); + status &= SM_TO_UTSR0(sport->port.read_status_mask) | + ~UTSR0_TFS; + } while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID)); + spin_unlock(&sport->port.lock); +} + +/* + * Return TIOCSER_TEMT when transmitter is not busy. + */ +static unsigned int sa1100_tx_empty(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + return UART_GET_UTSR1(sport) & UTSR1_TBY ? 0 : TIOCSER_TEMT; +} + +static unsigned int sa1100_get_mctrl(struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; +} + +static void sa1100_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +/* + * Interrupts always disabled. + */ +static void sa1100_break_ctl(struct uart_port *port, int break_state) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + unsigned long flags; + unsigned int utcr3; + + spin_lock_irqsave(&sport->port.lock, flags); + utcr3 = UART_GET_UTCR3(sport); + if (break_state == -1) + utcr3 |= UTCR3_BRK; + else + utcr3 &= ~UTCR3_BRK; + UART_PUT_UTCR3(sport, utcr3); + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static int sa1100_startup(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + int retval; + + /* + * Allocate the IRQ + */ + retval = request_irq(sport->port.irq, sa1100_int, 0, + "serial_sa1100", sport); + if (retval) + return retval; + + /* + * Finally, clear and enable interrupts + */ + UART_PUT_UTSR0(sport, -1); + UART_PUT_UTCR3(sport, UTCR3_RXE | UTCR3_TXE | UTCR3_RIE); + + /* + * Enable modem status interrupts + */ + sa1100_enable_ms(&sport->port); + + return 0; +} + +static void sa1100_shutdown(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + /* + * Stop our timer. + */ + del_timer_sync(&sport->timer); + + /* + * Free the interrupt + */ + free_irq(sport->port.irq, sport); + + /* + * Disable all interrupts, port and break condition. + */ + UART_PUT_UTCR3(sport, 0); +} + +static void +sa1100_change_speed(struct uart_port *port, unsigned int cflag, + unsigned int iflag, unsigned int quot) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + unsigned long flags; + unsigned int utcr0, old_utcr3; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS7: + utcr0 = 0; + break; + default: + utcr0 = UTCR0_DSS; + break; + } + if (cflag & CSTOPB) + utcr0 |= UTCR0_SBS; + if (cflag & PARENB) { + utcr0 |= UTCR0_PE; + if (!(cflag & PARODD)) + utcr0 |= UTCR0_OES; + } + + sport->port.read_status_mask &= UTSR0_TO_SM(UTSR0_TFS); + sport->port.read_status_mask |= UTSR1_TO_SM(UTSR1_ROR); + if (iflag & INPCK) + sport->port.read_status_mask |= + UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE); + if (iflag & (BRKINT | PARMRK)) + sport->port.read_status_mask |= + UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB); + + /* + * Characters to ignore + */ + sport->port.ignore_status_mask = 0; + if (iflag & IGNPAR) + sport->port.ignore_status_mask |= + UTSR1_TO_SM(UTSR1_FRE | UTSR1_PRE); + if (iflag & IGNBRK) { + sport->port.ignore_status_mask |= + UTSR0_TO_SM(UTSR0_RBB | UTSR0_REB); + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (iflag & IGNPAR) + sport->port.ignore_status_mask |= + UTSR1_TO_SM(UTSR1_ROR); + } + + del_timer_sync(&sport->timer); + + /* first, disable interrupts and drain transmitter */ + spin_lock_irqsave(&sport->port.lock, flags); + old_utcr3 = UART_GET_UTCR3(sport); + UART_PUT_UTCR3(sport, old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)); + + while (UART_GET_UTSR1(sport) & UTSR1_TBY); + + /* then, disable everything */ + UART_PUT_UTCR3(sport, 0); + + /* set the parity, stop bits and data size */ + UART_PUT_UTCR0(sport, utcr0); + + /* set the baud rate */ + quot -= 1; + UART_PUT_UTCR1(sport, ((quot & 0xf00) >> 8)); + UART_PUT_UTCR2(sport, (quot & 0xff)); + + UART_PUT_UTSR0(sport, -1); + + UART_PUT_UTCR3(sport, old_utcr3); + spin_unlock_irqrestore(&sport->port.lock, flags); + + if (UART_ENABLE_MS(&sport->port, cflag)) + sa1100_enable_ms(&sport->port); +} + +static const char *sa1100_type(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + return sport->port.type == PORT_SA1100 ? "SA1100" : NULL; +} + +/* + * Release the memory region(s) being used by 'port'. + */ +static void sa1100_release_port(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + release_mem_region(sport->port.mapbase, UART_PORT_SIZE); +} + +/* + * Request the memory region(s) being used by 'port'. + */ +static int sa1100_request_port(struct uart_port *port) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + return request_mem_region(sport->port.mapbase, UART_PORT_SIZE, + "serial_sa1100") != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void sa1100_config_port(struct uart_port *port, int flags) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + + if (flags & UART_CONFIG_TYPE && + sa1100_request_port(&sport->port) == 0) + sport->port.type = PORT_SA1100; +} + +/* + * Verify the new serial_struct (for TIOCSSERIAL). + * The only change we allow are to the flags and type, and + * even then only between PORT_SA1100 and PORT_UNKNOWN + */ +static int +sa1100_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + struct sa1100_port *sport = (struct sa1100_port *)port; + int ret = 0; + + if (ser->type != PORT_UNKNOWN && ser->type != PORT_SA1100) + ret = -EINVAL; + if (sport->port.irq != ser->irq) + ret = -EINVAL; + if (ser->io_type != SERIAL_IO_MEM) + ret = -EINVAL; + if (sport->port.uartclk / 16 != ser->baud_base) + ret = -EINVAL; + if ((void *)sport->port.mapbase != ser->iomem_base) + ret = -EINVAL; + if (sport->port.iobase != ser->port) + ret = -EINVAL; + if (ser->hub6 != 0) + ret = -EINVAL; + return ret; +} + +static struct uart_ops sa1100_pops = { + tx_empty: sa1100_tx_empty, + set_mctrl: sa1100_set_mctrl, + get_mctrl: sa1100_get_mctrl, + stop_tx: sa1100_stop_tx, + start_tx: sa1100_start_tx, + stop_rx: sa1100_stop_rx, + enable_ms: sa1100_enable_ms, + break_ctl: sa1100_break_ctl, + startup: sa1100_startup, + shutdown: sa1100_shutdown, + change_speed: sa1100_change_speed, + type: sa1100_type, + release_port: sa1100_release_port, + request_port: sa1100_request_port, + config_port: sa1100_config_port, + verify_port: sa1100_verify_port, +}; + +static struct sa1100_port sa1100_ports[NR_PORTS]; + +/* + * Setup the SA1100 serial ports. Note that we don't include the IrDA + * port here since we have our own SIR/FIR driver (see drivers/net/irda) + * + * Note also that we support "console=ttySAx" where "x" is either 0 or 1. + * Which serial port this ends up being depends on the machine you're + * running this kernel on. I'm not convinced that this is a good idea, + * but that's the way it traditionally works. + * + * Note that NanoEngine UART3 becomes UART2, and UART2 is no longer + * used here. + */ +static void __init sa1100_init_ports(void) +{ + static int first = 1; + int i; + + if (!first) + return; + first = 0; + + for (i = 0; i < NR_PORTS; i++) { + sa1100_ports[i].port.uartclk = 3686400; + sa1100_ports[i].port.ops = &sa1100_pops; + sa1100_ports[i].port.fifosize = 8; + sa1100_ports[i].port.line = i; + sa1100_ports[i].port.iotype = SERIAL_IO_MEM; + init_timer(&sa1100_ports[i].timer); + sa1100_ports[i].timer.function = sa1100_timeout; + sa1100_ports[i].timer.data = (unsigned long)&sa1100_ports[i]; + } + + /* + * make transmit lines outputs, so that when the port + * is closed, the output is in the MARK state. + */ + PPDR |= PPC_TXD1 | PPC_TXD3; + PPSR |= PPC_TXD1 | PPC_TXD3; +} + +void __init sa1100_register_uart_fns(struct sa1100_port_fns *fns) +{ + if (fns->get_mctrl) + sa1100_pops.get_mctrl = fns->get_mctrl; + if (fns->set_mctrl) + sa1100_pops.set_mctrl = fns->set_mctrl; + + sa1100_pops.pm = fns->pm; + sa1100_pops.set_wake = fns->set_wake; +} + +void __init sa1100_register_uart(int idx, int port) +{ + if (idx >= NR_PORTS) { + printk(KERN_ERR __FUNCTION__ ": bad index number %d\n", idx); + return; + } + + switch (port) { + case 1: + sa1100_ports[idx].port.membase = (void *)&Ser1UTCR0; + sa1100_ports[idx].port.mapbase = _Ser1UTCR0; + sa1100_ports[idx].port.irq = IRQ_Ser1UART; + sa1100_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF; + break; + + case 2: + sa1100_ports[idx].port.membase = (void *)&Ser2UTCR0; + sa1100_ports[idx].port.mapbase = _Ser2UTCR0; + sa1100_ports[idx].port.irq = IRQ_Ser2ICP; + sa1100_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF; + break; + + case 3: + sa1100_ports[idx].port.membase = (void *)&Ser3UTCR0; + sa1100_ports[idx].port.mapbase = _Ser3UTCR0; + sa1100_ports[idx].port.irq = IRQ_Ser3UART; + sa1100_ports[idx].port.flags = ASYNC_BOOT_AUTOCONF; + break; + + default: + printk(KERN_ERR __FUNCTION__ ": bad port number %d\n", port); + } +} + + +#ifdef CONFIG_SERIAL_SA1100_CONSOLE + +/* + * Interrupts are disabled on entering + */ +static void +sa1100_console_write(struct console *co, const char *s, unsigned int count) +{ + struct sa1100_port *sport = &sa1100_ports[co->index]; + unsigned int old_utcr3, status, i; + + /* + * First, save UTCR3 and then disable interrupts + */ + old_utcr3 = UART_GET_UTCR3(sport); + UART_PUT_UTCR3(sport, (old_utcr3 & ~(UTCR3_RIE | UTCR3_TIE)) | + UTCR3_TXE); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + do { + status = UART_GET_UTSR1(sport); + } while (!(status & UTSR1_TNF)); + UART_PUT_CHAR(sport, s[i]); + if (s[i] == '\n') { + do { + status = UART_GET_UTSR1(sport); + } while (!(status & UTSR1_TNF)); + UART_PUT_CHAR(sport, '\r'); + } + } + + /* + * Finally, wait for transmitter to become empty + * and restore UTCR3 + */ + do { + status = UART_GET_UTSR1(sport); + } while (status & UTSR1_TBY); + UART_PUT_UTCR3(sport, old_utcr3); +} + +static kdev_t sa1100_console_device(struct console *co) +{ + return mk_kdev(SERIAL_SA1100_MAJOR, MINOR_START + co->index); +} + +/* + * If the port was already initialised (eg, by a boot loader), + * try to determine the current setup. + */ +static void __init +sa1100_console_get_options(struct sa1100_port *sport, int *baud, + int *parity, int *bits) +{ + unsigned int utcr3; + + utcr3 = UART_GET_UTCR3(sport) & (UTCR3_RXE | UTCR3_TXE); + if (utcr3 == (UTCR3_RXE | UTCR3_TXE)) { + /* ok, the port was enabled */ + unsigned int utcr0, quot; + + utcr0 = UART_GET_UTCR0(sport); + + *parity = 'n'; + if (utcr0 & UTCR0_PE) { + if (utcr0 & UTCR0_OES) + *parity = 'e'; + else + *parity = 'o'; + } + + if (utcr0 & UTCR0_DSS) + *bits = 8; + else + *bits = 7; + + quot = UART_GET_UTCR2(sport) | UART_GET_UTCR1(sport) << 8; + quot &= 0xfff; + *baud = sport->port.uartclk / (16 * (quot + 1)); + } +} + +static int __init +sa1100_console_setup(struct console *co, char *options) +{ + struct sa1100_port *sport; + int baud = 9600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + if (co->index == -1 || co->index >= NR_PORTS) + co->index = 0; + sport = &sa1100_ports[co->index]; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + sa1100_console_get_options(sport, &baud, &parity, &bits); + + return uart_set_options(&sport->port, co, baud, parity, bits, flow); +} + +static struct console sa1100_console = { + name: "ttySA", + write: sa1100_console_write, + device: sa1100_console_device, + setup: sa1100_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +void __init sa1100_rs_console_init(void) +{ + sa1100_init_ports(); + register_console(&sa1100_console); +} + +#define SA1100_CONSOLE &sa1100_console +#else +#define SA1100_CONSOLE NULL +#endif + +static struct uart_driver sa1100_reg = { + owner: THIS_MODULE, + driver_name: "ttySA", +#ifdef CONFIG_DEVFS_FS + dev_name: "ttySA%d", +#else + dev_name: "ttySA", +#endif + major: SERIAL_SA1100_MAJOR, + minor: MINOR_START, + nr: NR_PORTS, + cons: SA1100_CONSOLE, +}; + +static int __init sa1100_serial_init(void) +{ + int ret; + + printk(KERN_INFO "Serial: SA11x0 driver $Revision: 1.41 $\n"); + + sa1100_init_ports(); + ret = uart_register_driver(&sa1100_reg); + if (ret == 0) { + int i; + + for (i = 0; i < NR_PORTS; i++) + uart_add_one_port(&sa1100_reg, &sa1100_ports[i].port); + } + return ret; +} + +static void __exit sa1100_serial_exit(void) +{ + int i; + + for (i = 0; i < NR_PORTS; i++) + uart_remove_one_port(&sa1100_reg, &sa1100_ports[i].port); + + uart_unregister_driver(&sa1100_reg); +} + +module_init(sa1100_serial_init); +module_exit(sa1100_serial_exit); + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Deep Blue Solutions Ltd"); +MODULE_DESCRIPTION("SA1100 generic serial port driver $Revision: 1.41 $"); +MODULE_LICENSE("GPL"); diff --git a/drivers/serial/serial_uart00.c b/drivers/serial/serial_uart00.c new file mode 100644 index 000000000000..e90c36f6ac97 --- /dev/null +++ b/drivers/serial/serial_uart00.c @@ -0,0 +1,778 @@ +/* + * linux/drivers/char/serial_uart00.c + * + * Driver for UART00 serial ports + * + * Based on drivers/char/serial_amba.c, by ARM Limited & + * Deep Blue Solutions Ltd. + * Copyright 2001 Altera Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: serial_uart00.c,v 1.32 2002/07/20 17:10:04 rmk Exp $ + * + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> +#include <linux/major.h> +#include <linux/string.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/ioport.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/circ_buf.h> +#include <linux/serial.h> +#include <linux/console.h> +#include <linux/sysrq.h> +#include <linux/pld/pld_hotswap.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/uaccess.h> +#include <asm/bitops.h> +#include <asm/sizes.h> + +#if defined(CONFIG_SERIAL_UART00_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/serial_core.h> +#include <asm/arch/excalibur.h> +#define UART00_TYPE (volatile unsigned int*) +#include <asm/arch/uart00.h> +#include <asm/arch/int_ctrl00.h> + +#define UART_NR 2 + +#define SERIAL_UART00_NAME "ttyUA" +#define SERIAL_UART00_MAJOR 204 +#define SERIAL_UART00_MINOR 16 /* Temporary - will change in future */ +#define SERIAL_UART00_NR UART_NR +#define UART_PORT_SIZE 0x50 + +#define UART00_ISR_PASS_LIMIT 256 + +/* + * Access macros for the UART00 UARTs + */ +#define UART_GET_INT_STATUS(p) inl(UART_ISR((p)->membase)) +#define UART_PUT_IES(p, c) outl(c,UART_IES((p)->membase)) +#define UART_GET_IES(p) inl(UART_IES((p)->membase)) +#define UART_PUT_IEC(p, c) outl(c,UART_IEC((p)->membase)) +#define UART_GET_IEC(p) inl(UART_IEC((p)->membase)) +#define UART_PUT_CHAR(p, c) outl(c,UART_TD((p)->membase)) +#define UART_GET_CHAR(p) inl(UART_RD((p)->membase)) +#define UART_GET_RSR(p) inl(UART_RSR((p)->membase)) +#define UART_GET_RDS(p) inl(UART_RDS((p)->membase)) +#define UART_GET_MSR(p) inl(UART_MSR((p)->membase)) +#define UART_GET_MCR(p) inl(UART_MCR((p)->membase)) +#define UART_PUT_MCR(p, c) outl(c,UART_MCR((p)->membase)) +#define UART_GET_MC(p) inl(UART_MC((p)->membase)) +#define UART_PUT_MC(p, c) outl(c,UART_MC((p)->membase)) +#define UART_GET_TSR(p) inl(UART_TSR((p)->membase)) +#define UART_GET_DIV_HI(p) inl(UART_DIV_HI((p)->membase)) +#define UART_PUT_DIV_HI(p,c) outl(c,UART_DIV_HI((p)->membase)) +#define UART_GET_DIV_LO(p) inl(UART_DIV_LO((p)->membase)) +#define UART_PUT_DIV_LO(p,c) outl(c,UART_DIV_LO((p)->membase)) +#define UART_RX_DATA(s) ((s) & UART_RSR_RX_LEVEL_MSK) +#define UART_TX_READY(s) (((s) & UART_TSR_TX_LEVEL_MSK) < 15) +//#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & UART00_UARTFR_TMSK) == 0) + +static void uart00_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ + UART_PUT_IEC(port, UART_IEC_TIE_MSK); +} + +static void uart00_stop_rx(struct uart_port *port) +{ + UART_PUT_IEC(port, UART_IEC_RE_MSK); +} + +static void uart00_enable_ms(struct uart_port *port) +{ + UART_PUT_IES(port, UART_IES_ME_MSK); +} + +static void +uart00_rx_chars(struct uart_port *port, struct pt_regs *regs) +{ + struct tty_struct *tty = port->info->tty; + unsigned int status, ch, rds, flg, ignored = 0; + + status = UART_GET_RSR(port); + while (UART_RX_DATA(status)) { + /* + * We need to read rds before reading the + * character from the fifo + */ + rds = UART_GET_RDS(port); + ch = UART_GET_CHAR(port); + port->icount.rx++; + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + + flg = TTY_NORMAL; + + /* + * Note that the error handling code is + * out of the main execution path + */ + if (rds & (UART_RDS_BI_MSK |UART_RDS_FE_MSK| + UART_RDS_PE_MSK |UART_RDS_PE_MSK)) + goto handle_error; + if (uart_handle_sysrq_char(port, ch, regs)) + goto ignore_char; + + error_return: + *tty->flip.flag_buf_ptr++ = flg; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + ignore_char: + status = UART_GET_RSR(port); + } + out: + tty_flip_buffer_push(tty); + return; + + handle_error: + if (rds & UART_RDS_BI_MSK) { + status &= ~(UART_RDS_FE_MSK | UART_RDS_PE_MSK); + port->icount.brk++; + if (uart_handle_break(port)) + goto ignore_char; + } else if (rds & UART_RDS_PE_MSK) + port->icount.parity++; + else if (rds & UART_RDS_PE_MSK) + port->icount.frame++; + if (rds & UART_RDS_OE_MSK) + port->icount.overrun++; + + if (rds & port->ignore_status_mask) { + if (++ignored > 100) + goto out; + goto ignore_char; + } + rds &= port->read_status_mask; + + if (rds & UART_RDS_BI_MSK) + flg = TTY_BREAK; + else if (rds & UART_RDS_PE_MSK) + flg = TTY_PARITY; + else if (rds & UART_RDS_FE_MSK) + flg = TTY_FRAME; + + if (status & UART_RDS_OE_MSK) { + /* + * CHECK: does overrun affect the current character? + * ASSUMPTION: it does not. + */ + *tty->flip.flag_buf_ptr++ = flg; + *tty->flip.char_buf_ptr++ = ch; + tty->flip.count++; + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + goto ignore_char; + ch = 0; + flg = TTY_OVERRUN; + } +#ifdef SUPPORT_SYSRQ + port->sysrq = 0; +#endif + goto error_return; +} + +static void uart00_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + int count; + + if (port->x_char) { + while ((UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK) == 15); + UART_PUT_CHAR(port, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + uart00_stop_tx(port, 0); + return; + } + + count = port->fifosize >> 1; + do { + while ((UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK) == 15); + UART_PUT_CHAR(port, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + } while (--count > 0); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_event(port, EVT_WRITE_WAKEUP); + + if (uart_circ_empty(xmit)) + uart00_stop_tx(port, 0); +} + +static void uart00_start_tx(struct uart_port *port, unsigned int tty_start) +{ + UART_PUT_IES(port, UART_IES_TIE_MSK); + uart00_tx_chars(port); +} + +static void uart00_modem_status(struct uart_port *port) +{ + unsigned int status; + + status = UART_GET_MSR(port); + + if (!status & (UART_MSR_DCTS_MSK | UART_MSR_DDSR_MSK | + UART_MSR_TERI_MSK | UART_MSR_DDCD_MSK)) + return; + + if (status & UART_MSR_DDCD_MSK) + uart_handle_dcd_change(port, status & UART_MSR_DCD_MSK); + + if (status & UART_MSR_DDSR_MSK) + port->icount.dsr++; + + if (status & UART_MSR_DCTS_MSK) + uart_handle_cts_change(port, status & UART_MSR_CTS_MSK); + + wake_up_interruptible(&port->info->delta_msr_wait); +} + +static void uart00_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct uart_port *port = dev_id; + unsigned int status, pass_counter = 0; + + status = UART_GET_INT_STATUS(port); + do { + if (status & UART_ISR_RI_MSK) + uart00_rx_chars(port, regs); + if (status & UART_ISR_MI_MSK) + uart00_modem_status(port); + if (status & (UART_ISR_TI_MSK | UART_ISR_TII_MSK)) + uart00_tx_chars(port); + if (pass_counter++ > UART00_ISR_PASS_LIMIT) + break; + + status = UART_GET_INT_STATUS(port); + } while (status); +} + +static unsigned int uart00_tx_empty(struct uart_port *port) +{ + return UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK? 0 : TIOCSER_TEMT; +} + +static unsigned int uart00_get_mctrl(struct uart_port *port) +{ + unsigned int result = 0; + unsigned int status; + + status = UART_GET_MSR(port); + if (status & UART_MSR_DCD_MSK) + result |= TIOCM_CAR; + if (status & UART_MSR_DSR_MSK) + result |= TIOCM_DSR; + if (status & UART_MSR_CTS_MSK) + result |= TIOCM_CTS; + if (status & UART_MSR_RI_MSK) + result |= TIOCM_RI; + + return result; +} + +static void uart00_set_mctrl_null(struct uart_port *port, unsigned int mctrl) +{ +} + +static void uart00_break_ctl(struct uart_port *port, int break_state) +{ + unsigned long flags; + unsigned int mcr; + + spin_lock_irqsave(&port->lock, flags); + mcr = UART_GET_MCR(port); + if (break_state == -1) + mcr |= UART_MCR_BR_MSK; + else + mcr &= ~UART_MCR_BR_MSK; + UART_PUT_MCR(port, mcr); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void +uart00_change_speed(struct uart_port *port, unsigned int cflag, + unsigned int iflag, unsigned int quot) +{ + unsigned int uart_mc, old_ies; + unsigned long flags; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: + uart_mc = UART_MC_CLS_CHARLEN_5; + break; + case CS6: + uart_mc = UART_MC_CLS_CHARLEN_6; + break; + case CS7: + uart_mc = UART_MC_CLS_CHARLEN_7; + break; + default: // CS8 + uart_mc = UART_MC_CLS_CHARLEN_8; + break; + } + if (cflag & CSTOPB) + uart_mc|= UART_MC_ST_TWO; + if (cflag & PARENB) { + uart_mc |= UART_MC_PE_MSK; + if (!(cflag & PARODD)) + uart_mc |= UART_MC_EP_MSK; + } + + port->read_status_mask = UART_RDS_OE_MSK; + if (iflag & INPCK) + port->read_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK; + if (iflag & (BRKINT | PARMRK)) + port->read_status_mask |= UART_RDS_BI_MSK; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (iflag & IGNPAR) + port->ignore_status_mask |= UART_RDS_FE_MSK | UART_RDS_PE_MSK; + if (iflag & IGNBRK) { + port->ignore_status_mask |= UART_RDS_BI_MSK; + /* + * If we're ignoring parity and break indicators, + * ignore overruns to (for real raw support). + */ + if (iflag & IGNPAR) + port->ignore_status_mask |= UART_RDS_OE_MSK; + } + + /* first, disable everything */ + spin_lock_irqsave(&port->lock, flags); + old_ies = UART_GET_IES(port); + + if (UART_ENABLE_MS(port, cflag)) + old_ies |= UART_IES_ME_MSK; + + /* Set baud rate */ + UART_PUT_DIV_LO(port, (quot & 0xff)); + UART_PUT_DIV_HI(port, ((quot & 0xf00) >> 8)); + + UART_PUT_MC(port, uart_mc); + UART_PUT_IES(port, old_ies); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static int uart00_startup(struct uart_port *port) +{ + int result; + + /* + * Allocate the IRQ + */ + result = request_irq(port->irq, uart00_int, 0, "uart00", port); + if (result) { + printk(KERN_ERR "Request of irq %d failed\n", port->irq); + return result; + } + + /* + * Finally, enable interrupts. Use the TII interrupt to minimise + * the number of interrupts generated. If higher performance is + * needed, consider using the TI interrupt with a suitable FIFO + * threshold + */ + UART_PUT_IES(port, UART_IES_RE_MSK | UART_IES_TIE_MSK); + + return 0; +} + +static void uart00_shutdown(struct uart_port *port) +{ + /* + * disable all interrupts, disable the port + */ + UART_PUT_IEC(port, 0xff); + + /* disable break condition and fifos */ + UART_PUT_MCR(port, UART_GET_MCR(port) &~UART_MCR_BR_MSK); + + /* + * Free the interrupt + */ + free_irq(port->irq, port); +} + +static const char *uart00_type(struct uart_port *port) +{ + return port->type == PORT_UART00 ? "Altera UART00" : NULL; +} + +/* + * Release the memory region(s) being used by 'port' + */ +static void uart00_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, UART_PORT_SIZE); + +#ifdef CONFIG_ARCH_CAMELOT + if (port->membase != (void*)IO_ADDRESS(EXC_UART00_BASE)) { + iounmap(port->membase); + } +#endif +} + +/* + * Request the memory region(s) being used by 'port' + */ +static int uart00_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_uart00") + != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void uart00_config_port(struct uart_port *port, int flags) +{ + + /* + * Map the io memory if this is a soft uart + */ + if (!port->membase) + port->membase = ioremap_nocache(port->mapbase,SZ_4K); + + if (!port->membase) + printk(KERN_ERR "serial00: cannot map io memory\n"); + else + port->type = PORT_UART00; + +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int uart00_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_UART00) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= NR_IRQS) + ret = -EINVAL; + if (ser->baud_base < 9600) + ret = -EINVAL; + return ret; +} + +static struct uart_ops uart00_pops = { + tx_empty: uart00_tx_empty, + set_mctrl: uart00_set_mctrl_null, + get_mctrl: uart00_get_mctrl, + stop_tx: uart00_stop_tx, + start_tx: uart00_start_tx, + stop_rx: uart00_stop_rx, + enable_ms: uart00_enable_ms, + break_ctl: uart00_break_ctl, + startup: uart00_startup, + shutdown: uart00_shutdown, + change_speed: uart00_change_speed, + type: uart00_type, + release_port: uart00_release_port, + request_port: uart00_request_port, + config_port: uart00_config_port, + verify_port: uart00_verify_port, +}; + + +#ifdef CONFIG_ARCH_CAMELOT +static struct uart_port epxa10db_port = { + membase: (void*)IO_ADDRESS(EXC_UART00_BASE), + mapbase: EXC_UART00_BASE, + iotype: SERIAL_IO_MEM, + irq: IRQ_UART, + uartclk: EXC_AHB2_CLK_FREQUENCY, + fifosize: 16, + ops: &uart00_pops, + flags: ASYNC_BOOT_AUTOCONF, +}; +#endif + + +#ifdef CONFIG_SERIAL_UART00_CONSOLE +static void uart00_console_write(struct console *co, const char *s, unsigned count) +{ +#ifdef CONFIG_ARCH_CAMELOT + struct uart_port *port = &epxa10db_port; + unsigned int status, old_ies; + int i; + + /* + * First save the CR then disable the interrupts + */ + old_ies = UART_GET_IES(port); + UART_PUT_IEC(port,0xff); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + do { + status = UART_GET_TSR(port); + } while (!UART_TX_READY(status)); + UART_PUT_CHAR(port, s[i]); + if (s[i] == '\n') { + do { + status = UART_GET_TSR(port); + } while (!UART_TX_READY(status)); + UART_PUT_CHAR(port, '\r'); + } + } + + /* + * Finally, wait for transmitter to become empty + * and restore the IES + */ + do { + status = UART_GET_TSR(port); + } while (status & UART_TSR_TX_LEVEL_MSK); + UART_PUT_IES(port, old_ies); +#endif +} + +static kdev_t uart00_console_device(struct console *co) +{ + return mk_kdev(SERIAL_UART00_MAJOR, SERIAL_UART00_MINOR + co->index); +} + +static void __init +uart00_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) +{ + unsigned int uart_mc, quot; + + uart_mc = UART_GET_MC(port); + + *parity = 'n'; + if (uart_mc & UART_MC_PE_MSK) { + if (uart_mc & UART_MC_EP_MSK) + *parity = 'e'; + else + *parity = 'o'; + } + + switch (uart_mc & UART_MC_CLS_MSK) { + case UART_MC_CLS_CHARLEN_5: + *bits = 5; + break; + case UART_MC_CLS_CHARLEN_6: + *bits = 6; + break; + case UART_MC_CLS_CHARLEN_7: + *bits = 7; + break; + case UART_MC_CLS_CHARLEN_8: + *bits = 8; + break; + } + quot = UART_GET_DIV_LO(port) | (UART_GET_DIV_HI(port) << 8); + *baud = port->uartclk / (16 *quot ); +} + +static int __init uart00_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + +#ifdef CONFIG_ARCH_CAMELOT + port = &epxa10db_port; ; +#else + return -ENODEV; +#endif + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + uart00_console_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console uart00_console = { + name: SERIAL_UART00_NAME, + write: uart00_console_write, + device: uart00_console_device, + setup: uart00_console_setup, + flags: CON_PRINTBUFFER, + index: 0, +}; + +void __init uart00_console_init(void) +{ + register_console(&uart00_console); +} + +#define UART00_CONSOLE &uart00_console +#else +#define UART00_CONSOLE NULL +#endif + +static struct uart_driver uart00_reg = { + owner: NULL, + driver_name: SERIAL_UART00_NAME, + dev_name: SERIAL_UART00_NAME, + major: SERIAL_UART00_MAJOR, + minor: SERIAL_UART00_MINOR, + nr: UART_NR, + cons: UART00_CONSOLE, +}; + +struct dev_port_entry{ + unsigned int base_addr; + struct uart_port *port; +}; + +static struct dev_port_entry dev_port_map[UART_NR]; + +#ifdef CONFIG_PLD_HOTSWAP +/* + * Keep a mapping of dev_info addresses -> port lines to use when + * removing ports dev==NULL indicates unused entry + */ + +struct uart00_ps_data{ + unsigned int clk; + unsigned int fifosize; +}; + +int uart00_add_device(struct pldhs_dev_info* dev_info, void* dev_ps_data) +{ + struct uart00_ps_data* dev_ps=dev_ps_data; + struct uart_port * port; + int i,result; + + i=0; + while(dev_port_map[i].port) + i++; + + if(i==UART_NR){ + printk(KERN_WARNING "uart00: Maximum number of ports reached\n"); + return 0; + } + + port=kmalloc(sizeof(struct uart_port),GFP_KERNEL); + if(!port) + return -ENOMEM; + + printk("clk=%d fifo=%d\n",dev_ps->clk,dev_ps->fifosize); + port->membase=0; + port->mapbase=dev_info->base_addr; + port->iotype=SERIAL_IO_MEM; + port->irq=dev_info->irq; + port->uartclk=dev_ps->clk; + port->fifosize=dev_ps->fifosize; + port->ops=&uart00_pops; + port->line=i; + port->flags=ASYNC_BOOT_AUTOCONF; + + result=uart_add_one_port(&uart00_reg, port); + if(result){ + printk("uart_add_one_port returned %d\n",result); + return result; + } + dev_port_map[i].base_addr=dev_info->base_addr; + dev_port_map[i].port=port; + printk("uart00: added device at %x as ttyUA%d\n",dev_port_map[i].base_addr,i); + return 0; + +} + +int uart00_remove_devices(void) +{ + int i,result; + + + result=0; + for(i=1;i<UART_NR;i++){ + if(dev_port_map[i].base_addr){ + result=uart_remove_one_port(&uart00_reg, dev_port_map[i].port); + if(result) + return result; + + /* port removed sucessfully, so now tidy up */ + kfree(dev_port_map[i].port); + dev_port_map[i].base_addr=0; + dev_port_map[i].port=NULL; + } + } + return 0; + +} + +struct pld_hotswap_ops uart00_pldhs_ops={ + name: "uart00", + add_device: uart00_add_device, + remove_devices:uart00_remove_devices, +}; + +#endif + +static int __init uart00_init(void) +{ + int result; + + printk(KERN_INFO "Serial: UART00 driver $Revision: 1.32 $\n"); + + printk(KERN_WARNING "serial_uart00:Using temporary major/minor pairs" + " - these WILL change in the future\n"); + + result = uart_register_driver(&uart00_reg); + if (result) + return result; +#ifdef CONFIG_ARCH_CAMELOT + result = uart_add_one_port(&uart00_reg,&epxa10db_port); +#endif + if (result) + uart_unregister_driver(&uart00_reg); + +#ifdef CONFIG_PLD_HOTSWAP + pldhs_register_driver(&uart00_pldhs_ops); +#endif + return result; +} + +__initcall(uart00_init); diff --git a/drivers/usb/serial/keyspan_pda.S b/drivers/usb/serial/keyspan_pda.S index 10c99eadd36f..418fe69aa5e0 100644 --- a/drivers/usb/serial/keyspan_pda.S +++ b/drivers/usb/serial/keyspan_pda.S @@ -970,9 +970,9 @@ start_in__have_work: mov r1, #1 ; INbuf size counter start_in__loop: mov a, rx_ring_in - cjne a, rx_ring_out, start_in__still_copying + cjne a, rx_ring_out, start_inlocal_irq_enablell_copying sjmp start_in__kick -start_in__still_copying: +start_inlocal_irq_enablell_copying: inc rx_ring_out mov dpl, rx_ring_out movx a, @dptr diff --git a/drivers/usb/serial/xircom_pgs.S b/drivers/usb/serial/xircom_pgs.S index dd7c457c4cbf..05d99dd63776 100644 --- a/drivers/usb/serial/xircom_pgs.S +++ b/drivers/usb/serial/xircom_pgs.S @@ -1035,9 +1035,9 @@ start_in__have_work: mov r1, #1 ; INbuf size counter start_in__loop: mov a, rx_ring_in - cjne a, rx_ring_out, start_in__still_copying + cjne a, rx_ring_out, start_inlocal_irq_enablell_copying sjmp start_in__kick -start_in__still_copying: +start_inlocal_irq_enablell_copying: inc rx_ring_out mov dpl, rx_ring_out movx a, @dptr diff --git a/fs/block_dev.c b/fs/block_dev.c index aa496e1bdd29..2a0304c00c77 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -37,14 +37,6 @@ static unsigned long max_block(struct block_device *bdev) return retval; } -static loff_t blkdev_size(kdev_t dev) -{ - loff_t sz = blkdev_size_in_bytes(dev); - if (sz) - return sz; - return ~0ULL; -} - /* Kill _all_ buffers, dirty or not.. */ static void kill_bdev(struct block_device *bdev) { @@ -301,6 +293,8 @@ struct block_device *bdget(dev_t dev) new_bdev->bd_queue = NULL; new_bdev->bd_contains = NULL; new_bdev->bd_inode = inode; + new_bdev->bd_part_count = 0; + sema_init(&new_bdev->bd_part_sem, 1); inode->i_mode = S_IFBLK; inode->i_rdev = kdev; inode->i_bdev = new_bdev; @@ -423,9 +417,9 @@ int get_blkdev_list(char * p) Return the function table of a device. Load the driver if needed. */ -const struct block_device_operations * get_blkfops(unsigned int major) +struct block_device_operations * get_blkfops(unsigned int major) { - const struct block_device_operations *ret = NULL; + struct block_device_operations *ret = NULL; /* major 0 is used for non-device mounts */ if (major && major < MAX_BLKDEV) { @@ -487,7 +481,7 @@ int unregister_blkdev(unsigned int major, const char * name) int check_disk_change(kdev_t dev) { int i; - const struct block_device_operations * bdops = NULL; + struct block_device_operations * bdops = NULL; i = major(dev); if (i < MAX_BLKDEV) @@ -520,35 +514,28 @@ int check_disk_change(kdev_t dev) return 1; } -int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg) -{ - int res; - mm_segment_t old_fs = get_fs(); - - if (!bdev->bd_op->ioctl) - return -EINVAL; - set_fs(KERNEL_DS); - res = bdev->bd_op->ioctl(bdev->bd_inode, NULL, cmd, arg); - set_fs(old_fs); - return res; -} - static int do_open(struct block_device *bdev, struct inode *inode, struct file *file) { int ret = -ENXIO; kdev_t dev = to_kdev_t(bdev->bd_dev); struct module *owner = NULL; + struct block_device_operations *ops, *current_ops; - down(&bdev->bd_sem); lock_kernel(); - if (!bdev->bd_op) { - bdev->bd_op = get_blkfops(major(dev)); - if (!bdev->bd_op) - goto out; - owner = bdev->bd_op->owner; + ops = get_blkfops(major(dev)); + if (ops) { + owner = ops->owner; if (owner) __MOD_INC_USE_COUNT(owner); } + + down(&bdev->bd_sem); + if (!bdev->bd_op) + current_ops = ops; + else + current_ops = bdev->bd_op; + if (!current_ops) + goto out; if (!bdev->bd_contains) { unsigned minor = minor(dev); struct gendisk *g = get_gendisk(dev); @@ -569,15 +556,36 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * } } } - if (bdev->bd_op->open) { - ret = bdev->bd_op->open(inode, file); - if (ret) - goto out2; + if (bdev->bd_contains == bdev) { + if (current_ops->open) { + ret = current_ops->open(inode, file); + if (ret) + goto out2; + } + } else { + down(&bdev->bd_contains->bd_part_sem); + bdev->bd_contains->bd_part_count++; + up(&bdev->bd_contains->bd_part_sem); } - bdev->bd_inode->i_size = blkdev_size(dev); + if (!bdev->bd_op) + bdev->bd_op = ops; + else if (owner) + __MOD_DEC_USE_COUNT(owner); if (!bdev->bd_openers) { struct blk_dev_struct *p = blk_dev + major(dev); + struct gendisk *g = get_gendisk(dev); unsigned bsize = bdev_hardsect_size(bdev); + + bdev->bd_offset = 0; + if (g) { + bdev->bd_inode->i_size = + (loff_t) g->part[minor(dev)].nr_sects << 9; + bdev->bd_offset = g->part[minor(dev)].start_sect; + } else if (blk_size[major(dev)]) + bdev->bd_inode->i_size = + (loff_t) blk_size[major(dev)][minor(dev)] << 10; + else + bdev->bd_inode->i_size = 0; while (bsize < PAGE_CACHE_SIZE) { if (bdev->bd_inode->i_size & bsize) break; @@ -601,14 +609,12 @@ static int do_open(struct block_device *bdev, struct inode *inode, struct file * } } bdev->bd_openers++; - unlock_kernel(); up(&bdev->bd_sem); + unlock_kernel(); return 0; out2: if (!bdev->bd_openers) { - bdev->bd_op = NULL; - bdev->bd_queue = NULL; bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; if (bdev != bdev->bd_contains) { blkdev_put(bdev->bd_contains, BDEV_RAW); @@ -619,8 +625,8 @@ out1: if (owner) __MOD_DEC_USE_COUNT(owner); out: - unlock_kernel(); up(&bdev->bd_sem); + unlock_kernel(); if (ret) bdput(bdev); return ret; @@ -677,11 +683,17 @@ int blkdev_put(struct block_device *bdev, int kind) } if (!--bdev->bd_openers) kill_bdev(bdev); - if (bdev->bd_op->release) - ret = bdev->bd_op->release(bd_inode, NULL); - if (bdev->bd_op->owner) - __MOD_DEC_USE_COUNT(bdev->bd_op->owner); + if (bdev->bd_contains == bdev) { + if (bdev->bd_op->release) + ret = bdev->bd_op->release(bd_inode, NULL); + } else { + down(&bdev->bd_contains->bd_part_sem); + bdev->bd_contains->bd_part_count--; + up(&bdev->bd_contains->bd_part_sem); + } if (!bdev->bd_openers) { + if (bdev->bd_op->owner) + __MOD_DEC_USE_COUNT(bdev->bd_op->owner); bdev->bd_op = NULL; bdev->bd_queue = NULL; bdev->bd_inode->i_data.backing_dev_info = &default_backing_dev_info; @@ -706,15 +718,37 @@ static int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd, { int ret = -EINVAL; switch (cmd) { + /* + * deprecated, use the /proc/iosched interface instead + */ + case BLKELVGET: + case BLKELVSET: + ret = -ENOTTY; + break; case BLKRAGET: + case BLKROGET: + case BLKBSZGET: + case BLKSSZGET: case BLKFRAGET: + case BLKSECTGET: case BLKRASET: case BLKFRASET: + case BLKBSZSET: + case BLKPG: ret = blk_ioctl(inode->i_bdev, cmd, arg); break; default: if (inode->i_bdev->bd_op->ioctl) ret =inode->i_bdev->bd_op->ioctl(inode, file, cmd, arg); + if (ret == -EINVAL) { + switch (cmd) { + case BLKGETSIZE: + case BLKGETSIZE64: + case BLKFLSBUF: + case BLKROSET: + ret = blk_ioctl(inode->i_bdev,cmd,arg); + } + } break; } return ret; @@ -742,6 +776,16 @@ struct file_operations def_blk_fops = { ioctl: blkdev_ioctl, }; +int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg) +{ + int res; + mm_segment_t old_fs = get_fs(); + set_fs(KERNEL_DS); + res = blkdev_ioctl(bdev->bd_inode, NULL, cmd, arg); + set_fs(old_fs); + return res; +} + const char *__bdevname(kdev_t dev) { static char buffer[32]; diff --git a/fs/hfs/binsert.c b/fs/hfs/binsert.c index 6f0853892dcb..7fe11c3b88d3 100644 --- a/fs/hfs/binsert.c +++ b/fs/hfs/binsert.c @@ -16,21 +16,6 @@ #include "hfs_btree.h" /*================ File-local functions ================*/ - -/* btree locking functions */ -static inline void hfs_btree_lock(struct hfs_btree *tree) -{ - while (tree->lock) - hfs_sleep_on(&tree->wait); - tree->lock = 1; -} - -static inline void hfs_btree_unlock(struct hfs_btree *tree) -{ - tree->lock = 0; - hfs_wake_up(&tree->wait); -} - /* * binsert_nonfull() * @@ -526,11 +511,11 @@ restart: /* make certain we have enough nodes to proceed */ if ((tree->bthFree - tree->reserved) < reserve) { hfs_brec_relse(&brec, NULL); - hfs_btree_lock(tree); + down(&tree->sem); if ((tree->bthFree - tree->reserved) < reserve) { hfs_btree_extend(tree); } - hfs_btree_unlock(tree); + up(&tree->sem); if ((tree->bthFree - tree->reserved) < reserve) { return -ENOSPC; } else { diff --git a/fs/hfs/btree.c b/fs/hfs/btree.c index bc23f94c26de..f14bb508e134 100644 --- a/fs/hfs/btree.c +++ b/fs/hfs/btree.c @@ -172,8 +172,7 @@ struct hfs_btree * hfs_btree_init(struct hfs_mdb *mdb, ino_t cnid, bt->magic = HFS_BTREE_MAGIC; bt->sys_mdb = mdb->sys_mdb; bt->reserved = 0; - bt->lock = 0; - hfs_init_waitqueue(&bt->wait); + sema_init(&bt->sem, 1); bt->dirt = 0; memset(bt->cache, 0, sizeof(bt->cache)); diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index a82753c462d9..b036b1f2186e 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -302,8 +302,7 @@ static void __read_entry(struct hfs_cat_entry *entry, entry->modify_date = hfs_get_nl(cat->u.dir.MdDat); entry->backup_date = hfs_get_nl(cat->u.dir.BkDat); dir->dirs = dir->files = 0; - hfs_init_waitqueue(&dir->read_wait); - hfs_init_waitqueue(&dir->write_wait); + init_rwsem(&dir->sem); } else if (cat->cdrType == HFS_CDR_FIL) { struct hfs_file *fil = &entry->u.file; @@ -642,51 +641,6 @@ static void update_dir(struct hfs_mdb *mdb, struct hfs_cat_entry *dir, } /* - * Add a writer to dir, excluding readers. - * - * XXX: this is wrong. it allows a move to occur when a directory - * is being written to. - */ -static inline void start_write(struct hfs_cat_entry *dir) -{ - if (dir->u.dir.readers || waitqueue_active(&dir->u.dir.read_wait)) { - hfs_sleep_on(&dir->u.dir.write_wait); - } - ++dir->u.dir.writers; -} - -/* - * Add a reader to dir, excluding writers. - */ -static inline void start_read(struct hfs_cat_entry *dir) -{ - if (dir->u.dir.writers || waitqueue_active(&dir->u.dir.write_wait)) { - hfs_sleep_on(&dir->u.dir.read_wait); - } - ++dir->u.dir.readers; -} - -/* - * Remove a writer from dir, possibly admitting readers. - */ -static inline void end_write(struct hfs_cat_entry *dir) -{ - if (!(--dir->u.dir.writers)) { - hfs_wake_up(&dir->u.dir.read_wait); - } -} - -/* - * Remove a reader from dir, possibly admitting writers. - */ -static inline void end_read(struct hfs_cat_entry *dir) -{ - if (!(--dir->u.dir.readers)) { - hfs_wake_up(&dir->u.dir.write_wait); - } -} - -/* * create_entry() * * Add a new file or directory to the catalog B-tree and @@ -707,7 +661,7 @@ static int create_entry(struct hfs_cat_entry *parent, struct hfs_cat_key *key, } /* keep readers from getting confused by changing dir size */ - start_write(parent); + down_write(&parent->u.dir.sem); /* create a locked entry in the cache */ entry = get_entry(mdb, key, 0); @@ -782,7 +736,7 @@ bail1: bail2: hfs_cat_put(entry); done: - end_write(parent); + up_write(&parent->u.dir.sem); return error; } @@ -1058,21 +1012,19 @@ int hfs_cat_open(struct hfs_cat_entry *dir, struct hfs_brec *brec) struct hfs_cat_key key; int error; - if (dir->type != HFS_CDR_DIR) { + if (dir->type != HFS_CDR_DIR) return -EINVAL; - } /* Block writers */ - start_read(dir); + down_read(&dir->u.dir.sem); /* Find the directory */ hfs_cat_build_key(dir->cnid, NULL, &key); error = hfs_bfind(brec, dir->mdb->cat_tree, HFS_BKEY(&key), HFS_BFIND_READ_EQ); - if (error) { - end_read(dir); - } + if (error) + up_read(&dir->u.dir.sem); return error; } @@ -1109,7 +1061,7 @@ int hfs_cat_next(struct hfs_cat_entry *dir, struct hfs_brec *brec, *type = ((struct hfs_cat_rec *)brec->data)->cdrType; *cnid = brec_to_id(brec); } else { - end_read(dir); + up_read(&dir->u.dir.sem); } return error; } @@ -1127,7 +1079,7 @@ void hfs_cat_close(struct hfs_cat_entry *dir, struct hfs_brec *brec) { if (dir && brec) { hfs_brec_relse(brec, NULL); - end_read(dir); + up_read(&dir->u.dir.sem); } } @@ -1260,11 +1212,11 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry, } /* keep readers from getting confused by changing dir size */ - start_write(parent); + down_write(&parent->u.dir.sem); /* don't delete a busy directory */ if (entry->type == HFS_CDR_DIR) { - start_read(entry); + down_read(&entry->u.dir.sem); error = -ENOTEMPTY; if (entry->u.dir.files || entry->u.dir.dirs) @@ -1299,10 +1251,9 @@ hfs_delete_unlock: unlock_entry(entry); hfs_delete_end: - if (entry->type == HFS_CDR_DIR) { - end_read(entry); - } - end_write(parent); + if (entry->type == HFS_CDR_DIR) + up_read(&entry->u.dir.sem); + up_write(&parent->u.dir.sem); return error; } @@ -1347,10 +1298,10 @@ int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir, } /* keep readers from getting confused by changing dir size */ - start_write(new_dir); - if (old_dir != new_dir) { - start_write(old_dir); - } + down_write(&new_dir->u.dir.sem); + /* AV: smells like a deadlock */ + if (old_dir != new_dir) + down_write(&old_dir->u.dir.sem); /* Don't move a directory inside itself */ if (is_dir) { @@ -1556,10 +1507,9 @@ bail3: hfs_cat_put(dest); } done: - if (new_dir != old_dir) { - end_write(old_dir); - } - end_write(new_dir); + if (new_dir != old_dir) + up_write(&old_dir->u.dir.sem); + up_write(&new_dir->u.dir.sem); return error; } diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h index ad9f70d74294..adf912cbec0c 100644 --- a/fs/hfs/hfs.h +++ b/fs/hfs/hfs.h @@ -310,10 +310,7 @@ struct hfs_dir { hfs_u16 flags; hfs_u16 dirs; /* Number of directories in this one */ hfs_u16 files; /* Number of files in this directory */ - int readers; - hfs_wait_queue read_wait; - int writers; - hfs_wait_queue write_wait; + struct rw_semaphore sem; }; /* diff --git a/fs/hfs/hfs_btree.h b/fs/hfs/hfs_btree.h index c3371bfa883d..b4bc1069ecfd 100644 --- a/fs/hfs/hfs_btree.h +++ b/fs/hfs/hfs_btree.h @@ -194,8 +194,7 @@ struct hfs_btree { struct hfs_bnode /* The bnode cache */ *cache[HFS_CACHELEN]; struct hfs_cat_entry entry; /* Fake catalog entry */ - int lock; - hfs_wait_queue wait; + struct semaphore sem; int dirt; int keySize; /* Fields from the BTHdrRec in native byte-order: */ diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index ad179ff4bbdc..839108f3f21a 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -73,14 +73,13 @@ kmem_cache_t *fm_cache = NULL; /* Called by the VFS at mount time to initialize the whole file system. */ static int jffs_fill_super(struct super_block *sb, void *data, int silent) { - kdev_t dev = to_kdev_t(sb->s_dev); struct inode *root_inode; struct jffs_control *c; D1(printk(KERN_NOTICE "JFFS: Trying to mount device %s.\n", sb->s_id)); - if (major(dev) != MTD_BLOCK_MAJOR) { + if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) { printk(KERN_WARNING "JFFS: Trying to mount a " "non-mtd device.\n"); return -EINVAL; @@ -115,7 +114,7 @@ static int jffs_fill_super(struct super_block *sb, void *data, int silent) #ifdef CONFIG_JFFS_PROC_FS /* Set up the jffs proc file system. */ - if (jffs_register_jffs_proc_dir(dev, c) < 0) { + if (jffs_register_jffs_proc_dir(MINOR(sb->s_dev), c) < 0) { printk(KERN_WARNING "JFFS: Failed to initialize the JFFS " "proc file system for device %s.\n", sb->s_id); diff --git a/fs/jffs/jffs_proc.c b/fs/jffs/jffs_proc.c index b100bff2c49e..60677115b73d 100644 --- a/fs/jffs/jffs_proc.c +++ b/fs/jffs/jffs_proc.c @@ -65,52 +65,39 @@ static int jffs_proc_layout_read (char *page, char **start, off_t off, /* * Register a JFFS partition directory (called upon mount) */ -int jffs_register_jffs_proc_dir(kdev_t dev, struct jffs_control *c) +int jffs_register_jffs_proc_dir(int mtd, struct jffs_control *c) { struct jffs_partition_dir *part_dir; struct proc_dir_entry *part_info = 0; struct proc_dir_entry *part_layout = 0; struct proc_dir_entry *part_root = 0; + char name[10]; + sprintf(name, "%d", mtd); /* Allocate structure for local JFFS partition table */ - if (!(part_dir = (struct jffs_partition_dir *) - kmalloc (sizeof (struct jffs_partition_dir), GFP_KERNEL))) { - return -ENOMEM; - } + part_dir = (struct jffs_partition_dir *) + kmalloc(sizeof (struct jffs_partition_dir), GFP_KERNEL); + if (!part_dir) + goto out; /* Create entry for this partition */ - if ((part_root = create_proc_entry (kdevname(dev), - S_IFDIR | S_IRUGO | S_IXUGO, jffs_proc_root))) { - part_root->read_proc = jffs_proc_info_read; - part_root->data = (void *) c; - } - else { - kfree (part_dir); - return -ENOMEM; - } + part_root = proc_mkdir(name, jffs_proc_root); + if (!part_root) + goto out1; /* Create entry for 'info' file */ - if ((part_info = create_proc_entry ("info", 0, part_root))) { - part_info->read_proc = jffs_proc_info_read; - part_info->data = (void *) c; - } - else { - remove_proc_entry (part_root->name, jffs_proc_root); - kfree (part_dir); - return -ENOMEM; - } + part_info = create_proc_entry ("info", 0, part_root); + if (!part_info) + goto out2; + part_info->read_proc = jffs_proc_info_read; + part_info->data = (void *) c; /* Create entry for 'layout' file */ - if ((part_layout = create_proc_entry ("layout", 0, part_root))) { - part_layout->read_proc = jffs_proc_layout_read; - part_layout->data = (void *) c; - } - else { - remove_proc_entry (part_info->name, part_root); - remove_proc_entry (part_root->name, jffs_proc_root); - kfree (part_dir); - return -ENOMEM; - } + part_layout = create_proc_entry ("layout", 0, part_root); + if (!part_layout) + goto out3; + part_layout->read_proc = jffs_proc_layout_read; + part_layout->data = (void *) c; /* Fill in structure for table and insert in the list */ part_dir->c = c; @@ -122,6 +109,15 @@ int jffs_register_jffs_proc_dir(kdev_t dev, struct jffs_control *c) /* Return happy */ return 0; + +out3: + remove_proc_entry("info", part_root); +out2: + remove_proc_entry(name, jffs_proc_root); +out1: + kfree(part_dir); +out: + return -ENOMEM; } @@ -155,11 +151,7 @@ int jffs_unregister_jffs_proc_dir(struct jffs_control *c) * if it is. */ if (jffs_part_dirs == part_dir->next) -#if LINUX_VERSION_CODE < 0x020300 - remove_proc_entry ("jffs", &proc_root_fs); -#else remove_proc_entry ("jffs", proc_root_fs); -#endif /* Free memory for entry */ kfree(part_dir); diff --git a/fs/jffs/jffs_proc.h b/fs/jffs/jffs_proc.h index bf36c9d68cf6..39a1c5d162b0 100644 --- a/fs/jffs/jffs_proc.h +++ b/fs/jffs/jffs_proc.h @@ -22,7 +22,7 @@ /* The proc_dir_entry for jffs (defined in jffs_proc.c). */ extern struct proc_dir_entry *jffs_proc_root; -int jffs_register_jffs_proc_dir(kdev_t dev, struct jffs_control *c); +int jffs_register_jffs_proc_dir(int mtd, struct jffs_control *c); int jffs_unregister_jffs_proc_dir(struct jffs_control *c); #endif /* __LINUX_JFFS_PROC_H__ */ diff --git a/fs/namei.c b/fs/namei.c index e3e9b5434c90..86a067c7143a 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1496,14 +1496,18 @@ out: static void d_unhash(struct dentry *dentry) { dget(dentry); + spin_lock(&dcache_lock); switch (atomic_read(&dentry->d_count)) { default: + spin_unlock(&dcache_lock); shrink_dcache_parent(dentry); + spin_lock(&dcache_lock); if (atomic_read(&dentry->d_count) != 2) break; case 2: - d_drop(dentry); + list_del_init(&dentry->d_hash); } + spin_unlock(&dcache_lock); } int vfs_rmdir(struct inode *dir, struct dentry *dentry) @@ -1590,21 +1594,16 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry) DQUOT_INIT(dir); - dget(dentry); down(&dentry->d_inode->i_sem); if (d_mountpoint(dentry)) error = -EBUSY; - else { + else error = dir->i_op->unlink(dir, dentry); - if (!error) - d_delete(dentry); - } up(&dentry->d_inode->i_sem); - dput(dentry); - - if (!error) + if (!error) { + d_delete(dentry); inode_dir_notify(dir, DN_DELETE); - + } return error; } diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 73d57238a1cc..2a0b795c3afc 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -772,10 +772,6 @@ static int nfs_sillyrename(struct inode *dir, struct dentry *dentry) dentry->d_parent->d_name.name, dentry->d_name.name, atomic_read(&dentry->d_count)); - if (atomic_read(&dentry->d_count) == 1) - goto out; /* No need to silly rename. */ - - #ifdef NFS_PARANOIA if (!dentry->d_inode) printk("NFS: silly-renaming %s/%s, negative dentry??\n", @@ -837,31 +833,15 @@ static int nfs_safe_remove(struct dentry *dentry) { struct inode *dir = dentry->d_parent->d_inode; struct inode *inode = dentry->d_inode; - int error = -EBUSY, rehash = 0; + int error = -EBUSY; dfprintk(VFS, "NFS: safe_remove(%s/%s)\n", dentry->d_parent->d_name.name, dentry->d_name.name); - /* - * Unhash the dentry while we remove the file ... - */ - if (!d_unhashed(dentry)) { - d_drop(dentry); - rehash = 1; - } - if (atomic_read(&dentry->d_count) > 1) { -#ifdef NFS_PARANOIA - printk("nfs_safe_remove: %s/%s busy, d_count=%d\n", - dentry->d_parent->d_name.name, dentry->d_name.name, - atomic_read(&dentry->d_count)); -#endif - goto out; - } - /* If the dentry was sillyrenamed, we simply call d_delete() */ if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { error = 0; - goto out_delete; + goto out; } nfs_zap_caches(dir); @@ -872,15 +852,7 @@ static int nfs_safe_remove(struct dentry *dentry) goto out; if (inode) inode->i_nlink--; - - out_delete: - /* - * Free the inode - */ - d_delete(dentry); out: - if (rehash) - d_rehash(dentry); return error; } @@ -892,18 +864,29 @@ out: static int nfs_unlink(struct inode *dir, struct dentry *dentry) { int error; + int need_rehash = 0; dfprintk(VFS, "NFS: unlink(%s/%ld, %s)\n", dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); lock_kernel(); - error = nfs_sillyrename(dir, dentry); - if (error && error != -EBUSY) { - error = nfs_safe_remove(dentry); - if (!error) { - nfs_renew_times(dentry); - } + spin_lock(&dcache_lock); + if (atomic_read(&dentry->d_count) > 1) { + spin_unlock(&dcache_lock); + error = nfs_sillyrename(dir, dentry); + unlock_kernel(); + return error; + } + if (!d_unhashed(dentry)) { + list_del_init(&dentry->d_hash); + need_rehash = 1; } + spin_unlock(&dcache_lock); + error = nfs_safe_remove(dentry); + if (!error) + nfs_renew_times(dentry); + else if (need_rehash) + d_rehash(dentry); unlock_kernel(); return error; } diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c index f0d759e9b9f3..2516a2027b0e 100644 --- a/fs/partitions/acorn.c +++ b/fs/partitions/acorn.c @@ -10,33 +10,14 @@ * Scan ADFS partitions on hard disk drives. */ #include <linux/config.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/genhd.h> #include <linux/buffer_head.h> #include "check.h" #include "acorn.h" -static void -adfspart_setgeometry(kdev_t dev, unsigned int secspertrack, unsigned int heads) -{ -#ifdef CONFIG_BLK_DEV_MFM - extern void xd_set_geometry(kdev_t dev, unsigned char, unsigned char, - unsigned long, unsigned int); - - if (major(dev) == MFM_ACORN_MAJOR) { - unsigned long totalblocks = hd->part[MINOR(dev)].nr_sects; - xd_set_geometry(dev, secspertrack, heads, totalblocks, 1); - } -#endif -} - static struct adfs_discrecord * -adfs_partition(struct gendisk *hd, char *name, char *data, - unsigned long first_sector, int minor) +adfs_partition(struct parsed_partitions *state, char *name, char *data, + unsigned long first_sector, int slot) { struct adfs_discrecord *dr; unsigned int nr_sects; @@ -54,14 +35,14 @@ adfs_partition(struct gendisk *hd, char *name, char *data, if (name) printk(" [%s]", name); - add_gd_partition(hd, minor, first_sector, nr_sects); + put_partition(state, slot, first_sector, nr_sects); return dr; } #ifdef CONFIG_ACORN_PARTITION_RISCIX static int -riscix_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sect, int minor, unsigned long nr_sects) +riscix_partition(struct parsed_partitions *state, struct block_device *bdev, + unsigned long first_sect, int slot, unsigned long nr_sects) { Sector sect; struct riscix_record *rr; @@ -79,39 +60,38 @@ riscix_partition(struct gendisk *hd, struct block_device *bdev, printk(" <"); - add_gd_partition(hd, minor++, first_sect, size); + put_partition(state, slot++, first_sect, size); for (part = 0; part < 8; part++) { if (rr->part[part].one && memcmp(rr->part[part].name, "All\0", 4)) { - add_gd_partition(hd, minor++, - le32_to_cpu(rr->part[part].start), - le32_to_cpu(rr->part[part].length)); + put_partition(state, slot++, + le32_to_cpu(rr->part[part].start), + le32_to_cpu(rr->part[part].length)); printk("(%s)", rr->part[part].name); } } printk(" >\n"); } else { - add_gd_partition(hd, minor++, first_sect, nr_sects); + put_partition(state, slot++, first_sect, nr_sects); } put_dev_sector(sect); - return minor; + return slot; } #endif static int -linux_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sect, int minor, unsigned long nr_sects) +linux_partition(struct parsed_partitions *state, struct block_device *bdev, + unsigned long first_sect, int slot, unsigned long nr_sects) { Sector sect; struct linux_part *linuxp; - unsigned int mask = (1 << hd->minor_shift) - 1; unsigned long size = nr_sects > 2 ? 2 : nr_sects; printk(" [Linux]"); - add_gd_partition(hd, minor++, first_sect, size); + put_partition(state, slot++, first_sect, size); linuxp = (struct linux_part *)read_dev_sector(bdev, first_sect, §); if (!linuxp) @@ -120,9 +100,9 @@ linux_partition(struct gendisk *hd, struct block_device *bdev, printk(" <"); while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) || linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) { - if (!(minor & mask)) + if (slot == state->limit) break; - add_gd_partition(hd, minor++, first_sect + + put_partition(state, slot++, first_sect + le32_to_cpu(linuxp->start_sect), le32_to_cpu(linuxp->nr_sects)); linuxp ++; @@ -130,19 +110,20 @@ linux_partition(struct gendisk *hd, struct block_device *bdev, printk(" >"); put_dev_sector(sect); - return minor; + return slot; } #ifdef CONFIG_ACORN_PARTITION_CUMANA static int -adfspart_check_CUMANA(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int minor) +adfspart_check_CUMANA(struct parsed_partitions *state, struct block_device *bdev) { - unsigned int start_blk = 0, mask = (1 << hd->minor_shift) - 1; + unsigned long first_sector = 0; + unsigned int start_blk = 0; Sector sect; unsigned char *data; char *name = "CUMANA/ADFS"; int first = 1; + int slot = 1; /* * Try Cumana style partitions - sector 3 contains ADFS boot block @@ -165,10 +146,10 @@ adfspart_check_CUMANA(struct gendisk *hd, struct block_device *bdev, if (!data) return -1; - if (!(minor & mask)) + if (slot == state->limit) break; - dr = adfs_partition(hd, name, data, first_sector, minor++); + dr = adfs_partition(state, name, data, first_sector, slot++); if (!dr) break; @@ -193,19 +174,19 @@ adfspart_check_CUMANA(struct gendisk *hd, struct block_device *bdev, #ifdef CONFIG_ACORN_PARTITION_RISCIX case PARTITION_RISCIX_SCSI: /* RISCiX - we don't know how to find the next one. */ - minor = riscix_partition(hd, bdev, first_sector, - minor, nr_sects); + slot = riscix_partition(state, bdev, first_sector, + slot, nr_sects); break; #endif case PARTITION_LINUX: - minor = linux_partition(hd, bdev, first_sector, - minor, nr_sects); + slot = linux_partition(state, bdev, first_sector, + slot, nr_sects); break; } put_dev_sector(sect); - if (minor == -1) - return minor; + if (slot == -1) + return -1; } while (1); put_dev_sector(sect); return first ? 0 : 1; @@ -218,8 +199,6 @@ adfspart_check_CUMANA(struct gendisk *hd, struct block_device *bdev, * * Params : hd - pointer to gendisk structure to store partition info. * dev - device number to access. - * first_sector- first readable sector on the device. - * minor - first available minor on device. * * Returns: -1 on error, 0 for no ADFS boot sector, 1 for ok. * @@ -228,20 +207,20 @@ adfspart_check_CUMANA(struct gendisk *hd, struct block_device *bdev, * hda2 = non-ADFS partition. */ static int -adfspart_check_ADFS(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int minor) +adfspart_check_ADFS(struct parsed_partitions *state, struct block_device *bdev) { unsigned long start_sect, nr_sects, sectscyl, heads; Sector sect; unsigned char *data; struct adfs_discrecord *dr; unsigned char id; + int slot = 1; data = read_dev_sector(bdev, 6, §); if (!data) return -1; - dr = adfs_partition(hd, "ADFS", data, first_sector, minor++); + dr = adfs_partition(state, "ADFS", data, 0, slot++); if (!dr) { put_dev_sector(sect); return 0; @@ -253,9 +232,15 @@ adfspart_check_ADFS(struct gendisk *hd, struct block_device *bdev, id = data[0x1fc] & 15; put_dev_sector(sect); - adfspart_setgeometry(to_kdev_t(bdev->bd_dev), dr->secspertrack, heads); - invalidate_bdev(bdev, 1); - truncate_inode_pages(bdev->bd_inode->i_mapping, 0); +#ifdef CONFIG_BLK_DEV_MFM + if (MAJOR(bdev->bd_dev) == MFM_ACORN_MAJOR) { + extern void xd_set_geometry(struct block_device *, + unsigned char, unsigned char, unsigned int); + xd_set_geometry(bdev, dr->secspertrack, heads, 1); + invalidate_bdev(bdev, 1); + truncate_inode_pages(bdev->bd_inode->i_mapping, 0); + } +#endif /* * Work out start of non-adfs partition. @@ -263,20 +248,18 @@ adfspart_check_ADFS(struct gendisk *hd, struct block_device *bdev, nr_sects = (bdev->bd_inode->i_size >> 9) - start_sect; if (start_sect) { - first_sector += start_sect; - switch (id) { #ifdef CONFIG_ACORN_PARTITION_RISCIX case PARTITION_RISCIX_SCSI: case PARTITION_RISCIX_MFM: - minor = riscix_partition(hd, bdev, first_sector, - minor, nr_sects); + slot = riscix_partition(state, bdev, start_sect, + slot, nr_sects); break; #endif case PARTITION_LINUX: - minor = linux_partition(hd, bdev, first_sector, - minor, nr_sects); + slot = linux_partition(state, bdev, start_sect, + slot, nr_sects); break; } } @@ -304,8 +287,6 @@ static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long bloc * Purpose: allocate ICS partitions. * Params : hd - pointer to gendisk structure to store partition info. * dev - device number to access. - * first_sector- first readable sector on the device. - * minor - first available minor on device. * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok. * Alloc : hda = whole drive * hda1 = ADFS partition 0 on first drive. @@ -313,13 +294,13 @@ static int adfspart_check_ICSLinux(struct block_device *bdev, unsigned long bloc * ..etc.. */ static int -adfspart_check_ICS(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int minor) +adfspart_check_ICS(struct parsed_partitions *state, struct block_device *bdev) { Sector sect; unsigned char *data; unsigned long sum; - unsigned int i, mask = (1 << hd->minor_shift) - 1; + unsigned int i; + int slot; struct ics_part *p; /* @@ -343,16 +324,13 @@ adfspart_check_ICS(struct gendisk *hd, struct block_device *bdev, printk(" [ICS]"); - for (p = (struct ics_part *)data; p->size; p++) { - unsigned long start; - long size; + for (slot = 1, p = (struct ics_part *)data; p->size; p++) { + u32 start = le32_to_cpu(p->start); + u32 size = le32_to_cpu(p->size); - if ((minor & mask) == 0) + if (slot == state->limit) break; - start = le32_to_cpu(p->start); - size = le32_to_cpu(p->size); - if (size < 0) { size = -size; @@ -366,10 +344,8 @@ adfspart_check_ICS(struct gendisk *hd, struct block_device *bdev, } } - if (size) { - add_gd_partition(hd, minor, first_sector + start, size); - minor++; - } + if (size) + put_partition(state, slot++, start, size); } put_dev_sector(sect); @@ -381,8 +357,6 @@ adfspart_check_ICS(struct gendisk *hd, struct block_device *bdev, * Purpose: allocate ICS partitions. * Params : hd - pointer to gendisk structure to store partition info. * dev - device number to access. - * first_sector- first readable sector on the device. - * minor - first available minor on device. * Returns: -1 on error, 0 for no ICS table, 1 for partitions ok. * Alloc : hda = whole drive * hda1 = ADFS partition 0 on first drive. @@ -391,13 +365,13 @@ adfspart_check_ICS(struct gendisk *hd, struct block_device *bdev, */ #ifdef CONFIG_ACORN_PARTITION_POWERTEC static int -adfspart_check_POWERTEC(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int minor) +adfspart_check_POWERTEC(struct parsed_partitions *state, struct block_device *bdev) { Sector sect; unsigned char *data; struct ptec_partition *p; unsigned char checksum; + int slot = 1; int i; data = read_dev_sector(bdev, 0, §); @@ -415,16 +389,11 @@ adfspart_check_POWERTEC(struct gendisk *hd, struct block_device *bdev, printk(" [POWERTEC]"); for (i = 0, p = (struct ptec_partition *)data; i < 12; i++, p++) { - unsigned long start; - unsigned long size; - - start = le32_to_cpu(p->start); - size = le32_to_cpu(p->size); + u32 start = le32_to_cpu(p->start); + u32 size = le32_to_cpu(p->size); if (size) - add_gd_partition(hd, minor, first_sector + start, - size); - minor++; + put_partition(state, slot++, start, size); } put_dev_sector(sect); @@ -432,7 +401,7 @@ adfspart_check_POWERTEC(struct gendisk *hd, struct block_device *bdev, } #endif -static int (*partfn[])(struct gendisk *, struct block_device *, unsigned long, int) = { +static int (*partfn[])(struct parsed_partitions *, struct block_device *) = { #ifdef CONFIG_ACORN_PARTITION_ICS adfspart_check_ICS, #endif @@ -454,18 +423,15 @@ static int (*partfn[])(struct gendisk *, struct block_device *, unsigned long, i * * Params : hd - pointer to gendisk structure * dev - device number to access - * first_sect - first available sector on the disk. - * first_minor - first available minor on this device. * * Returns: -1 on error, 0 if not ADFS format, 1 if ok. */ -int acorn_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sect, int first_minor) +int acorn_partition(struct parsed_partitions *state, struct block_device *bdev) { int i; for (i = 0; partfn[i]; i++) { - int r = partfn[i](hd, bdev, first_sect, first_minor); + int r = partfn[i](state, bdev); if (r) { if (r > 0) printk("\n"); diff --git a/fs/partitions/acorn.h b/fs/partitions/acorn.h index f4b3b80d383c..7c984234ae81 100644 --- a/fs/partitions/acorn.h +++ b/fs/partitions/acorn.h @@ -50,6 +50,4 @@ struct ptec_partition { }; -int acorn_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sect, int first_minor); - +int acorn_partition(struct parsed_partitions *state, struct block_device *bdev); diff --git a/fs/partitions/amiga.c b/fs/partitions/amiga.c index bf70413faa9f..89a717bbbe42 100644 --- a/fs/partitions/amiga.c +++ b/fs/partitions/amiga.c @@ -7,14 +7,7 @@ * Re-organised Feb 1998 Russell King */ -#include <linux/fs.h> -#include <linux/genhd.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/blk.h> - -#include <asm/byteorder.h> +#include <linux/types.h> #include <linux/affs_hardblocks.h> #include "check.h" @@ -31,14 +24,14 @@ checksum_block(u32 *m, int size) } int -amiga_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor) +amiga_partition(struct parsed_partitions *state, struct block_device *bdev) { Sector sect; unsigned char *data; struct RigidDiskBlock *rdb; struct PartitionBlock *pb; int start_sect, nr_sects, blk, part, res = 0; + int slot = 1; for (blk = 0; ; blk++, put_dev_sector(sect)) { if (blk == RDB_ALLOCATION_LIMIT) @@ -100,8 +93,7 @@ amiga_partition(struct gendisk *hd, struct block_device *bdev, start_sect = be32_to_cpu(pb->pb_Environment[9]) * be32_to_cpu(pb->pb_Environment[3]) * be32_to_cpu(pb->pb_Environment[5]); - add_gd_partition(hd,first_part_minor,start_sect,nr_sects); - first_part_minor++; + put_partition(state,slot++,start_sect,nr_sects); res = 1; } printk("\n"); diff --git a/fs/partitions/amiga.h b/fs/partitions/amiga.h index 4f4f8a2772d9..2f3e9ce22d53 100644 --- a/fs/partitions/amiga.h +++ b/fs/partitions/amiga.h @@ -2,7 +2,5 @@ * fs/partitions/amiga.h */ -int -amiga_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor); +int amiga_partition(struct parsed_partitions *state, struct block_device *bdev); diff --git a/fs/partitions/atari.c b/fs/partitions/atari.c index e01a3e461961..192a6adfdefd 100644 --- a/fs/partitions/atari.c +++ b/fs/partitions/atari.c @@ -7,17 +7,7 @@ * Re-organised Feb 1998 Russell King */ -#include <linux/fs.h> -#include <linux/genhd.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/blk.h> #include <linux/ctype.h> - -#include <asm/byteorder.h> -#include <asm/system.h> - #include "check.h" #include "atari.h" @@ -40,15 +30,14 @@ static inline int OK_id(char *s) memcmp (s, "RAW", 3) == 0 ; } -int atari_partition (struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int minor) +int atari_partition(struct parsed_partitions *state, struct block_device *bdev) { - int m_lim = minor + (1 << hd->minor_shift); Sector sect; struct rootsector *rs; struct partition_info *pi; u32 extensect; u32 hd_size; + int slot; #ifdef ICD_PARTS int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */ #endif @@ -58,7 +47,7 @@ int atari_partition (struct gendisk *hd, struct block_device *bdev, return -1; /* Verify this is an Atari rootsector: */ - hd_size = hd->part[minor - 1].nr_sects; + hd_size = bdev->bd_inode->i_size >> 9; if (!VALID_PARTITION(&rs->part[0], hd_size) && !VALID_PARTITION(&rs->part[1], hd_size) && !VALID_PARTITION(&rs->part[2], hd_size) && @@ -74,7 +63,7 @@ int atari_partition (struct gendisk *hd, struct block_device *bdev, pi = &rs->part[0]; printk (" AHDI"); - for (; pi < &rs->part[4] && minor < m_lim; minor++, pi++) { + for (slot = 1; pi < &rs->part[4] && slot < state->limit; slot++, pi++) { struct rootsector *xrs; Sector sect2; ulong partsect; @@ -84,7 +73,7 @@ int atari_partition (struct gendisk *hd, struct block_device *bdev, /* active partition */ if (memcmp (pi->id, "XGM", 3) != 0) { /* we don't care about other id's */ - add_gd_partition (hd, minor, be32_to_cpu(pi->st), + put_partition (state, slot, be32_to_cpu(pi->st), be32_to_cpu(pi->siz)); continue; } @@ -109,7 +98,7 @@ int atari_partition (struct gendisk *hd, struct block_device *bdev, break; } - add_gd_partition(hd, minor, + put_partition(state, slot, partsect + be32_to_cpu(xrs->part[0].st), be32_to_cpu(xrs->part[0].siz)); @@ -126,8 +115,7 @@ int atari_partition (struct gendisk *hd, struct block_device *bdev, partsect = be32_to_cpu(xrs->part[1].st) + extensect; put_dev_sector(sect2); - minor++; - if (minor >= m_lim) { + if (++slot == state->limit) { printk( "\nMaximum number of partitions reached!\n" ); break; } @@ -140,12 +128,12 @@ int atari_partition (struct gendisk *hd, struct block_device *bdev, /* sanity check: no ICD format if first partition invalid */ if (OK_id(pi->id)) { printk(" ICD<"); - for (; pi < &rs->icdpart[8] && minor < m_lim; minor++, pi++) { + for (; pi < &rs->icdpart[8] && slot < state->limit; slot++, pi++) { /* accept only GEM,BGM,RAW,LNX,SWP partitions */ if (!((pi->flg & 1) && OK_id(pi->id))) continue; part_fmt = 2; - add_gd_partition (hd, minor, + put_partition (state, slot, be32_to_cpu(pi->st), be32_to_cpu(pi->siz)); } @@ -159,4 +147,3 @@ int atari_partition (struct gendisk *hd, struct block_device *bdev, return 1; } - diff --git a/fs/partitions/atari.h b/fs/partitions/atari.h index 6a14eb75947d..314d4dbd33bf 100644 --- a/fs/partitions/atari.h +++ b/fs/partitions/atari.h @@ -31,6 +31,4 @@ struct rootsector u16 checksum; /* checksum for bootable disks */ } __attribute__((__packed__)); -int atari_partition (struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor); - +int atari_partition(struct parsed_partitions *state, struct block_device *bdev); diff --git a/fs/partitions/check.c b/fs/partitions/check.c index bccd9cf773dd..462405eabad8 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -34,10 +34,13 @@ #include "ultrix.h" #include "efi.h" +#if CONFIG_BLK_DEV_MD +extern void md_autodetect_dev(kdev_t dev); +#endif + int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ -static int (*check_part[])(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sect, int first_minor) = { +static int (*check_part[])(struct parsed_partitions *, struct block_device *) = { #ifdef CONFIG_ACORN_PARTITION acorn_partition, #endif @@ -199,28 +202,6 @@ char *disk_name (struct gendisk *hd, int minor, char *buf) return buf; } -/* - * Add a partitions details to the devices partition description. - */ -void add_gd_partition(struct gendisk *hd, int minor, int start, int size) -{ -#ifndef CONFIG_DEVFS_FS - char buf[40]; -#endif - - hd->part[minor].start_sect = start; - hd->part[minor].nr_sects = size; -#ifdef CONFIG_DEVFS_FS - printk(" p%d", (minor & ((1 << hd->minor_shift) - 1))); -#else - if ((hd->major >= COMPAQ_SMART2_MAJOR+0 && hd->major <= COMPAQ_SMART2_MAJOR+7) || - (hd->major >= COMPAQ_CISS_MAJOR+0 && hd->major <= COMPAQ_CISS_MAJOR+7)) - printk(" p%d", (minor & ((1 << hd->minor_shift) - 1))); - else - printk(" %s", disk_name(hd, minor, buf)); -#endif -} - /* Driverfs file support */ static ssize_t partition_device_kdev_read(struct device *driverfs_dev, char *page, size_t count, loff_t off) @@ -255,6 +236,7 @@ void driverfs_create_partitions(struct gendisk *hd, int minor) int max_p; int part; devfs_handle_t dir = 0; + struct hd_struct *p = hd->part + minor; /* get parent driverfs device structure */ if (hd->driverfs_dev_arr) @@ -279,9 +261,9 @@ void driverfs_create_partitions(struct gendisk *hd, int minor) /* for all partitions setup parents and device node names */ for(part=0; part < max_p; part++) { - if ((part == 0) || (hd->part[minor + part].nr_sects >= 1)) { + if ((part == 0) || (p[part].nr_sects >= 1)) { struct device * current_driverfs_dev = - &hd->part[minor+part].hd_driverfs_dev; + &p[part].hd_driverfs_dev; current_driverfs_dev->parent = parent; /* handle disc case */ current_driverfs_dev->driver_data = @@ -319,7 +301,6 @@ void driverfs_create_partitions(struct gendisk *hd, int minor) &partition_device_kdev_file); } } - return; } void driverfs_remove_partitions(struct gendisk *hd, int minor) @@ -327,14 +308,14 @@ void driverfs_remove_partitions(struct gendisk *hd, int minor) int max_p; int part; struct device * current_driverfs_dev; + struct hd_struct *p = hd->part + minor; max_p=(1 << hd->minor_shift); /* for all parts setup parent relationships and device node names */ for(part=1; part < max_p; part++) { - if ((hd->part[minor + part].nr_sects >= 1)) { - current_driverfs_dev = - &hd->part[minor + part].hd_driverfs_dev; + if ((p[part].nr_sects >= 1)) { + current_driverfs_dev = &p[part].hd_driverfs_dev; device_remove_file(current_driverfs_dev, partition_device_type_file.name); device_remove_file(current_driverfs_dev, @@ -342,7 +323,7 @@ void driverfs_remove_partitions(struct gendisk *hd, int minor) put_device(current_driverfs_dev); } } - current_driverfs_dev = &hd->part[minor].hd_driverfs_dev; + current_driverfs_dev = &p->hd_driverfs_dev; device_remove_file(current_driverfs_dev, partition_device_type_file.name); device_remove_file(current_driverfs_dev, @@ -351,12 +332,13 @@ void driverfs_remove_partitions(struct gendisk *hd, int minor) return; } -static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor) +static void check_partition(struct gendisk *hd, kdev_t dev) { devfs_handle_t de = NULL; unsigned long first_sector; struct block_device *bdev; char buf[64]; + struct parsed_partitions *state; int i; first_sector = hd->part[minor(dev)].start_sect; @@ -369,56 +351,66 @@ static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor hd->part[minor(dev)].start_sect = 0; return; } + if (first_sector != 0) + BUG(); + + state = kmalloc(sizeof(struct parsed_partitions), GFP_KERNEL); + if (!state) + return; if (hd->de_arr) de = hd->de_arr[minor(dev) >> hd->minor_shift]; i = devfs_generate_path (de, buf, sizeof buf); - if (i >= 0) + if (i >= 0) { printk(KERN_INFO " /dev/%s:", buf + i); - else - printk(KERN_INFO " %s:", disk_name(hd, minor(dev), buf)); - bdev = bdget(kdev_t_to_nr(dev)); - bdev->bd_contains = bdev; - bdev->bd_inode->i_size = (loff_t)hd->part[minor(dev)].nr_sects << 9; - if (!bdev->bd_openers) { - struct blk_dev_struct *p = blk_dev + major(dev); - unsigned bsize = bdev_hardsect_size(bdev); - while (bsize < PAGE_CACHE_SIZE) { - if (bdev->bd_inode->i_size & bsize) - break; - bsize <<= 1; - } - if (p->queue) - bdev->bd_queue = p->queue(dev); - else - bdev->bd_queue = &p->request_queue; - bdev->bd_block_size = bsize; - bdev->bd_inode->i_blkbits = blksize_bits(bsize); + sprintf(state->name, "p"); + } else { + unsigned n = hd->major; + disk_name(hd, minor(dev), state->name); + printk(KERN_INFO " %s:", state->name); + if (n - COMPAQ_SMART2_MAJOR <= 7 || n - COMPAQ_CISS_MAJOR <= 7) + sprintf(state->name, "p"); } + bdev = bdget(kdev_t_to_nr(dev)); + if (blkdev_get(bdev, FMODE_READ, 0, BDEV_RAW)) + goto out; + state->limit = 1<<hd->minor_shift; for (i = 0; check_part[i]; i++) { - int res; - res = check_part[i](hd, bdev, first_sector, first_part_minor); - if (res) { - if (res < 0 && warn_no_part) + int res, j; + memset(&state->parts, 0, sizeof(state->parts)); + res = check_part[i](state, bdev); + if (!res) + continue; + if (res < 0) { + if (warn_no_part) printk(" unable to read partition table\n"); goto setup_devfs; } + for (j = 1; j < state->limit; j++) { + hd->part[j + minor(dev)].start_sect = + state->parts[j].from; + hd->part[j + minor(dev)].nr_sects = + state->parts[j].size; +#if CONFIG_BLK_DEV_MD + if (!state->parts[j].flags) + continue; + md_autodetect_dev(mk_kdev(major(dev),minor(dev)+j)); +#endif + } + goto setup_devfs; } printk(" unknown partition table\n"); setup_devfs: - invalidate_bdev(bdev, 1); - truncate_inode_pages(bdev->bd_inode->i_mapping, 0); - bdput(bdev); - i = first_part_minor - 1; - + blkdev_put(bdev, BDEV_RAW); +out: /* Setup driverfs tree */ if (hd->sizes) - driverfs_create_partitions(hd, i); + driverfs_create_partitions(hd, minor(dev)); else - driverfs_remove_partitions(hd, i); + driverfs_remove_partitions(hd, minor(dev)); - devfs_register_partitions (hd, i, hd->sizes ? 0 : 1); + devfs_register_partitions (hd, minor(dev), hd->sizes ? 0 : 1); } #ifdef CONFIG_DEVFS_FS @@ -564,7 +556,7 @@ void grok_partitions(kdev_t dev, long size) if (!size) return; - check_partition(g, mk_kdev(g->major, first_minor), 1 + first_minor); + check_partition(g, mk_kdev(g->major, first_minor)); /* * We need to set the sizes array before we will be able to access @@ -632,28 +624,3 @@ int wipe_partitions(kdev_t dev) } return 0; } - -/* - * Make sure that a proposed subpartition is strictly contained inside - * the parent partition. If all is well, call add_gd_partition(). - */ -int -check_and_add_subpartition(struct gendisk *hd, int super_minor, int minor, - int sub_start, int sub_size) -{ - int start = hd->part[super_minor].start_sect; - int size = hd->part[super_minor].nr_sects; - - if (start == sub_start && size == sub_size) { - /* full parent partition, we have it already */ - return 0; - } - - if (start <= sub_start && start+size >= sub_start+sub_size) { - add_gd_partition(hd, minor, sub_start, sub_size); - return 1; - } - - printk("bad subpartition - ignored\n"); - return 0; -} diff --git a/fs/partitions/check.h b/fs/partitions/check.h index 17818bd6401f..8598a571b76c 100644 --- a/fs/partitions/check.h +++ b/fs/partitions/check.h @@ -5,12 +5,28 @@ * add_gd_partition adds a partitions details to the devices partition * description. */ -void add_gd_partition(struct gendisk *hd, int minor, int start, int size); -/* - * check_and_add_subpartition does the same for subpartitions - */ -int check_and_add_subpartition(struct gendisk *hd, int super_minor, - int minor, int sub_start, int sub_size); +enum { MAX_PART = 256 }; + +struct parsed_partitions { + char name[40]; + struct { + unsigned long from; + unsigned long size; + int flags; + } parts[MAX_PART]; + int next; + int limit; +}; + +static inline void +put_partition(struct parsed_partitions *p, int n, int from, int size) +{ + if (n < p->limit) { + p->parts[n].from = from; + p->parts[n].size = size; + printk(" %s%d", p->name, n); + } +} extern int warn_no_part; diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c index ea6496a3de2c..86e6314bd4d2 100644 --- a/fs/partitions/efi.c +++ b/fs/partitions/efi.c @@ -87,26 +87,10 @@ * ************************************************************/ #include <linux/config.h> -#include <linux/fs.h> -#include <linux/genhd.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/blk.h> -#include <linux/blkpg.h> -#include <linux/slab.h> -#include <linux/smp_lock.h> -#include <linux/init.h> #include <linux/crc32.h> -#include <asm/system.h> -#include <asm/byteorder.h> #include "check.h" #include "efi.h" -#if CONFIG_BLK_DEV_MD -extern void md_autodetect_dev(kdev_t dev); -#endif - /* Handle printing of 64-bit values */ /* Borrowed from /usr/include/inttypes.h */ # if BITS_PER_LONG == 64 @@ -184,7 +168,6 @@ is_pmbr_valid(legacy_mbr *mbr) /** * last_lba(): return number of last logical block of device - * @hd: gendisk with partition list * @bdev: block device * * Description: Returns last LBA value on success, 0 on error. @@ -193,16 +176,13 @@ is_pmbr_valid(legacy_mbr *mbr) * physical sectors available on the disk. */ static u64 -last_lba(struct gendisk *hd, struct block_device *bdev) +last_lba(struct block_device *bdev) { - if (!hd || !hd->part || !bdev) - return 0; - return hd->part[minor(to_kdev_t(bdev->bd_dev))].nr_sects - 1; + return (bdev->bd_inode->i_size >> 9) - 1; } /** * read_lba(): Read bytes from disk, starting at given LBA - * @hd * @bdev * @lba * @buffer @@ -212,39 +192,26 @@ last_lba(struct gendisk *hd, struct block_device *bdev) * Returns number of bytes read on success, 0 on error. */ static size_t -read_lba(struct gendisk *hd, struct block_device *bdev, u64 lba, - u8 * buffer, size_t count) +read_lba(struct block_device *bdev, u64 lba, u8 * buffer, size_t count) { + size_t totalreadcount = 0; - size_t totalreadcount = 0, bytesread = 0; - unsigned long blocksize; - int i; - Sector sect; - unsigned char *data = NULL; - - if (!hd || !bdev || !buffer || !count) + if (!bdev || !buffer) return 0; - blocksize = bdev_hardsect_size(bdev); - if (!blocksize) - blocksize = 512; - - for (i = 0; count > 0; i++) { - data = read_dev_sector(bdev, lba, §); + while (count) { + int copied = 512; + Sector sect; + unsigned char *data = read_dev_sector(bdev, lba++, §); if (!data) - return totalreadcount; - - bytesread = - PAGE_CACHE_SIZE - (data - - (unsigned char *) page_address(sect.v)); - bytesread = min(bytesread, count); - memcpy(buffer, data, bytesread); + break; + if (copied > count) + copied = count; + memcpy(buffer, data, copied); put_dev_sector(sect); - - buffer += bytesread; - totalreadcount += bytesread; - count -= bytesread; - lba += (bytesread / blocksize); + buffer += copied; + totalreadcount +=copied; + count -= copied; } return totalreadcount; } @@ -252,7 +219,6 @@ read_lba(struct gendisk *hd, struct block_device *bdev, u64 lba, /** * alloc_read_gpt_entries(): reads partition entries from disk - * @hd * @bdev * @gpt - GPT header * @@ -261,12 +227,11 @@ read_lba(struct gendisk *hd, struct block_device *bdev, u64 lba, * Notes: remember to free pte when you're done! */ static gpt_entry * -alloc_read_gpt_entries(struct gendisk *hd, - struct block_device *bdev, gpt_header *gpt) +alloc_read_gpt_entries(struct block_device *bdev, gpt_header *gpt) { size_t count; gpt_entry *pte; - if (!hd || !bdev || !gpt) + if (!bdev || !gpt) return NULL; count = le32_to_cpu(gpt->num_partition_entries) * @@ -278,7 +243,7 @@ alloc_read_gpt_entries(struct gendisk *hd, return NULL; memset(pte, 0, count); - if (read_lba(hd, bdev, le64_to_cpu(gpt->partition_entry_lba), + if (read_lba(bdev, le64_to_cpu(gpt->partition_entry_lba), (u8 *) pte, count) < count) { kfree(pte); @@ -290,7 +255,6 @@ alloc_read_gpt_entries(struct gendisk *hd, /** * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk - * @hd * @bdev * @lba is the Logical Block Address of the partition table * @@ -299,10 +263,10 @@ alloc_read_gpt_entries(struct gendisk *hd, * Note: remember to free gpt when finished with it. */ static gpt_header * -alloc_read_gpt_header(struct gendisk *hd, struct block_device *bdev, u64 lba) +alloc_read_gpt_header(struct block_device *bdev, u64 lba) { gpt_header *gpt; - if (!hd || !bdev) + if (!bdev) return NULL; gpt = kmalloc(sizeof (gpt_header), GFP_KERNEL); @@ -310,7 +274,7 @@ alloc_read_gpt_header(struct gendisk *hd, struct block_device *bdev, u64 lba) return NULL; memset(gpt, 0, sizeof (gpt_header)); - if (read_lba(hd, bdev, lba, (u8 *) gpt, + if (read_lba(bdev, lba, (u8 *) gpt, sizeof (gpt_header)) < sizeof (gpt_header)) { kfree(gpt); gpt=NULL; @@ -322,7 +286,6 @@ alloc_read_gpt_header(struct gendisk *hd, struct block_device *bdev, u64 lba) /** * is_gpt_valid() - tests one GPT header and PTEs for validity - * @hd * @bdev * @lba is the logical block address of the GPT header to test * @gpt is a GPT header ptr, filled on return. @@ -332,14 +295,14 @@ alloc_read_gpt_header(struct gendisk *hd, struct block_device *bdev, u64 lba) * If valid, returns pointers to newly allocated GPT header and PTEs. */ static int -is_gpt_valid(struct gendisk *hd, struct block_device *bdev, u64 lba, +is_gpt_valid(struct block_device *bdev, u64 lba, gpt_header **gpt, gpt_entry **ptes) { u32 crc, origcrc; - if (!hd || !bdev || !gpt || !ptes) + if (!bdev || !gpt || !ptes) return 0; - if (!(*gpt = alloc_read_gpt_header(hd, bdev, lba))) + if (!(*gpt = alloc_read_gpt_header(bdev, lba))) return 0; /* Check the GUID Partition Table signature */ @@ -377,7 +340,7 @@ is_gpt_valid(struct gendisk *hd, struct block_device *bdev, u64 lba, return 0; } - if (!(*ptes = alloc_read_gpt_entries(hd, bdev, *gpt))) { + if (!(*ptes = alloc_read_gpt_entries(bdev, *gpt))) { kfree(*gpt); *gpt = NULL; return 0; @@ -502,7 +465,6 @@ compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) /** * find_valid_gpt() - Search disk for valid GPT headers and PTEs - * @hd * @bdev * @gpt is a GPT header ptr, filled on return. * @ptes is a PTEs ptr, filled on return. @@ -512,31 +474,30 @@ compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) * or the Alternate GPT header and PTEs valid, and the PMBR valid. */ static int -find_valid_gpt(struct gendisk *hd, struct block_device *bdev, - gpt_header **gpt, gpt_entry **ptes) +find_valid_gpt(struct block_device *bdev, gpt_header **gpt, gpt_entry **ptes) { int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; gpt_header *pgpt = NULL, *agpt = NULL; gpt_entry *pptes = NULL, *aptes = NULL; legacy_mbr *legacymbr = NULL; u64 lastlba; - if (!hd || !bdev || !gpt || !ptes) + if (!bdev || !gpt || !ptes) return 0; - lastlba = last_lba(hd, bdev); - good_pgpt = is_gpt_valid(hd, bdev, GPT_PRIMARY_PARTITION_TABLE_LBA, + lastlba = last_lba(bdev); + good_pgpt = is_gpt_valid(bdev, GPT_PRIMARY_PARTITION_TABLE_LBA, &pgpt, &pptes); if (good_pgpt) { - good_agpt = is_gpt_valid(hd, bdev, + good_agpt = is_gpt_valid(bdev, le64_to_cpu(pgpt->alternate_lba), &agpt, &aptes); if (!good_agpt) { - good_agpt = is_gpt_valid(hd, bdev, lastlba, + good_agpt = is_gpt_valid(bdev, lastlba, &agpt, &aptes); } } else { - good_agpt = is_gpt_valid(hd, bdev, lastlba, + good_agpt = is_gpt_valid(bdev, lastlba, &agpt, &aptes); } @@ -549,7 +510,7 @@ find_valid_gpt(struct gendisk *hd, struct block_device *bdev, legacymbr = kmalloc(sizeof (*legacymbr), GFP_KERNEL); if (legacymbr) { memset(legacymbr, 0, sizeof (*legacymbr)); - read_lba(hd, bdev, 0, (u8 *) legacymbr, + read_lba(bdev, 0, (u8 *) legacymbr, sizeof (*legacymbr)); good_pmbr = is_pmbr_valid(legacymbr); kfree(legacymbr); @@ -616,12 +577,16 @@ find_valid_gpt(struct gendisk *hd, struct block_device *bdev, } /** - * add_gpt_partitions(struct gendisk *hd, struct block_device *bdev, - * @hd + * efi_partition(struct parsed_partitions *state, struct block_device *bdev) + * @state * @bdev * - * Description: Create devices for each entry in the GUID Partition Table - * Entries. + * Description: called from check.c, if the disk contains GPT + * partitions, sets up partition entries in the kernel. + * + * If the first block on the disk is a legacy MBR, + * it will get handled by msdos_partition(). + * If it's a Protective MBR, we'll handle it here. * * We do not create a Linux partition for GPT, but * only for the actual data partitions. @@ -631,106 +596,41 @@ find_valid_gpt(struct gendisk *hd, struct block_device *bdev, * 1 if successful * */ -static int -add_gpt_partitions(struct gendisk *hd, struct block_device *bdev, int nextminor) +int +efi_partition(struct parsed_partitions *state, struct block_device *bdev) { gpt_header *gpt = NULL; gpt_entry *ptes = NULL; u32 i; - int max_p; - - if (!hd || !bdev) - return -1; - if (!find_valid_gpt(hd, bdev, &gpt, &ptes) || !gpt || !ptes) { - if (gpt) { - kfree(gpt); - gpt = NULL; - } - if (ptes) { - kfree(ptes); - ptes = NULL; - } + if (!find_valid_gpt(bdev, &gpt, &ptes) || !gpt || !ptes) { + kfree(gpt); + kfree(ptes); return 0; } Dprintk("GUID Partition Table is valid! Yea!\n"); - max_p = (1 << hd->minor_shift) - 1; - for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < max_p; i++) { + for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { if (!efi_guidcmp(ptes[i].partition_type_guid, NULL_GUID)) continue; - add_gd_partition(hd, nextminor+i, - le64_to_cpu(ptes[i].starting_lba), + put_partition(state, i+1, le64_to_cpu(ptes[i].starting_lba), (le64_to_cpu(ptes[i].ending_lba) - le64_to_cpu(ptes[i].starting_lba) + 1)); /* If there's this is a RAID volume, tell md */ -#if CONFIG_BLK_DEV_MD if (!efi_guidcmp(ptes[i].partition_type_guid, - PARTITION_LINUX_RAID_GUID)) { - md_autodetect_dev(mk_kdev(hd->major, - nextminor)); - } -#endif + PARTITION_LINUX_RAID_GUID)) + state->parts[i+1].flags = 1; } kfree(ptes); - ptes=NULL; kfree(gpt); - gpt=NULL; printk("\n"); return 1; } -/** - * efi_partition(): EFI GPT partition handling entry function - * @hd - * @bdev - * @first_sector: unused - * @first_part_minor: minor number assigned to first GPT partition found - * - * Description: called from check.c, if the disk contains GPT - * partitions, sets up partition entries in the kernel. - * - * If the first block on the disk is a legacy MBR, - * it will get handled by msdos_partition(). - * If it's a Protective MBR, we'll handle it here. - * - * set_blocksize() calls are necessary to be able to read - * a disk with an odd number of 512-byte sectors, as the - * default BLOCK_SIZE of 1024 bytes won't let that last - * sector be read otherwise. - * - * Returns: - * -1 if unable to read the partition table - * 0 if this isn't our partitoin table - * 1 if successful - */ -int -efi_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor) -{ - - int hardblocksize = bdev_hardsect_size(bdev); - int orig_blksize_size = block_size(bdev); - int rc = 0; - - /* Need to change the block size that the block layer uses */ - - if (orig_blksize_size != hardblocksize) - set_blocksize(bdev, hardblocksize); - - rc = add_gpt_partitions(hd, bdev, first_part_minor); - - /* change back */ - if (orig_blksize_size != hardblocksize) - set_blocksize(bdev, orig_blksize_size); - - return rc; -} - /* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically diff --git a/fs/partitions/efi.h b/fs/partitions/efi.h index eaaab6ef651f..5e85d8e2846d 100644 --- a/fs/partitions/efi.h +++ b/fs/partitions/efi.h @@ -112,9 +112,7 @@ typedef struct _legacy_mbr { } __attribute__ ((packed)) legacy_mbr; /* Functions */ -extern int - efi_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor); +extern int efi_partition(struct parsed_partitions *state, struct block_device *bdev); #endif diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c index 249e87361d66..63d5bfdd6c5a 100644 --- a/fs/partitions/ibm.c +++ b/fs/partitions/ibm.c @@ -88,8 +88,7 @@ ibm_ioctl_unopened(struct block_device *bdev, unsigned cmd, unsigned long arg) /* */ int -ibm_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor) +ibm_partition(struct parsed_partitions *state, struct block_device *bdev) { int blocksize, offset, size; dasd_information_t *info; @@ -100,9 +99,6 @@ ibm_partition(struct gendisk *hd, struct block_device *bdev, unsigned char *data; Sector sect; - if ( first_sector != 0 ) - BUG(); - if ((info = kmalloc(sizeof(dasd_information_t), GFP_KERNEL)) == NULL) goto out_noinfo; if ((geo = kmalloc(sizeof(struct hd_geometry), GFP_KERNEL)) == NULL) @@ -155,9 +151,7 @@ ibm_partition(struct gendisk *hd, struct block_device *bdev, offset = (info->label_block + 1); size = bdev->bd_inode->i_size >> 9; } - // add_gd_partition(hd, first_part_minor - 1, 0, size); - add_gd_partition(hd, first_part_minor, - offset*(blocksize >> 9), + put_partition(state, 1, offset*(blocksize >> 9), size-offset*(blocksize >> 9)); } else if (strncmp(type, "VOL1", 4) == 0) { /* @@ -194,9 +188,9 @@ ibm_partition(struct gendisk *hd, struct block_device *bdev, offset = cchh2blk(&f1.DS1EXT1.llimit, geo); size = cchh2blk(&f1.DS1EXT1.ulimit, geo) - offset + geo->sectors; - if (counter >= (1 << hd->minor_shift)) + if (counter >= state->limit) break; - add_gd_partition(hd, first_part_minor + counter, + put_partition(state, counter + 1, offset * (blocksize >> 9), size * (blocksize >> 9)); counter++; @@ -212,9 +206,7 @@ ibm_partition(struct gendisk *hd, struct block_device *bdev, printk("(nonl)/%8s:", name); offset = (info->label_block + 1); size = (bdev->bd_inode->i_size >> 9); - // add_gd_partition(hd, first_part_minor - 1, 0, size); - add_gd_partition(hd, first_part_minor, - offset*(blocksize >> 9), + put_partition(state, 1, offset*(blocksize >> 9), size-offset*(blocksize >> 9)); } diff --git a/fs/partitions/ibm.h b/fs/partitions/ibm.h index 08b05ed151fe..31f85a6ac459 100644 --- a/fs/partitions/ibm.h +++ b/fs/partitions/ibm.h @@ -1 +1 @@ -int ibm_partition(struct gendisk *, struct block_device *, unsigned long, int); +int ibm_partition(struct parsed_partitions *, struct block_device *); diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c index 895e6465d904..4b8a28c57e78 100644 --- a/fs/partitions/ldm.c +++ b/fs/partitions/ldm.c @@ -23,12 +23,6 @@ * * 28/10/2001 - Added sorting of ldm partitions. (AIA) */ -#include <linux/types.h> -#include <asm/unaligned.h> -#include <asm/byteorder.h> -#include <linux/pagemap.h> -#include <linux/genhd.h> -#include <linux/blkdev.h> #include <linux/slab.h> #include "check.h" #include "ldm.h" @@ -57,7 +51,6 @@ static void ldm_debug(const char *f, ...); #endif /* !CONFIG_LDM_DEBUG */ /* Necessary forward declarations. */ -static int create_partition(struct gendisk *, int, int, int); static int parse_privhead(const u8 *, struct privhead *); static u64 get_vnum(const u8 *, int *); static int get_vstr(const u8 *, u8 *, const int); @@ -161,8 +154,7 @@ static int parse_vblk(const u8 *buffer, const int buf_size, struct vblk *vb) /** * add_partition_to_list - insert partition into a partition list * @pl: sorted list of partitions - * @hd: gendisk structure to which the data partition belongs - * @disk_minor: minor number of the disk device + * @disk_size: number of sectors on the disk device * @start: first sector within the disk device * @size: number of sectors on the partition device * @@ -174,16 +166,15 @@ static int parse_vblk(const u8 *buffer, const int buf_size, struct vblk *vb) * * TODO: Add sanity check for overlapping partitions. (AIA) */ -static int add_partition_to_list(struct list_head *pl, const struct gendisk *hd, - const int disk_minor, const unsigned long start, +static int add_partition_to_list(struct list_head *pl, + const unsigned long disk_size, + const unsigned long start, const unsigned long size) { struct ldm_part *lp, *lptmp; struct list_head *tmp; - if (!hd->part) - return -1; - if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) { + if (start < 1 || start + size > disk_size) { printk(LDM_CRIT "LDM partition exceeds physical disk. " "Skipping.\n"); return -1; @@ -215,7 +206,6 @@ static int add_partition_to_list(struct list_head *pl, const struct gendisk *hd, /** * create_data_partitions - create the data partition devices * @hd: gendisk structure in which to create the data partitions - * @first_sector: first sector within the disk device * @first_part_minor: first minor number of data partition devices * @dev: partition device holding the LDM database * @vm: in memory vmdb structure of @dev @@ -234,9 +224,8 @@ static int add_partition_to_list(struct list_head *pl, const struct gendisk *hd, * * Return 1 on success and -1 on error. */ -static int create_data_partitions(struct gendisk *hd, - const unsigned long first_sector, int first_part_minor, - struct block_device *bdev, const struct vmdb *vm, +static int create_data_partitions(struct parsed_partitions *state, + int slot, struct block_device *bdev, const struct vmdb *vm, const struct privhead *ph, const struct ldmdisk *dk, unsigned long base) { @@ -249,7 +238,7 @@ static int create_data_partitions(struct gendisk *hd, int vblk; int vsize; /* VBLK size. */ int perbuf; /* VBLKs per buffer. */ - int buffer, lastbuf, lastofs, err, disk_minor; + int buffer, lastbuf, lastofs, err; vb = (struct vblk*)kmalloc(sizeof(struct vblk), GFP_KERNEL); if (!vb) @@ -268,11 +257,6 @@ static int create_data_partitions(struct gendisk *hd, if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize > ph->config_size * 512) goto err_out; - /* - * Get the minor number of the parent device so we can check we don't - * go beyond the end of the device. - */ - disk_minor = (first_part_minor >> hd->minor_shift) << hd->minor_shift; for (buffer = 0; buffer < lastbuf; buffer++) { data = read_dev_sector(bdev, base + 2*OFF_VBLK + buffer, §); if (!data) @@ -292,8 +276,9 @@ static int create_data_partitions(struct gendisk *hd, if (dk->obj_id != vb->disk_id) continue; /* Ignore invalid partition errors. */ - if (add_partition_to_list(&pl, hd, disk_minor, - first_sector + vb->start_sector + + if (add_partition_to_list(&pl, + bdev->bd_inode->i_size>>9, + vb->start_sector + ph->logical_disk_start, vb->num_sectors) < -1) goto brelse_out; @@ -306,7 +291,7 @@ out: printk(" <"); list_for_each(tmp, &pl) { lp = list_entry(tmp, struct ldm_part, part_list); - add_gd_partition(hd, first_part_minor++, lp->start, lp->size); + put_partition(state, slot++, lp->start, lp->size); } printk(" >\n"); if (!list_empty(&pl)) { @@ -820,42 +805,6 @@ err_out: } /** - * create_partition - validate input and create a kernel partition device - * @hd: gendisk structure in which to create partition - * @minor: minor number for device to create - * @start: starting offset of the partition into the parent device - * @size: size of the partition - * - * This validates the range, then puts an entry into the kernel's partition - * table. - * - * @start and @size are numbers of sectors. - * - * Return 1 on succes and -1 on error. - */ -static int create_partition(struct gendisk *hd, const int minor, - const int start, const int size) -{ - int disk_minor; - - if (!hd->part) - return -1; - /* - * Get the minor number of the parent device so we can check we don't - * go beyond the end of the device. - */ - disk_minor = (minor >> hd->minor_shift) << hd->minor_shift; - if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) { - printk(LDM_CRIT "LDM Partition exceeds physical disk. " - "Aborting.\n"); - return -1; - } - add_gd_partition(hd, minor, start, size); - ldm_debug("Created partition successfully.\n"); - return 1; -} - -/** * parse_privhead - parse the LDM database PRIVHEAD structure * @buffer: LDM database privhead structure loaded from the device * @ph: in memory privhead structure to return parsed information in @@ -901,19 +850,16 @@ static int parse_privhead(const u8 *buffer, struct privhead *ph) } /** - * create_db_partition - create a dedicated partition for our database - * @hd: gendisk structure in which to create partition + * find_db_partition - find our database * @dev: device of which to create partition * @ph: @dev's LDM database private header * - * Find the primary private header, locate the LDM database, then create a + * Find the primary private header and the LDM database * partition to wrap it. * * Return 1 on succes, 0 if device is not a dynamic disk and -1 on error. */ -static int create_db_partition(struct gendisk *hd, struct block_device *bdev, - const unsigned long first_sector, const int first_part_minor, - struct privhead *ph) +static int find_db_partition(struct block_device *bdev, struct privhead *ph) { Sector sect; unsigned char *data; @@ -930,10 +876,15 @@ static int create_db_partition(struct gendisk *hd, struct block_device *bdev, return 0; } err = parse_privhead(data, ph); - if (err == 1) - err = create_partition(hd, first_part_minor, first_sector + - ph->config_start, ph->config_size); put_dev_sector(sect); + if (err <= 0) + return err; + if (ph->config_start < 1 || + ph->config_start + ph->config_size > bdev->bd_inode->i_size >> 9) { + printk(LDM_CRIT "LDM Partition exceeds physical disk. " + "Aborting.\n"); + err = -1; + } return err; } @@ -990,8 +941,6 @@ no_msdos_partition: * ldm_partition - find out whether a device is a dynamic disk and handle it * @hd: gendisk structure in which to return the handled disk * @dev: device we need to look at - * @first_sector: first sector within the device - * @first_part_minor: first minor number of partitions for the device * * Description: * @@ -1010,8 +959,7 @@ no_msdos_partition: * 0 if @dev is not a dynamic disk, * -1 if an error occured. */ -int ldm_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor) +int ldm_partition(struct parsed_partitions *state, struct block_device *bdev) { struct privhead *ph = NULL; struct tocblock *toc = NULL; @@ -1020,8 +968,6 @@ int ldm_partition(struct gendisk *hd, struct block_device *bdev, unsigned long db_first; int err; - if (!hd) - return 0; /* Check the partition table. */ err = validate_partition_table(bdev); if (err != 1) @@ -1029,10 +975,11 @@ int ldm_partition(struct gendisk *hd, struct block_device *bdev, if (!(ph = (struct privhead*)kmalloc(sizeof(*ph), GFP_KERNEL))) goto no_mem; /* Create the LDM database device. */ - err = create_db_partition(hd, bdev, first_sector, first_part_minor, ph); + err = find_db_partition(bdev, ph); if (err != 1) goto out; - db_first = hd->part[first_part_minor].start_sect; + db_first = ph->config_start; + put_partition(state, 1, db_first, ph->config_size); /* Check the backup privheads. */ err = validate_privheads(bdev, ph, db_first); if (err != 1) @@ -1056,8 +1003,8 @@ int ldm_partition(struct gendisk *hd, struct block_device *bdev, if (err != 1) goto out; /* Finally, create the data partition devices. */ - err = create_data_partitions(hd, first_sector, first_part_minor + - LDM_FIRST_PART_OFFSET, bdev, vm, ph, dk, db_first); + err = create_data_partitions(state, 1 + LDM_FIRST_PART_OFFSET, + bdev, vm, ph, dk, db_first); if (err == 1) ldm_debug("Parsed LDM database successfully.\n"); out: @@ -1071,4 +1018,3 @@ no_mem: err = -1; goto out; } - diff --git a/fs/partitions/ldm.h b/fs/partitions/ldm.h index b1255e84c632..0d9d9ffa0763 100644 --- a/fs/partitions/ldm.h +++ b/fs/partitions/ldm.h @@ -150,8 +150,7 @@ struct ldm_part { unsigned long size; }; -int ldm_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor); +int ldm_partition(struct parsed_partitions *state, struct block_device *bdev); #endif /* _FS_PT_LDM_H_ */ diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c index 84baad30c812..cf3dccd6810d 100644 --- a/fs/partitions/mac.c +++ b/fs/partitions/mac.c @@ -7,16 +7,7 @@ */ #include <linux/config.h> -#include <linux/fs.h> -#include <linux/genhd.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/blk.h> #include <linux/ctype.h> - -#include <asm/system.h> - #include "check.h" #include "mac.h" @@ -36,9 +27,9 @@ static inline void mac_fix_string(char *stg, int len) stg[i] = 0; } -int mac_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long fsec, int first_part_minor) +int mac_partition(struct parsed_partitions *state, struct block_device *bdev) { + int slot = 1; Sector sect; unsigned char *data; int blk, blocks_in_map; @@ -79,8 +70,8 @@ int mac_partition(struct gendisk *hd, struct block_device *bdev, part = (struct mac_partition *) (data + pos%512); if (be16_to_cpu(part->signature) != MAC_PARTITION_MAGIC) break; - add_gd_partition(hd, first_part_minor, - fsec + be32_to_cpu(part->start_block) * (secsize/512), + put_partition(state, slot, + be32_to_cpu(part->start_block) * (secsize/512), be32_to_cpu(part->block_count) * (secsize/512)); #ifdef CONFIG_ALL_PPC @@ -126,7 +117,7 @@ int mac_partition(struct gendisk *hd, struct block_device *bdev, } #endif /* CONFIG_ALL_PPC */ - ++first_part_minor; + ++slot; } #ifdef CONFIG_ALL_PPC if (found_root_goodness) @@ -138,4 +129,3 @@ int mac_partition(struct gendisk *hd, struct block_device *bdev, printk("\n"); return 1; } - diff --git a/fs/partitions/mac.h b/fs/partitions/mac.h index 9d36ec64983e..9b0a0d242597 100644 --- a/fs/partitions/mac.h +++ b/fs/partitions/mac.h @@ -41,4 +41,4 @@ struct mac_driver_desc { /* ... more stuff */ }; -int mac_partition(struct gendisk *hd, struct block_device *bdev, unsigned long fsec, int first_part_minor); +int mac_partition(struct parsed_partitions *state, struct block_device *bdev); diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index f8f987998fe3..f06e68e07cce 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -20,12 +20,6 @@ */ #include <linux/config.h> -#include <linux/fs.h> -#include <linux/genhd.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/blk.h> #include <linux/buffer_head.h> /* for invalidate_bdev() */ #ifdef CONFIG_BLK_DEV_IDE @@ -38,16 +32,10 @@ EXPORT_SYMBOL(ide_xlate_1024_hook); #define ide_xlate_1024 ide_xlate_1024_hook #endif -#include <asm/system.h> - #include "check.h" #include "msdos.h" #include "efi.h" -#if CONFIG_BLK_DEV_MD -extern void md_autodetect_dev(kdev_t dev); -#endif - /* * Many architectures don't like unaligned accesses, which is * frequently the case with the nr_sects and start_sect partition @@ -73,23 +61,6 @@ static inline int is_extended_partition(struct partition *p) SYS_IND(p) == LINUX_EXTENDED_PARTITION); } -/* - * partition_name() formats the short partition name into the supplied - * buffer, and returns a pointer to that buffer. - * Used by several partition types which makes conditional inclusion messy, - * use __attribute__ ((unused)) instead. - */ -static char __attribute__ ((unused)) - *partition_name (struct gendisk *hd, int minor, char *buf) -{ -#ifdef CONFIG_DEVFS_FS - sprintf(buf, "p%d", (minor & ((1 << hd->minor_shift) - 1))); - return buf; -#else - return disk_name(hd, minor, buf); -#endif -} - #define MSDOS_LABEL_MAGIC1 0x55 #define MSDOS_LABEL_MAGIC2 0xAA @@ -110,26 +81,26 @@ msdos_magic_present(unsigned char *p) * only for the actual data partitions. */ -static void extended_partition(struct gendisk *hd, struct block_device *bdev, - int minor, unsigned long first_size, int *current_minor) +static void +parse_extended(struct parsed_partitions *state, struct block_device *bdev, + u32 first_sector, u32 first_size) { struct partition *p; Sector sect; unsigned char *data; - unsigned long first_sector, this_sector, this_size; - int mask = (1 << hd->minor_shift) - 1; + u32 this_sector, this_size; int sector_size = bdev_hardsect_size(bdev) / 512; int loopct = 0; /* number of links followed without finding a data partition */ int i; - this_sector = first_sector = hd->part[minor].start_sect; + this_sector = first_sector; this_size = first_size; while (1) { if (++loopct > 100) return; - if ((*current_minor & mask) == 0) + if (state->next == state->limit) return; data = read_dev_sector(bdev, this_sector, §); if (!data) @@ -153,7 +124,7 @@ static void extended_partition(struct gendisk *hd, struct block_device *bdev, * First process the data partition(s) */ for (i=0; i<4; i++, p++) { - unsigned long offs, size, next; + u32 offs, size, next; if (!NR_SECTS(p) || is_extended_partition(p)) continue; @@ -171,27 +142,19 @@ static void extended_partition(struct gendisk *hd, struct block_device *bdev, continue; } - add_gd_partition(hd, *current_minor, next, size); -#if CONFIG_BLK_DEV_MD - if (SYS_IND(p) == LINUX_RAID_PARTITION) { - md_autodetect_dev(mk_kdev(hd->major,*current_minor)); - } -#endif - - (*current_minor)++; + put_partition(state, state->next, next, size); + if (SYS_IND(p) == LINUX_RAID_PARTITION) + state->parts[state->next].flags = 1; loopct = 0; - if ((*current_minor & mask) == 0) + if (++state->next == state->limit) goto done; } /* * Next, process the (first) extended partition, if present. * (So far, there seems to be no reason to make - * extended_partition() recursive and allow a tree + * parse_extended() recursive and allow a tree * of extended partitions.) * It should be a link to the next logical partition. - * Create a minor for this just long enough to get the next - * partition table. The minor will be reused for the next - * data partition. */ p -= 4; for (i=0; i<4; i++, p++) @@ -202,7 +165,6 @@ static void extended_partition(struct gendisk *hd, struct block_device *bdev, this_sector = first_sector + START_SECT(p) * sector_size; this_size = NR_SECTS(p) * sector_size; - minor = *current_minor; put_dev_sector(sect); } done: @@ -213,18 +175,13 @@ done: indicates linux swap. Be careful before believing this is Solaris. */ static void -solaris_x86_partition(struct gendisk *hd, struct block_device *bdev, - int minor, int *current_minor) +parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev, + u32 offset, u32 size, int origin) { - #ifdef CONFIG_SOLARIS_X86_PARTITION - long offset = hd->part[minor].start_sect; Sector sect; struct solaris_x86_vtoc *v; - struct solaris_x86_slice *s; - int mask = (1 << hd->minor_shift) - 1; int i; - char buf[40]; v = (struct solaris_x86_vtoc *)read_dev_sector(bdev, offset+1, §); if (!v) @@ -233,29 +190,23 @@ solaris_x86_partition(struct gendisk *hd, struct block_device *bdev, put_dev_sector(sect); return; } - printk(" %s: <solaris:", partition_name(hd, minor, buf)); + printk(" %s%d: <solaris:", state->name, origin); if (le32_to_cpu(v->v_version) != 1) { printk(" cannot handle version %d vtoc>\n", le32_to_cpu(v->v_version)); put_dev_sector(sect); return; } - for (i=0; i<SOLARIS_X86_NUMSLICE; i++) { - if ((*current_minor & mask) == 0) - break; - s = &v->v_slice[i]; - + for (i=0; i<SOLARIS_X86_NUMSLICE && state->next<state->limit; i++) { + struct solaris_x86_slice *s = &v->v_slice[i]; if (s->s_size == 0) continue; printk(" [s%d]", i); /* solaris partitions are relative to current MS-DOS - * one but add_gd_partition starts relative to sector - * zero of the disk. Therefore, must add the offset - * of the current partition */ - add_gd_partition(hd, *current_minor, + * one; must add the offset of the current partition */ + put_partition(state, state->next++, le32_to_cpu(s->s_start)+offset, le32_to_cpu(s->s_size)); - (*current_minor)++; } put_dev_sector(sect); printk(" >\n"); @@ -265,17 +216,16 @@ solaris_x86_partition(struct gendisk *hd, struct block_device *bdev, #ifdef CONFIG_BSD_DISKLABEL /* * Create devices for BSD partitions listed in a disklabel, under a - * dos-like partition. See extended_partition() for more information. + * dos-like partition. See parse_extended() for more information. */ -static void do_bsd_partition(struct gendisk *hd, struct block_device *bdev, - int minor, int *current_minor, char *name, int max_partitions) +static void +parse_bsd(struct parsed_partitions *state, struct block_device *bdev, + u32 offset, u32 size, int origin, char *flavour, + int max_partitions) { - long offset = hd->part[minor].start_sect; Sector sect; struct bsd_disklabel *l; struct bsd_partition *p; - int mask = (1 << hd->minor_shift) - 1; - char buf[40]; l = (struct bsd_disklabel *)read_dev_sector(bdev, offset+1, §); if (!l) @@ -284,69 +234,75 @@ static void do_bsd_partition(struct gendisk *hd, struct block_device *bdev, put_dev_sector(sect); return; } - printk(" %s: <%s:", partition_name(hd, minor, buf), name); + printk(" %s%d: <%s:", state->name, origin, flavour); if (le16_to_cpu(l->d_npartitions) < max_partitions) max_partitions = le16_to_cpu(l->d_npartitions); for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) { - int bsd_start, bsd_size; + u32 bsd_start, bsd_size; - if ((*current_minor & mask) == 0) + if (state->next == state->limit) break; if (p->p_fstype == BSD_FS_UNUSED) continue; bsd_start = le32_to_cpu(p->p_offset); bsd_size = le32_to_cpu(p->p_size); - if (check_and_add_subpartition(hd, minor, *current_minor, - bsd_start, bsd_size)) - (*current_minor)++; + if (offset == bsd_start && size == bsd_size) + /* full parent partition, we have it already */ + continue; + if (offset > bsd_start || offset+size < bsd_start+bsd_size) { + printk("bad subpartition - ignored\n"); + continue; + } + put_partition(state, state->next++, bsd_start, bsd_size); } put_dev_sector(sect); printk(" >\n"); } #endif -static void bsd_partition(struct gendisk *hd, struct block_device *bdev, - int minor, int *current_minor) +static void +parse_freebsd(struct parsed_partitions *state, struct block_device *bdev, + u32 offset, u32 size, int origin) { #ifdef CONFIG_BSD_DISKLABEL - do_bsd_partition(hd, bdev, minor, current_minor, "bsd", - BSD_MAXPARTITIONS); + parse_bsd(state, bdev, offset, size, origin, + "bsd", BSD_MAXPARTITIONS); #endif } -static void netbsd_partition(struct gendisk *hd, struct block_device *bdev, - int minor, int *current_minor) +static void +parse_netbsd(struct parsed_partitions *state, struct block_device *bdev, + u32 offset, u32 size, int origin) { #ifdef CONFIG_BSD_DISKLABEL - do_bsd_partition(hd, bdev, minor, current_minor, "netbsd", - BSD_MAXPARTITIONS); + parse_bsd(state, bdev, offset, size, origin, + "netbsd", BSD_MAXPARTITIONS); #endif } -static void openbsd_partition(struct gendisk *hd, struct block_device *bdev, - int minor, int *current_minor) +static void +parse_openbsd(struct parsed_partitions *state, struct block_device *bdev, + u32 offset, u32 size, int origin) { #ifdef CONFIG_BSD_DISKLABEL - do_bsd_partition(hd, bdev, minor, current_minor, + parse_bsd(state, bdev, offset, size, origin, "openbsd", OPENBSD_MAXPARTITIONS); #endif } /* * Create devices for Unixware partitions listed in a disklabel, under a - * dos-like partition. See extended_partition() for more information. + * dos-like partition. See parse_extended() for more information. */ -static void unixware_partition(struct gendisk *hd, struct block_device *bdev, - int minor, int *current_minor) +static void +parse_unixware(struct parsed_partitions *state, struct block_device *bdev, + u32 offset, u32 size, int origin) { #ifdef CONFIG_UNIXWARE_DISKLABEL - long offset = hd->part[minor].start_sect; Sector sect; struct unixware_disklabel *l; struct unixware_slice *p; - int mask = (1 << hd->minor_shift) - 1; - char buf[40]; l = (struct unixware_disklabel *)read_dev_sector(bdev, offset+29, §); if (!l) @@ -356,18 +312,16 @@ static void unixware_partition(struct gendisk *hd, struct block_device *bdev, put_dev_sector(sect); return; } - printk(" %s: <unixware:", partition_name(hd, minor, buf)); + printk(" %s%d: <unixware:", state->name, origin); p = &l->vtoc.v_slice[1]; /* I omit the 0th slice as it is the same as whole disk. */ while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) { - if ((*current_minor & mask) == 0) + if (state->next == state->limit) break; - if (p->s_label != UNIXWARE_FS_UNUSED) { - add_gd_partition(hd, *current_minor, START_SECT(p), - NR_SECTS(p)); - (*current_minor)++; - } + if (p->s_label != UNIXWARE_FS_UNUSED) + put_partition(state, state->next++, + START_SECT(p), NR_SECTS(p)); p++; } put_dev_sector(sect); @@ -380,17 +334,15 @@ static void unixware_partition(struct gendisk *hd, struct block_device *bdev, * Anand Krishnamurthy <anandk@wiproge.med.ge.com> * Rajeev V. Pillai <rajeevvp@yahoo.com> */ -static void minix_partition(struct gendisk *hd, struct block_device *bdev, - int minor, int *current_minor) +static void +parse_minix(struct parsed_partitions *state, struct block_device *bdev, + u32 offset, u32 size, int origin) { #ifdef CONFIG_MINIX_SUBPARTITION - long offset = hd->part[minor].start_sect; Sector sect; unsigned char *data; struct partition *p; - int mask = (1 << hd->minor_shift) - 1; int i; - char buf[40]; data = read_dev_sector(bdev, offset, §); if (!data) @@ -404,16 +356,14 @@ static void minix_partition(struct gendisk *hd, struct block_device *bdev, if (msdos_magic_present (data + 510) && SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */ - printk(" %s: <minix:", partition_name(hd, minor, buf)); + printk(" %s%d: <minix:", state->name, origin); for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) { - if ((*current_minor & mask) == 0) + if (state->next == state->limit) break; /* add each partition in use */ - if (SYS_IND(p) == MINIX_PARTITION) { - add_gd_partition(hd, *current_minor, + if (SYS_IND(p) == MINIX_PARTITION) + put_partition(state, state->next++, START_SECT(p), NR_SECTS(p)); - (*current_minor)++; - } } printk(" >\n"); } @@ -423,14 +373,15 @@ static void minix_partition(struct gendisk *hd, struct block_device *bdev, static struct { unsigned char id; - void (*parse)(struct gendisk *, struct block_device *, int, int *); + void (*parse)(struct parsed_partitions *, struct block_device *, + u32, u32, int); } subtypes[] = { - {BSD_PARTITION, bsd_partition}, - {NETBSD_PARTITION, netbsd_partition}, - {OPENBSD_PARTITION, openbsd_partition}, - {MINIX_PARTITION, minix_partition}, - {UNIXWARE_PARTITION, unixware_partition}, - {SOLARIS_X86_PARTITION, solaris_x86_partition}, + {BSD_PARTITION, parse_freebsd}, + {NETBSD_PARTITION, parse_netbsd}, + {OPENBSD_PARTITION, parse_openbsd}, + {MINIX_PARTITION, parse_minix}, + {UNIXWARE_PARTITION, parse_unixware}, + {SOLARIS_X86_PARTITION, parse_solaris_x86}, {0, NULL}, }; /* @@ -515,16 +466,13 @@ reread: return 1; } -int msdos_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor) +int msdos_partition(struct parsed_partitions *state, struct block_device *bdev) { - int i, minor = first_part_minor; + int sector_size = bdev_hardsect_size(bdev) / 512; Sector sect; - struct partition *p; unsigned char *data; - int mask = (1 << hd->minor_shift) - 1; - int sector_size = bdev_hardsect_size(bdev) / 512; - int current_minor = first_part_minor; + struct partition *p; + int slot; int err; err = handle_ide_mess(bdev); @@ -539,7 +487,7 @@ int msdos_partition(struct gendisk *hd, struct block_device *bdev, } p = (struct partition *) (data + 0x1be); #ifdef CONFIG_EFI_PARTITION - for (i=1 ; i<=4 ; i++,p++) { + for (slot = 1 ; slot <= 4 ; slot++, p++) { /* If this is an EFI GPT disk, msdos should ignore it. */ if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) { put_dev_sector(sect); @@ -555,28 +503,24 @@ int msdos_partition(struct gendisk *hd, struct block_device *bdev, * On the second pass look inside *BSD, Unixware and Solaris partitions. */ - current_minor += 4; - for (i=1 ; i<=4 ; minor++,i++,p++) { - if (!NR_SECTS(p)) + state->next = 5; + for (slot = 1 ; slot <= 4 ; slot++, p++) { + u32 start = START_SECT(p)*sector_size; + u32 size = NR_SECTS(p)*sector_size; + if (!size) continue; - add_gd_partition(hd, minor, - first_sector+START_SECT(p)*sector_size, - NR_SECTS(p)*sector_size); -#if CONFIG_BLK_DEV_MD - if (SYS_IND(p) == LINUX_RAID_PARTITION) { - md_autodetect_dev(mk_kdev(hd->major,minor)); - } -#endif if (is_extended_partition(p)) { - unsigned long size = hd->part[minor].nr_sects; - printk(" <"); /* prevent someone doing mkfs or mkswap on an extended partition, but leave room for LILO */ - if (size > 2) - hd->part[minor].nr_sects = 2; - extended_partition(hd, bdev, minor, size, ¤t_minor); + put_partition(state, slot, start, size == 1 ? 1 : 2); + printk(" <"); + parse_extended(state, bdev, start, size); printk(" >"); + continue; } + put_partition(state, slot, start, size); + if (SYS_IND(p) == LINUX_RAID_PARTITION) + state->parts[slot].flags = 1; } /* @@ -584,21 +528,21 @@ int msdos_partition(struct gendisk *hd, struct block_device *bdev, */ if (msdos_magic_present(data + 0xfc)) { p = (struct partition *) (0x1be + data); - for (i = 4 ; i < 16 ; i++, current_minor++) { + for (slot = 4 ; slot < 16 ; slot++, state->next++) { p--; - if ((current_minor & mask) == 0) + if (state->next == state->limit) break; if (!(START_SECT(p) && NR_SECTS(p))) continue; - add_gd_partition(hd, current_minor, START_SECT(p), NR_SECTS(p)); + put_partition(state, state->next, + START_SECT(p), NR_SECTS(p)); } } printk("\n"); /* second pass - output for each on a separate line */ - minor -= 4; p = (struct partition *) (0x1be + data); - for (i=1 ; i<=4 ; minor++,i++,p++) { + for (slot = 1 ; slot <= 4 ; slot++, p++) { unsigned char id = SYS_IND(p); int n; @@ -608,8 +552,10 @@ int msdos_partition(struct gendisk *hd, struct block_device *bdev, for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++) ; - if (subtypes[n].parse) - subtypes[n].parse(hd, bdev, minor, ¤t_minor); + if (!subtypes[n].parse) + continue; + subtypes[n].parse(state, bdev, START_SECT(p)*sector_size, + NR_SECTS(p)*sector_size, n); } put_dev_sector(sect); return 1; diff --git a/fs/partitions/msdos.h b/fs/partitions/msdos.h index 09c8b095ad56..01e5e0b6902d 100644 --- a/fs/partitions/msdos.h +++ b/fs/partitions/msdos.h @@ -4,6 +4,5 @@ #define MSDOS_LABEL_MAGIC 0xAA55 -int msdos_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor); +int msdos_partition(struct parsed_partitions *state, struct block_device *bdev); diff --git a/fs/partitions/osf.c b/fs/partitions/osf.c index e178ca2b6543..6be3fff325cf 100644 --- a/fs/partitions/osf.c +++ b/fs/partitions/osf.c @@ -7,23 +7,15 @@ * Re-organised Feb 1998 Russell King */ -#include <linux/fs.h> -#include <linux/genhd.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/blk.h> - #include "check.h" #include "osf.h" -int osf_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int current_minor) +int osf_partition(struct parsed_partitions *state, struct block_device *bdev) { int i; + int slot = 1; Sector sect; unsigned char *data; - int mask = (1 << hd->minor_shift) - 1; struct disklabel { u32 d_magic; u16 d_type,d_subtype; @@ -72,16 +64,14 @@ int osf_partition(struct gendisk *hd, struct block_device *bdev, return 0; } for (i = 0 ; i < le16_to_cpu(label->d_npartitions); i++, partition++) { - if ((current_minor & mask) == 0) + if (slot == state->limit) break; if (le32_to_cpu(partition->p_size)) - add_gd_partition(hd, current_minor, - first_sector+le32_to_cpu(partition->p_offset), + put_partition(state, slot++, + le32_to_cpu(partition->p_offset), le32_to_cpu(partition->p_size)); - current_minor++; } printk("\n"); put_dev_sector(sect); return 1; } - diff --git a/fs/partitions/osf.h b/fs/partitions/osf.h index 6f02393c490b..427b8eab314b 100644 --- a/fs/partitions/osf.h +++ b/fs/partitions/osf.h @@ -4,6 +4,4 @@ #define DISKLABELMAGIC (0x82564557UL) -int osf_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int current_minor); - +int osf_partition(struct parsed_partitions *state, struct block_device *bdev); diff --git a/fs/partitions/sgi.c b/fs/partitions/sgi.c index 5051e3d28ab4..ed8439bb5c4d 100644 --- a/fs/partitions/sgi.c +++ b/fs/partitions/sgi.c @@ -4,22 +4,13 @@ * Code extracted from drivers/block/genhd.c */ -#include <linux/fs.h> -#include <linux/genhd.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/blk.h> - -#include <asm/byteorder.h> -#include <asm/system.h> - #include "check.h" #include "sgi.h" -int sgi_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int current_minor) +int sgi_partition(struct parsed_partitions *state, struct block_device *bdev) { int i, csum, magic; + int slot = 1; unsigned int *ui, start, blocks, cs; Sector sect; struct sgi_disklabel { @@ -73,10 +64,8 @@ int sgi_partition(struct gendisk *hd, struct block_device *bdev, unsigned long f for(i = 0; i < 16; i++, p++) { blocks = be32_to_cpu(p->num_blocks); start = be32_to_cpu(p->first_block); - if(!blocks) - continue; - add_gd_partition(hd, current_minor, start, blocks); - current_minor++; + if (blocks) + put_partition(state, slot++, start, blocks); } printk("\n"); put_dev_sector(sect); diff --git a/fs/partitions/sgi.h b/fs/partitions/sgi.h index 55840d9285e5..5d5595c09928 100644 --- a/fs/partitions/sgi.h +++ b/fs/partitions/sgi.h @@ -2,8 +2,7 @@ * fs/partitions/sgi.h */ -extern int sgi_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor); +extern int sgi_partition(struct parsed_partitions *state, struct block_device *bdev); #define SGI_LABEL_MAGIC 0x0be5a941 diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c index a19f89dfd2e1..c56ef567c381 100644 --- a/fs/partitions/sun.c +++ b/fs/partitions/sun.c @@ -7,21 +7,13 @@ * Re-organised Feb 1998 Russell King */ -#include <linux/fs.h> -#include <linux/genhd.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/string.h> -#include <linux/blk.h> - -#include <asm/system.h> - #include "check.h" #include "sun.h" -int sun_partition(struct gendisk *hd, struct block_device *bdev, unsigned long first_sector, int first_part_minor) +int sun_partition(struct parsed_partitions *state, struct block_device *bdev) { int i, csum; + int slot = 1; unsigned short *ush; Sector sect; struct sun_disklabel { @@ -74,11 +66,10 @@ int sun_partition(struct gendisk *hd, struct block_device *bdev, unsigned long f unsigned long st_sector; int num_sectors; - st_sector = first_sector + be32_to_cpu(p->start_cylinder) * spc; + st_sector = be32_to_cpu(p->start_cylinder) * spc; num_sectors = be32_to_cpu(p->num_sectors); if (num_sectors) - add_gd_partition(hd, first_part_minor, st_sector, num_sectors); - first_part_minor++; + put_partition(state, slot++, st_sector, num_sectors); } printk("\n"); put_dev_sector(sect); diff --git a/fs/partitions/sun.h b/fs/partitions/sun.h index ae2f9579ef87..b1b19fda7b22 100644 --- a/fs/partitions/sun.h +++ b/fs/partitions/sun.h @@ -4,6 +4,4 @@ #define SUN_LABEL_MAGIC 0xDABE -int sun_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor); - +int sun_partition(struct parsed_partitions *state, struct block_device *bdev); diff --git a/fs/partitions/ultrix.c b/fs/partitions/ultrix.c index a7e0629dd2da..8a8d4d9db314 100644 --- a/fs/partitions/ultrix.c +++ b/fs/partitions/ultrix.c @@ -6,16 +6,9 @@ * Re-organised Jul 1999 Russell King */ -#include <linux/fs.h> -#include <linux/genhd.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/blk.h> - #include "check.h" -int ultrix_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor) +int ultrix_partition(struct parsed_partitions *state, struct block_device *bdev) { int i; Sector sect; @@ -39,9 +32,9 @@ int ultrix_partition(struct gendisk *hd, struct block_device *bdev, label = (struct ultrix_disklabel *)(data + 512 - sizeof(*label)); if (label->pt_magic == PT_MAGIC && label->pt_valid == PT_VALID) { - for (i=0; i<8; i++, first_part_minor++) + for (i=0; i<8; i++) if (label->pt_part[i].pi_nblocks) - add_gd_partition(hd, first_part_minor, + put_partition(state, i+1, label->pt_part[i].pi_blkoff, label->pt_part[i].pi_nblocks); put_dev_sector(sect); diff --git a/fs/partitions/ultrix.h b/fs/partitions/ultrix.h index 1572c90d90be..a74bf8e2d370 100644 --- a/fs/partitions/ultrix.h +++ b/fs/partitions/ultrix.h @@ -2,6 +2,4 @@ * fs/partitions/ultrix.h */ -int ultrix_partition(struct gendisk *hd, struct block_device *bdev, - unsigned long first_sector, int first_part_minor); - +int ultrix_partition(struct parsed_partitions *state, struct block_device *bdev); diff --git a/include/asm-alpha/io.h b/include/asm-alpha/io.h index 594292133373..eb6ef31bf932 100644 --- a/include/asm-alpha/io.h +++ b/include/asm-alpha/io.h @@ -31,7 +31,7 @@ static inline void __set_hae(unsigned long new_hae) { unsigned long flags; - __save_and_cli(flags); + local_irq_save(flags); alpha_mv.hae_cache = new_hae; *alpha_mv.hae_register = new_hae; @@ -39,7 +39,7 @@ static inline void __set_hae(unsigned long new_hae) /* Re-read to make sure it was written. */ new_hae = *alpha_mv.hae_register; - __restore_flags(flags); + local_irq_restore(flags); } static inline void set_hae(unsigned long new_hae) diff --git a/include/asm-alpha/smplock.h b/include/asm-alpha/smplock.h index 911a06573a8e..b757693c0688 100644 --- a/include/asm-alpha/smplock.h +++ b/include/asm-alpha/smplock.h @@ -20,7 +20,7 @@ static __inline__ void release_kernel_lock(struct task_struct *task, int cpu) if (task->lock_depth >= 0) spin_unlock(&kernel_flag); release_irqlock(cpu); - __sti(); + local_irq_enable(); } /* diff --git a/include/asm-alpha/system.h b/include/asm-alpha/system.h index fb7496fce46f..db3f889b2463 100644 --- a/include/asm-alpha/system.h +++ b/include/asm-alpha/system.h @@ -303,16 +303,11 @@ extern int __min_ipl; #define getipl() (rdps() & 7) #define setipl(ipl) ((void) swpipl(ipl)) -#define __cli() do { setipl(IPL_MAX); barrier(); } while(0) -#define __sti() do { barrier(); setipl(IPL_MIN); } while(0) -#define __save_flags(flags) ((flags) = rdps()) -#define __save_and_cli(flags) do { (flags) = swpipl(IPL_MAX); barrier(); } while(0) -#define __restore_flags(flags) do { barrier(); setipl(flags); barrier(); } while(0) - -#define local_irq_save(flags) __save_and_cli(flags) -#define local_irq_restore(flags) __restore_flags(flags) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() +#define local_irq_disable() do { setipl(IPL_MAX); barrier(); } while(0) +#define local_irq_enable() do { barrier(); setipl(IPL_MIN); } while(0) +#define local_save_flags(flags) ((flags) = rdps()) +#define local_irq_save(flags) do { (flags) = swpipl(IPL_MAX); barrier(); } while(0) +#define local_irq_restore(flags) do { barrier(); setipl(flags); barrier(); } while(0) #ifdef CONFIG_SMP @@ -332,11 +327,11 @@ extern void __global_restore_flags(unsigned long flags); #else /* CONFIG_SMP */ -#define cli() __cli() -#define sti() __sti() -#define save_flags(flags) __save_flags(flags) -#define save_and_cli(flags) __save_and_cli(flags) -#define restore_flags(flags) __restore_flags(flags) +#define cli() local_irq_disable() +#define sti() local_irq_enable() +#define save_flags(flags) local_save_flags(flags) +#define save_and_cli(flags) local_irq_save(flags) +#define restore_flags(flags) local_irq_restore(flags) #endif /* CONFIG_SMP */ diff --git a/include/asm-arm/atomic.h b/include/asm-arm/atomic.h index 1930c34e48a3..d1b48d65ff23 100644 --- a/include/asm-arm/atomic.h +++ b/include/asm-arm/atomic.h @@ -36,36 +36,36 @@ static inline void atomic_add(int i, volatile atomic_t *v) { unsigned long flags; - __save_flags_cli(flags); + local_save_flags_cli(flags); v->counter += i; - __restore_flags(flags); + local_irq_restore(flags); } static inline void atomic_sub(int i, volatile atomic_t *v) { unsigned long flags; - __save_flags_cli(flags); + local_save_flags_cli(flags); v->counter -= i; - __restore_flags(flags); + local_irq_restore(flags); } static inline void atomic_inc(volatile atomic_t *v) { unsigned long flags; - __save_flags_cli(flags); + local_save_flags_cli(flags); v->counter += 1; - __restore_flags(flags); + local_irq_restore(flags); } static inline void atomic_dec(volatile atomic_t *v) { unsigned long flags; - __save_flags_cli(flags); + local_save_flags_cli(flags); v->counter -= 1; - __restore_flags(flags); + local_irq_restore(flags); } static inline int atomic_dec_and_test(volatile atomic_t *v) @@ -73,10 +73,10 @@ static inline int atomic_dec_and_test(volatile atomic_t *v) unsigned long flags; int val; - __save_flags_cli(flags); + local_save_flags_cli(flags); val = v->counter; v->counter = val -= 1; - __restore_flags(flags); + local_irq_restore(flags); return val == 0; } @@ -86,10 +86,10 @@ static inline int atomic_add_negative(int i, volatile atomic_t *v) unsigned long flags; int val; - __save_flags_cli(flags); + local_save_flags_cli(flags); val = v->counter; v->counter = val += i; - __restore_flags(flags); + local_irq_restore(flags); return val < 0; } @@ -98,9 +98,9 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) { unsigned long flags; - __save_flags_cli(flags); + local_save_flags_cli(flags); *addr &= ~mask; - __restore_flags(flags); + local_irq_restore(flags); } /* Atomic operations are already serializing on ARM */ diff --git a/include/asm-arm/proc-armo/system.h b/include/asm-arm/proc-armo/system.h index fccc6bbff83f..23f2b96cb2d0 100644 --- a/include/asm-arm/proc-armo/system.h +++ b/include/asm-arm/proc-armo/system.h @@ -39,7 +39,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size /* * Save the current interrupt enable state & disable IRQs */ -#define __save_flags_cli(x) \ +#define local_save_flags_cli(x) \ do { \ unsigned long temp; \ __asm__ __volatile__( \ @@ -55,7 +55,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size /* * Enable IRQs */ -#define __sti() \ +#define local_irq_enable() \ do { \ unsigned long temp; \ __asm__ __volatile__( \ @@ -70,7 +70,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size /* * Disable IRQs */ -#define __cli() \ +#define local_irq_disable() \ do { \ unsigned long temp; \ __asm__ __volatile__( \ @@ -103,7 +103,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size /* * save current IRQ & FIQ state */ -#define __save_flags(x) \ +#define local_save_flags(x) \ do { \ __asm__ __volatile__( \ " mov %0, pc @ save_flags\n" \ @@ -114,7 +114,7 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size /* * restore saved IRQ & FIQ state */ -#define __restore_flags(x) \ +#define local_irq_restore(x) \ do { \ unsigned long temp; \ __asm__ __volatile__( \ diff --git a/include/asm-arm/proc-armv/system.h b/include/asm-arm/proc-armv/system.h index 229513280b5a..d9647dc39f6a 100644 --- a/include/asm-arm/proc-armv/system.h +++ b/include/asm-arm/proc-armv/system.h @@ -49,7 +49,7 @@ extern unsigned long cr_alignment; /* defined in entry-armv.S */ /* * Save the current interrupt enable state & disable IRQs */ -#define __save_flags_cli(x) \ +#define local_save_flags_cli(x) \ ({ \ unsigned long temp; \ __asm__ __volatile__( \ @@ -64,7 +64,7 @@ extern unsigned long cr_alignment; /* defined in entry-armv.S */ /* * Enable IRQs */ -#define __sti() \ +#define local_irq_enable() \ ({ \ unsigned long temp; \ __asm__ __volatile__( \ @@ -79,7 +79,7 @@ extern unsigned long cr_alignment; /* defined in entry-armv.S */ /* * Disable IRQs */ -#define __cli() \ +#define local_irq_disable() \ ({ \ unsigned long temp; \ __asm__ __volatile__( \ @@ -124,7 +124,7 @@ extern unsigned long cr_alignment; /* defined in entry-armv.S */ /* * save current IRQ & FIQ state */ -#define __save_flags(x) \ +#define local_save_flags(x) \ __asm__ __volatile__( \ "mrs %0, cpsr @ save_flags\n" \ : "=r" (x) \ @@ -134,7 +134,7 @@ extern unsigned long cr_alignment; /* defined in entry-armv.S */ /* * restore saved IRQ & FIQ state */ -#define __restore_flags(x) \ +#define local_irq_restore(x) \ __asm__ __volatile__( \ "msr cpsr_c, %0 @ restore_flags\n" \ : \ @@ -168,17 +168,17 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size switch (size) { #ifdef swp_is_buggy case 1: - __save_flags_cli(flags); + local_save_flags_cli(flags); ret = *(volatile unsigned char *)ptr; *(volatile unsigned char *)ptr = x; - __restore_flags(flags); + local_irq_restore(flags); break; case 4: - __save_flags_cli(flags); + local_save_flags_cli(flags); ret = *(volatile unsigned long *)ptr; *(volatile unsigned long *)ptr = x; - __restore_flags(flags); + local_irq_restore(flags); break; #else case 1: __asm__ __volatile__ ("swpb %0, %1, [%2]" diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h index d35f8d91c25f..f110ae2eb76b 100644 --- a/include/asm-arm/system.h +++ b/include/asm-arm/system.h @@ -76,10 +76,7 @@ extern struct task_struct *__switch_to(struct thread_info *, struct thread_info } while (0) /* For spinlocks etc */ -#define local_irq_save(x) __save_flags_cli(x) -#define local_irq_restore(x) __restore_flags(x) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() +#define local_irq_save(x) local_save_flags_cli(x) #ifdef CONFIG_SMP #error SMP not supported @@ -94,12 +91,12 @@ extern struct task_struct *__switch_to(struct thread_info *, struct thread_info #define smp_rmb() barrier() #define smp_wmb() barrier() -#define cli() __cli() -#define sti() __sti() +#define cli() local_irq_disable() +#define sti() local_irq_enable() #define clf() __clf() #define stf() __stf() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) +#define save_flags(x) local_save_flags(x) +#define restore_flags(x) local_irq_restore(x) #endif /* CONFIG_SMP */ diff --git a/include/asm-cris/softirq.h b/include/asm-cris/softirq.h index eb6e178c64e3..c5b2d8873f9a 100644 --- a/include/asm-cris/softirq.h +++ b/include/asm-cris/softirq.h @@ -21,7 +21,7 @@ do { \ if (!--local_bh_count(smp_processor_id()) \ && softirq_pending(smp_processor_id())) { \ do_softirq(); \ - __sti(); \ + local_irq_enable(); \ } \ } while (0) diff --git a/include/asm-cris/sv_addr.agh b/include/asm-cris/sv_addr.agh index c9c6141eb569..ddaf91fa38cf 100644 --- a/include/asm-cris/sv_addr.agh +++ b/include/asm-cris/sv_addr.agh @@ -1142,7 +1142,7 @@ #define R_SERIAL0_CTRL__rec_stick_par__BITNR 19 #define R_SERIAL0_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL0_CTRL__rec_stick_par__normal 0 -#define R_SERIAL0_CTRL__rec_stick_par__stick 1 +#define R_SERIAL0_CTRL__rec_stick_parlocal_irq_enableck 1 #define R_SERIAL0_CTRL__rec_par__BITNR 18 #define R_SERIAL0_CTRL__rec_par__WIDTH 1 #define R_SERIAL0_CTRL__rec_par__even 0 @@ -1172,7 +1172,7 @@ #define R_SERIAL0_CTRL__tr_stick_par__BITNR 11 #define R_SERIAL0_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL0_CTRL__tr_stick_par__normal 0 -#define R_SERIAL0_CTRL__tr_stick_par__stick 1 +#define R_SERIAL0_CTRL__tr_stick_parlocal_irq_enableck 1 #define R_SERIAL0_CTRL__tr_par__BITNR 10 #define R_SERIAL0_CTRL__tr_par__WIDTH 1 #define R_SERIAL0_CTRL__tr_par__even 0 @@ -1246,7 +1246,7 @@ #define R_SERIAL0_REC_CTRL__rec_stick_par__BITNR 3 #define R_SERIAL0_REC_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL0_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL0_REC_CTRL__rec_stick_par__stick 1 +#define R_SERIAL0_REC_CTRL__rec_stick_parlocal_irq_enableck 1 #define R_SERIAL0_REC_CTRL__rec_par__BITNR 2 #define R_SERIAL0_REC_CTRL__rec_par__WIDTH 1 #define R_SERIAL0_REC_CTRL__rec_par__even 0 @@ -1278,7 +1278,7 @@ #define R_SERIAL0_TR_CTRL__tr_stick_par__BITNR 3 #define R_SERIAL0_TR_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL0_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL0_TR_CTRL__tr_stick_par__stick 1 +#define R_SERIAL0_TR_CTRL__tr_stick_parlocal_irq_enableck 1 #define R_SERIAL0_TR_CTRL__tr_par__BITNR 2 #define R_SERIAL0_TR_CTRL__tr_par__WIDTH 1 #define R_SERIAL0_TR_CTRL__tr_par__even 0 @@ -1434,7 +1434,7 @@ #define R_SERIAL1_CTRL__rec_stick_par__BITNR 19 #define R_SERIAL1_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL1_CTRL__rec_stick_par__normal 0 -#define R_SERIAL1_CTRL__rec_stick_par__stick 1 +#define R_SERIAL1_CTRL__rec_stick_parlocal_irq_enableck 1 #define R_SERIAL1_CTRL__rec_par__BITNR 18 #define R_SERIAL1_CTRL__rec_par__WIDTH 1 #define R_SERIAL1_CTRL__rec_par__even 0 @@ -1464,7 +1464,7 @@ #define R_SERIAL1_CTRL__tr_stick_par__BITNR 11 #define R_SERIAL1_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL1_CTRL__tr_stick_par__normal 0 -#define R_SERIAL1_CTRL__tr_stick_par__stick 1 +#define R_SERIAL1_CTRL__tr_stick_parlocal_irq_enableck 1 #define R_SERIAL1_CTRL__tr_par__BITNR 10 #define R_SERIAL1_CTRL__tr_par__WIDTH 1 #define R_SERIAL1_CTRL__tr_par__even 0 @@ -1538,7 +1538,7 @@ #define R_SERIAL1_REC_CTRL__rec_stick_par__BITNR 3 #define R_SERIAL1_REC_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL1_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL1_REC_CTRL__rec_stick_par__stick 1 +#define R_SERIAL1_REC_CTRL__rec_stick_parlocal_irq_enableck 1 #define R_SERIAL1_REC_CTRL__rec_par__BITNR 2 #define R_SERIAL1_REC_CTRL__rec_par__WIDTH 1 #define R_SERIAL1_REC_CTRL__rec_par__even 0 @@ -1570,7 +1570,7 @@ #define R_SERIAL1_TR_CTRL__tr_stick_par__BITNR 3 #define R_SERIAL1_TR_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL1_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL1_TR_CTRL__tr_stick_par__stick 1 +#define R_SERIAL1_TR_CTRL__tr_stick_parlocal_irq_enableck 1 #define R_SERIAL1_TR_CTRL__tr_par__BITNR 2 #define R_SERIAL1_TR_CTRL__tr_par__WIDTH 1 #define R_SERIAL1_TR_CTRL__tr_par__even 0 @@ -1726,7 +1726,7 @@ #define R_SERIAL2_CTRL__rec_stick_par__BITNR 19 #define R_SERIAL2_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL2_CTRL__rec_stick_par__normal 0 -#define R_SERIAL2_CTRL__rec_stick_par__stick 1 +#define R_SERIAL2_CTRL__rec_stick_parlocal_irq_enableck 1 #define R_SERIAL2_CTRL__rec_par__BITNR 18 #define R_SERIAL2_CTRL__rec_par__WIDTH 1 #define R_SERIAL2_CTRL__rec_par__even 0 @@ -1756,7 +1756,7 @@ #define R_SERIAL2_CTRL__tr_stick_par__BITNR 11 #define R_SERIAL2_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL2_CTRL__tr_stick_par__normal 0 -#define R_SERIAL2_CTRL__tr_stick_par__stick 1 +#define R_SERIAL2_CTRL__tr_stick_parlocal_irq_enableck 1 #define R_SERIAL2_CTRL__tr_par__BITNR 10 #define R_SERIAL2_CTRL__tr_par__WIDTH 1 #define R_SERIAL2_CTRL__tr_par__even 0 @@ -1830,7 +1830,7 @@ #define R_SERIAL2_REC_CTRL__rec_stick_par__BITNR 3 #define R_SERIAL2_REC_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL2_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL2_REC_CTRL__rec_stick_par__stick 1 +#define R_SERIAL2_REC_CTRL__rec_stick_parlocal_irq_enableck 1 #define R_SERIAL2_REC_CTRL__rec_par__BITNR 2 #define R_SERIAL2_REC_CTRL__rec_par__WIDTH 1 #define R_SERIAL2_REC_CTRL__rec_par__even 0 @@ -1862,7 +1862,7 @@ #define R_SERIAL2_TR_CTRL__tr_stick_par__BITNR 3 #define R_SERIAL2_TR_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL2_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL2_TR_CTRL__tr_stick_par__stick 1 +#define R_SERIAL2_TR_CTRL__tr_stick_parlocal_irq_enableck 1 #define R_SERIAL2_TR_CTRL__tr_par__BITNR 2 #define R_SERIAL2_TR_CTRL__tr_par__WIDTH 1 #define R_SERIAL2_TR_CTRL__tr_par__even 0 @@ -2018,7 +2018,7 @@ #define R_SERIAL3_CTRL__rec_stick_par__BITNR 19 #define R_SERIAL3_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL3_CTRL__rec_stick_par__normal 0 -#define R_SERIAL3_CTRL__rec_stick_par__stick 1 +#define R_SERIAL3_CTRL__rec_stick_parlocal_irq_enableck 1 #define R_SERIAL3_CTRL__rec_par__BITNR 18 #define R_SERIAL3_CTRL__rec_par__WIDTH 1 #define R_SERIAL3_CTRL__rec_par__even 0 @@ -2048,7 +2048,7 @@ #define R_SERIAL3_CTRL__tr_stick_par__BITNR 11 #define R_SERIAL3_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL3_CTRL__tr_stick_par__normal 0 -#define R_SERIAL3_CTRL__tr_stick_par__stick 1 +#define R_SERIAL3_CTRL__tr_stick_parlocal_irq_enableck 1 #define R_SERIAL3_CTRL__tr_par__BITNR 10 #define R_SERIAL3_CTRL__tr_par__WIDTH 1 #define R_SERIAL3_CTRL__tr_par__even 0 @@ -2122,7 +2122,7 @@ #define R_SERIAL3_REC_CTRL__rec_stick_par__BITNR 3 #define R_SERIAL3_REC_CTRL__rec_stick_par__WIDTH 1 #define R_SERIAL3_REC_CTRL__rec_stick_par__normal 0 -#define R_SERIAL3_REC_CTRL__rec_stick_par__stick 1 +#define R_SERIAL3_REC_CTRL__rec_stick_parlocal_irq_enableck 1 #define R_SERIAL3_REC_CTRL__rec_par__BITNR 2 #define R_SERIAL3_REC_CTRL__rec_par__WIDTH 1 #define R_SERIAL3_REC_CTRL__rec_par__even 0 @@ -2154,7 +2154,7 @@ #define R_SERIAL3_TR_CTRL__tr_stick_par__BITNR 3 #define R_SERIAL3_TR_CTRL__tr_stick_par__WIDTH 1 #define R_SERIAL3_TR_CTRL__tr_stick_par__normal 0 -#define R_SERIAL3_TR_CTRL__tr_stick_par__stick 1 +#define R_SERIAL3_TR_CTRL__tr_stick_parlocal_irq_enableck 1 #define R_SERIAL3_TR_CTRL__tr_par__BITNR 2 #define R_SERIAL3_TR_CTRL__tr_par__WIDTH 1 #define R_SERIAL3_TR_CTRL__tr_par__even 0 diff --git a/include/asm-cris/system.h b/include/asm-cris/system.h index 0674811a31c5..240f36fc57a4 100644 --- a/include/asm-cris/system.h +++ b/include/asm-cris/system.h @@ -62,10 +62,10 @@ struct __xchg_dummy { unsigned long a[100]; }; #define save_flags(x) __asm__ __volatile__ ("move $ccr,%0" : "=rm" (x) : : "memory"); #define restore_flags(x) __asm__ __volatile__ ("move %0,$ccr\n\tbtstq 5,%0\n\tbpl 1f\n\tnop\n\tpush $r0\n\tmoveq 0,$r0\n\tmove.d $r0,[0x90000000]\n\tpop $r0\n1:\n" : : "r" (x) : "memory"); #else -#define __cli() __asm__ __volatile__ ( "di"); -#define __sti() __asm__ __volatile__ ( "ei" ); -#define __save_flags(x) __asm__ __volatile__ ("move $ccr,%0" : "=rm" (x) : : "memory"); -#define __restore_flags(x) __asm__ __volatile__ ("move %0,$ccr" : : "rm" (x) : "memory"); +#define local_irq_disable() __asm__ __volatile__ ( "di"); +#define local_irq_enable() __asm__ __volatile__ ( "ei" ); +#define local_save_flags(x) __asm__ __volatile__ ("move $ccr,%0" : "=rm" (x) : : "memory"); +#define local_irq_restore(x) __asm__ __volatile__ ("move %0,$ccr" : : "rm" (x) : "memory"); /* For spinlocks etc */ #define local_irq_save(x) __asm__ __volatile__ ("move $ccr,%0\n\tdi" : "=rm" (x) : : "memory"); @@ -76,11 +76,11 @@ struct __xchg_dummy { unsigned long a[100]; }; #endif -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) -#define save_and_cli(x) do { __save_flags(x); cli(); } while(0) +#define cli() local_irq_disable() +#define sti() local_irq_enable() +#define save_flags(x) local_save_flags(x) +#define restore_flags(x) local_irq_restore(x) +#define save_and_cli(x) do { local_save_flags(x); cli(); } while(0) static inline unsigned long __xchg(unsigned long x, void * ptr, int size) { diff --git a/include/asm-generic/smplock.h b/include/asm-generic/smplock.h index 96565069c988..f02afc9ffd6e 100644 --- a/include/asm-generic/smplock.h +++ b/include/asm-generic/smplock.h @@ -13,12 +13,11 @@ extern spinlock_t kernel_flag; /* * Release global kernel lock and global interrupt lock */ -#define release_kernel_lock(task, cpu) \ +#define release_kernel_lock(task) \ do { \ if (task->lock_depth >= 0) \ spin_unlock(&kernel_flag); \ - release_irqlock(cpu); \ - __sti(); \ + local_irq_enable(); \ } while (0) /* diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h index 084e6baf9b95..cdb2f1ecfc01 100644 --- a/include/asm-i386/acpi.h +++ b/include/asm-i386/acpi.h @@ -48,8 +48,8 @@ #define ACPI_ASM_MACROS #define BREAKPOINT3 -#define ACPI_DISABLE_IRQS() __cli() -#define ACPI_ENABLE_IRQS() __sti() +#define ACPI_DISABLE_IRQS() local_irq_disable() +#define ACPI_ENABLE_IRQS() local_irq_enable() #define ACPI_FLUSH_CPU_CACHE() wbinvd() /* diff --git a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h index ed73b0444f6b..cbd78d1dcaa1 100644 --- a/include/asm-i386/hardirq.h +++ b/include/asm-i386/hardirq.h @@ -8,8 +8,6 @@ /* assembly code in softirq.h is sensitive to the offsets of these fields */ typedef struct { unsigned int __softirq_pending; - unsigned int __local_irq_count; - unsigned int __local_bh_count; unsigned int __syscall_count; struct task_struct * __ksoftirqd_task; /* waitqueue is too large */ unsigned long idle_timestamp; @@ -18,77 +16,27 @@ typedef struct { #include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ +#define IRQ_OFFSET 64 + /* * Are we in an interrupt context? Either doing bottom half * or hardware interrupt processing? */ -#define in_interrupt() ({ int __cpu = smp_processor_id(); \ - (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); }) - -#define in_irq() (local_irq_count(smp_processor_id()) != 0) - -#ifndef CONFIG_SMP - -#define hardirq_trylock(cpu) (local_irq_count(cpu) == 0) -#define hardirq_endlock(cpu) do { } while (0) +#define in_interrupt() \ + ((preempt_count() & ~PREEMPT_ACTIVE) >= IRQ_OFFSET) -#define irq_enter(cpu, irq) (local_irq_count(cpu)++) -#define irq_exit(cpu, irq) (local_irq_count(cpu)--) +#define in_irq in_interrupt -#define synchronize_irq() barrier() +#define hardirq_trylock() (!in_interrupt()) +#define hardirq_endlock() do { } while (0) -#define release_irqlock(cpu) do { } while (0) +#define irq_enter() (preempt_count() += IRQ_OFFSET) +#define irq_exit() (preempt_count() -= IRQ_OFFSET) +#ifndef CONFIG_SMP +# define synchronize_irq(irq) barrier() #else - -#include <asm/atomic.h> -#include <asm/smp.h> - -extern unsigned char global_irq_holder; -extern unsigned volatile long global_irq_lock; /* long for set_bit -RR */ - -static inline int irqs_running (void) -{ - int i; - - for (i = 0; i < NR_CPUS; i++) - if (local_irq_count(i)) - return 1; - return 0; -} - -static inline void release_irqlock(int cpu) -{ - /* if we didn't own the irq lock, just ignore.. */ - if (global_irq_holder == (unsigned char) cpu) { - global_irq_holder = NO_PROC_ID; - clear_bit(0,&global_irq_lock); - } -} - -static inline void irq_enter(int cpu, int irq) -{ - ++local_irq_count(cpu); - - while (test_bit(0,&global_irq_lock)) { - cpu_relax(); - } -} - -static inline void irq_exit(int cpu, int irq) -{ - --local_irq_count(cpu); -} - -static inline int hardirq_trylock(int cpu) -{ - return !local_irq_count(cpu) && !test_bit(0,&global_irq_lock); -} - -#define hardirq_endlock(cpu) do { } while (0) - -extern void synchronize_irq(void); - + extern void synchronize_irq(unsigned int irq); #endif /* CONFIG_SMP */ #endif /* __ASM_HARDIRQ_H */ diff --git a/include/asm-i386/smplock.h b/include/asm-i386/smplock.h index 888a7b82f103..8bee3fd434c0 100644 --- a/include/asm-i386/smplock.h +++ b/include/asm-i386/smplock.h @@ -12,15 +12,9 @@ extern spinlock_t kernel_flag; #ifdef CONFIG_SMP #define kernel_locked() spin_is_locked(&kernel_flag) -#define check_irq_holder(cpu) \ -do { \ - if (global_irq_holder == (cpu)) \ - BUG(); \ -} while(0) #else #ifdef CONFIG_PREEMPT -#define kernel_locked() preempt_get_count() -#define check_irq_holder(cpu) do { } while(0) +#define kernel_locked() preempt_count() #else #define kernel_locked() 1 #endif @@ -29,12 +23,10 @@ do { \ /* * Release global kernel lock and global interrupt lock */ -#define release_kernel_lock(task, cpu) \ +#define release_kernel_lock(task) \ do { \ - if (unlikely(task->lock_depth >= 0)) { \ + if (unlikely(task->lock_depth >= 0)) \ spin_unlock(&kernel_flag); \ - check_irq_holder(cpu); \ - } \ } while (0) /* diff --git a/include/asm-i386/softirq.h b/include/asm-i386/softirq.h index c62cbece6ce7..c28019d821af 100644 --- a/include/asm-i386/softirq.h +++ b/include/asm-i386/softirq.h @@ -1,50 +1,27 @@ #ifndef __ASM_SOFTIRQ_H #define __ASM_SOFTIRQ_H -#include <asm/atomic.h> +#include <linux/preempt.h> #include <asm/hardirq.h> -#define __cpu_bh_enable(cpu) \ - do { barrier(); local_bh_count(cpu)--; preempt_enable(); } while (0) -#define cpu_bh_disable(cpu) \ - do { preempt_disable(); local_bh_count(cpu)++; barrier(); } while (0) +#define local_bh_disable() \ + do { preempt_count() += IRQ_OFFSET; barrier(); } while (0) +#define __local_bh_enable() \ + do { barrier(); preempt_count() -= IRQ_OFFSET; } while (0) -#define local_bh_disable() cpu_bh_disable(smp_processor_id()) -#define __local_bh_enable() __cpu_bh_enable(smp_processor_id()) - -#define in_softirq() (local_bh_count(smp_processor_id()) != 0) - -/* - * NOTE: this assembly code assumes: - * - * (char *)&local_bh_count - 8 == (char *)&softirq_pending - * - * If you change the offsets in irq_stat then you have to - * update this code as well. - */ -#define _local_bh_enable() \ +#define local_bh_enable() \ do { \ - unsigned int *ptr = &local_bh_count(smp_processor_id()); \ - \ - barrier(); \ - if (!--*ptr) \ - __asm__ __volatile__ ( \ - "cmpl $0, -8(%0);" \ - "jnz 2f;" \ - "1:;" \ - \ - LOCK_SECTION_START("") \ - "2: pushl %%eax; pushl %%ecx; pushl %%edx;" \ - "call %c1;" \ - "popl %%edx; popl %%ecx; popl %%eax;" \ - "jmp 1b;" \ - LOCK_SECTION_END \ - \ - : /* no output */ \ - : "r" (ptr), "i" (do_softirq) \ - /* no registers clobbered */ ); \ + if (unlikely((preempt_count() == IRQ_OFFSET) && \ + softirq_pending(smp_processor_id()))) { \ + __local_bh_enable(); \ + do_softirq(); \ + preempt_check_resched(); \ + } else { \ + __local_bh_enable(); \ + preempt_check_resched(); \ + } \ } while (0) -#define local_bh_enable() do { _local_bh_enable(); preempt_enable(); } while (0) +#define in_softirq() in_interrupt() #endif /* __ASM_SOFTIRQ_H */ diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h index 851f090e4394..d10a76223841 100644 --- a/include/asm-i386/system.h +++ b/include/asm-i386/system.h @@ -311,37 +311,24 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, #define set_wmb(var, value) do { var = value; wmb(); } while (0) /* interrupt control.. */ -#define __save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */) -#define __restore_flags(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc") -#define __cli() __asm__ __volatile__("cli": : :"memory") -#define __sti() __asm__ __volatile__("sti": : :"memory") +#define local_save_flags(x) __asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */) +#define local_irq_restore(x) __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc") +#define local_irq_disable() __asm__ __volatile__("cli": : :"memory") +#define local_irq_enable() __asm__ __volatile__("sti": : :"memory") /* used in the idle loop; sti takes one instruction cycle to complete */ #define safe_halt() __asm__ __volatile__("sti; hlt": : :"memory") /* For spinlocks etc */ #define local_irq_save(x) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory") -#define local_irq_restore(x) __restore_flags(x) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() - -#ifdef CONFIG_SMP - -extern void __global_cli(void); -extern void __global_sti(void); -extern unsigned long __global_save_flags(void); -extern void __global_restore_flags(unsigned long); -#define cli() __global_cli() -#define sti() __global_sti() -#define save_flags(x) ((x)=__global_save_flags()) -#define restore_flags(x) __global_restore_flags(x) - -#else - -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) +/* + * Compatibility macros - they will be removed after some time. + */ +#if !CONFIG_SMP +# define sti() local_irq_enable() +# define cli() local_irq_disable() +# define save_flags(flags) local_save_flags(flags) +# define restore_flags(flags) local_irq_restore(flags) #endif /* diff --git a/include/asm-ia64/system.h b/include/asm-ia64/system.h index 088e84a1b4df..9cc45e562991 100644 --- a/include/asm-ia64/system.h +++ b/include/asm-ia64/system.h @@ -169,12 +169,10 @@ do { \ #define local_irq_enable() __asm__ __volatile__ (";; ssm psr.i;; srlz.d" ::: "memory") -#define __cli() local_irq_disable () -#define __save_flags(flags) __asm__ __volatile__ ("mov %0=psr" : "=r" (flags) :: "memory") -#define __save_and_cli(flags) local_irq_save(flags) -#define save_and_cli(flags) __save_and_cli(flags) -#define __sti() local_irq_enable () -#define __restore_flags(flags) local_irq_restore(flags) +#define local_irq_disable() local_irq_disable () +#define local_save_flags(flags) __asm__ __volatile__ ("mov %0=psr" : "=r" (flags) :: "memory") +#define local_irq_save(flags) local_irq_save(flags) +#define save_and_cli(flags) local_irq_save(flags) #ifdef CONFIG_SMP extern void __global_cli (void); @@ -186,10 +184,10 @@ do { \ # define save_flags(flags) ((flags) = __global_save_flags()) # define restore_flags(flags) __global_restore_flags(flags) #else /* !CONFIG_SMP */ -# define cli() __cli() -# define sti() __sti() -# define save_flags(flags) __save_flags(flags) -# define restore_flags(flags) __restore_flags(flags) +# define cli() local_irq_disable() +# define sti() local_irq_enable() +# define save_flags(flags) local_save_flags(flags) +# define restore_flags(flags) local_irq_restore(flags) #endif /* !CONFIG_SMP */ /* diff --git a/include/asm-m68k/smplock.h b/include/asm-m68k/smplock.h index 96565069c988..3e98a6afd154 100644 --- a/include/asm-m68k/smplock.h +++ b/include/asm-m68k/smplock.h @@ -18,7 +18,7 @@ do { \ if (task->lock_depth >= 0) \ spin_unlock(&kernel_flag); \ release_irqlock(cpu); \ - __sti(); \ + local_irq_enable(); \ } while (0) /* diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h index efc5ab8ff507..eb0fc6a8fc16 100644 --- a/include/asm-m68k/system.h +++ b/include/asm-m68k/system.h @@ -49,28 +49,25 @@ asmlinkage void resume(void); /* interrupt control.. */ #if 0 -#define __sti() asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory") +#define local_irq_enable() asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory") #else #include <asm/hardirq.h> -#define __sti() ({ \ +#define local_irq_enable() ({ \ if (MACH_IS_Q40 || !local_irq_count(smp_processor_id())) \ asm volatile ("andiw %0,%%sr": : "i" (ALLOWINT) : "memory"); \ }) #endif -#define __cli() asm volatile ("oriw #0x0700,%%sr": : : "memory") -#define __save_flags(x) asm volatile ("movew %%sr,%0":"=d" (x) : : "memory") -#define __restore_flags(x) asm volatile ("movew %0,%%sr": :"d" (x) : "memory") +#define local_irq_disable() asm volatile ("oriw #0x0700,%%sr": : : "memory") +#define local_save_flags(x) asm volatile ("movew %%sr,%0":"=d" (x) : : "memory") +#define local_irq_restore(x) asm volatile ("movew %0,%%sr": :"d" (x) : "memory") /* For spinlocks etc */ -#define local_irq_save(x) ({ __save_flags(x); __cli(); }) -#define local_irq_restore(x) __restore_flags(x) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() - -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) +#define local_irq_save(x) ({ local_save_flags(x); local_irq_disable(); }) + +#define cli() local_irq_disable() +#define sti() local_irq_enable() +#define save_flags(x) local_save_flags(x) +#define restore_flags(x) local_irq_restore(x) #define save_and_cli(flags) do { save_flags(flags); cli(); } while(0) /* diff --git a/include/asm-mips/bitops.h b/include/asm-mips/bitops.h index edff4c0fe86b..a8d323251189 100644 --- a/include/asm-mips/bitops.h +++ b/include/asm-mips/bitops.h @@ -29,10 +29,10 @@ * that dares to use kernel include files alive. */ #define __bi_flags unsigned long flags -#define __bi_cli() __cli() -#define __bi_save_flags(x) __save_flags(x) -#define __bi_save_and_cli(x) __save_and_cli(x) -#define __bi_restore_flags(x) __restore_flags(x) +#define __bi_cli() local_irq_disable() +#define __bi_save_flags(x) local_save_flags(x) +#define __bi_save_and_cli(x) local_irq_save(x) +#define __bi_restore_flags(x) local_irq_restore(x) #else #define __bi_flags #define __bi_cli() diff --git a/include/asm-mips/smplock.h b/include/asm-mips/smplock.h index 188c4b4c9eb3..43da07e41222 100644 --- a/include/asm-mips/smplock.h +++ b/include/asm-mips/smplock.h @@ -21,7 +21,7 @@ do { \ if (task->lock_depth >= 0) \ spin_unlock(&kernel_flag); \ release_irqlock(cpu); \ - __sti(); \ + local_irq_enable(); \ } while (0) /* diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h index 60aeb5b3bc8f..2ececd43d9c3 100644 --- a/include/asm-mips/system.h +++ b/include/asm-mips/system.h @@ -22,7 +22,7 @@ #include <linux/kernel.h> extern __inline__ void -__sti(void) +local_irq_enable(void) { __asm__ __volatile__( ".set\tpush\n\t" @@ -46,7 +46,7 @@ __sti(void) * no nops at all. */ extern __inline__ void -__cli(void) +local_irq_disable(void) { __asm__ __volatile__( ".set\tpush\n\t" @@ -66,7 +66,7 @@ __cli(void) : "$1", "memory"); } -#define __save_flags(x) \ +#define local_save_flags(x) \ __asm__ __volatile__( \ ".set\tpush\n\t" \ ".set\treorder\n\t" \ @@ -74,7 +74,7 @@ __asm__ __volatile__( \ ".set\tpop\n\t" \ : "=r" (x)) -#define __save_and_cli(x) \ +#define local_irq_save(x) \ __asm__ __volatile__( \ ".set\tpush\n\t" \ ".set\treorder\n\t" \ @@ -92,12 +92,12 @@ __asm__ __volatile__( \ : /* no inputs */ \ : "$1", "memory") -#define __restore_flags(flags) \ +#define local_irq_restore(flags) \ do { \ unsigned long __tmp1; \ \ __asm__ __volatile__( \ - ".set\tnoreorder\t\t\t# __restore_flags\n\t" \ + ".set\tnoreorder\t\t\t# local_irq_restore\n\t" \ ".set\tnoat\n\t" \ "mfc0\t$1, $12\n\t" \ "andi\t%0, 1\n\t" \ @@ -129,20 +129,14 @@ extern void __global_restore_flags(unsigned long); #else /* Single processor */ -# define sti() __sti() -# define cli() __cli() -# define save_flags(x) __save_flags(x) -# define save_and_cli(x) __save_and_cli(x) -# define restore_flags(x) __restore_flags(x) +# define sti() local_irq_enable() +# define cli() local_irq_disable() +# define save_flags(x) local_save_flags(x) +# define save_and_cli(x) local_irq_save(x) +# define restore_flags(x) local_irq_restore(x) #endif /* SMP */ -/* For spinlocks etc */ -#define local_irq_save(x) __save_and_cli(x); -#define local_irq_restore(x) __restore_flags(x); -#define local_irq_disable() __cli(); -#define local_irq_enable() __sti(); - /* * These are probably defined overly paranoid ... */ diff --git a/include/asm-mips64/smplock.h b/include/asm-mips64/smplock.h index f0b627e6a92e..68345b04d68f 100644 --- a/include/asm-mips64/smplock.h +++ b/include/asm-mips64/smplock.h @@ -22,7 +22,7 @@ static __inline__ void release_kernel_lock(struct task_struct *task, int cpu) if (task->lock_depth >= 0) spin_unlock(&kernel_flag); release_irqlock(cpu); - __sti(); + local_irq_enable(); } /* diff --git a/include/asm-mips64/system.h b/include/asm-mips64/system.h index dfb641fbff5a..908b885b1f1f 100644 --- a/include/asm-mips64/system.h +++ b/include/asm-mips64/system.h @@ -16,7 +16,7 @@ #include <linux/kernel.h> extern __inline__ void -__sti(void) +local_irq_enable(void) { __asm__ __volatile__( ".set\tnoreorder\n\t" @@ -40,7 +40,7 @@ __sti(void) * no nops at all. */ extern __inline__ void -__cli(void) +local_irq_disable(void) { __asm__ __volatile__( ".set\tnoreorder\n\t" @@ -59,14 +59,14 @@ __cli(void) : "$1", "memory"); } -#define __save_flags(x) \ +#define local_save_flags(x) \ __asm__ __volatile__( \ ".set\tnoreorder\n\t" \ "mfc0\t%0,$12\n\t" \ ".set\treorder" \ : "=r" (x)) -#define __save_and_cli(x) \ +#define local_irq_save(x) \ __asm__ __volatile__( \ ".set\tnoreorder\n\t" \ ".set\tnoat\n\t" \ @@ -83,12 +83,12 @@ __asm__ __volatile__( \ : /* no inputs */ \ : "$1", "memory") -#define __restore_flags(flags) \ +#define local_irq_restore(flags) \ do { \ unsigned long __tmp1; \ \ __asm__ __volatile__( \ - ".set\tnoreorder\t\t\t# __restore_flags\n\t" \ + ".set\tnoreorder\t\t\t# local_irq_restore\n\t" \ ".set\tnoat\n\t" \ "mfc0\t$1, $12\n\t" \ "andi\t%0, 1\n\t" \ @@ -120,20 +120,14 @@ extern void __global_restore_flags(unsigned long); #else -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) -#define save_and_cli(x) __save_and_cli(x) +#define cli() local_irq_disable() +#define sti() local_irq_enable() +#define save_flags(x) local_save_flags(x) +#define restore_flags(x) local_irq_restore(x) +#define save_and_cli(x) local_irq_save(x) #endif /* CONFIG_SMP */ -/* For spinlocks etc */ -#define local_irq_save(x) __save_and_cli(x); -#define local_irq_restore(x) __restore_flags(x); -#define local_irq_disable() __cli(); -#define local_irq_enable() __sti(); - /* * These are probably defined overly paranoid ... */ diff --git a/include/asm-parisc/smplock.h b/include/asm-parisc/smplock.h index 1590fafe9e1c..06fb015d5cb9 100644 --- a/include/asm-parisc/smplock.h +++ b/include/asm-parisc/smplock.h @@ -16,7 +16,7 @@ do { \ if (task->lock_depth >= 0) \ spin_unlock(&kernel_flag); \ release_irqlock(cpu); \ - __sti(); \ + local_irq_enable(); \ } while (0) /* diff --git a/include/asm-parisc/system.h b/include/asm-parisc/system.h index 1f25634186f7..b5bfb03fe1aa 100644 --- a/include/asm-parisc/system.h +++ b/include/asm-parisc/system.h @@ -62,24 +62,22 @@ extern struct task_struct *_switch_to(struct task_struct *, struct task_struct * #endif /* interrupt control */ -#define __save_flags(x) __asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory") -#define __restore_flags(x) __asm__ __volatile__("mtsm %0" : : "r" (x) : "memory") -#define __cli() __asm__ __volatile__("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory" ) -#define __sti() __asm__ __volatile__("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory" ) +#define local_save_flags(x) __asm__ __volatile__("ssm 0, %0" : "=r" (x) : : "memory") +#define local_irq_restore(x) __asm__ __volatile__("mtsm %0" : : "r" (x) : "memory") +#define local_irq_disable() __asm__ __volatile__("rsm %0,%%r0\n" : : "i" (PSW_I) : "memory" ) +#define local_irq_enable() __asm__ __volatile__("ssm %0,%%r0\n" : : "i" (PSW_I) : "memory" ) #define local_irq_save(x) \ __asm__ __volatile__("rsm %1,%0" : "=r" (x) :"i" (PSW_I) : "memory" ) #define local_irq_restore(x) \ __asm__ __volatile__("mtsm %0" : : "r" (x) : "memory" ) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() #ifdef CONFIG_SMP #else -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) +#define cli() local_irq_disable() +#define sti() local_irq_enable() +#define save_flags(x) local_save_flags(x) +#define restore_flags(x) local_irq_restore(x) #endif diff --git a/include/asm-ppc/hw_irq.h b/include/asm-ppc/hw_irq.h index 71112a54a79b..e36d90289236 100644 --- a/include/asm-ppc/hw_irq.h +++ b/include/asm-ppc/hw_irq.h @@ -21,10 +21,10 @@ extern void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq); asm volatile("mfmsr %0" : "=r" (rval)); rval;}) #define mtmsr(v) asm volatile("mtmsr %0" : : "r" (v)) -#define __save_flags(flags) ((flags) = mfmsr()) -#define __restore_flags(flags) mtmsr(flags) +#define local_save_flags(flags) ((flags) = mfmsr()) +#define local_irq_restore(flags) mtmsr(flags) -static inline void __cli(void) +static inline void local_irq_disable(void) { unsigned long msr; msr = mfmsr(); @@ -32,7 +32,7 @@ static inline void __cli(void) __asm__ __volatile__("": : :"memory"); } -static inline void __sti(void) +static inline void local_irq_enable(void) { unsigned long msr; __asm__ __volatile__("": : :"memory"); @@ -49,18 +49,18 @@ static inline void __do_save_and_cli(unsigned long *flags) __asm__ __volatile__("": : :"memory"); } -#define __save_and_cli(flags) __do_save_and_cli(&flags) +#define local_irq_save(flags) __do_save_and_cli(&flags) #else -extern void __sti(void); -extern void __cli(void); -extern void __restore_flags(unsigned long); -extern void __save_flags_ptr(unsigned long *); -extern unsigned long __sti_end, __cli_end, __restore_flags_end, __save_flags_ptr_end; +extern void local_irq_enable(void); +extern void local_irq_disable(void); +extern void local_irq_restore(unsigned long); +extern void local_save_flags_ptr(unsigned long *); +extern unsigned long local_irq_enable_end, local_irq_disable_end, local_irq_restore_end, local_save_flags_ptr_end; -#define __save_flags(flags) __save_flags_ptr((unsigned long *)&flags) -#define __save_and_cli(flags) ({__save_flags(flags);__cli();}) +#define local_save_flags(flags) local_save_flags_ptr((unsigned long *)&flags) +#define local_irq_save(flags) ({local_save_flags(flags);local_irq_disable();}) #endif diff --git a/include/asm-ppc/system.h b/include/asm-ppc/system.h index 920752c47576..a9a6b1ac6aab 100644 --- a/include/asm-ppc/system.h +++ b/include/asm-ppc/system.h @@ -103,11 +103,11 @@ extern void dump_regs(struct pt_regs *); #ifndef CONFIG_SMP -#define cli() __cli() -#define sti() __sti() -#define save_flags(flags) __save_flags(flags) -#define restore_flags(flags) __restore_flags(flags) -#define save_and_cli(flags) __save_and_cli(flags) +#define cli() local_irq_disable() +#define sti() local_irq_enable() +#define save_flags(flags) local_save_flags(flags) +#define restore_flags(flags) local_irq_restore(flags) +#define save_and_cli(flags) local_irq_save(flags) #else /* CONFIG_SMP */ @@ -122,11 +122,6 @@ extern void __global_restore_flags(unsigned long); #endif /* !CONFIG_SMP */ -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() -#define local_irq_save(flags) __save_and_cli(flags) -#define local_irq_restore(flags) __restore_flags(flags) - static __inline__ unsigned long xchg_u32(volatile void *p, unsigned long val) { diff --git a/include/asm-ppc64/hw_irq.h b/include/asm-ppc64/hw_irq.h index 46bed74a35d4..3e030aa11ddd 100644 --- a/include/asm-ppc64/hw_irq.h +++ b/include/asm-ppc64/hw_irq.h @@ -26,18 +26,18 @@ extern unsigned long __no_use_save_flags(void); extern void __no_use_set_lost(unsigned long); extern void __no_lpq_restore_flags(unsigned long); -#define __cli() __no_use_cli() -#define __sti() __no_use_sti() -#define __save_flags(flags) ((flags) = __no_use_save_flags()) -#define __restore_flags(flags) __no_use_restore_flags((unsigned long)flags) -#define __save_and_cli(flags) ({__save_flags(flags);__cli();}) +#define local_irq_disable() __no_use_cli() +#define local_irq_enable() __no_use_sti() +#define local_save_flags(flags) ((flags) = __no_use_save_flags()) +#define local_irq_restore(flags) __no_use_restore_flags((unsigned long)flags) +#define local_irq_save(flags) ({local_save_flags(flags);local_irq_disable();}) #else -#define __save_flags(flags) ((flags) = mfmsr()) -#define __restore_flags(flags) __mtmsrd((flags), 1) +#define local_save_flags(flags) ((flags) = mfmsr()) +#define local_irq_restore(flags) __mtmsrd((flags), 1) -static inline void __cli(void) +static inline void local_irq_disable(void) { unsigned long msr; msr = mfmsr(); @@ -45,7 +45,7 @@ static inline void __cli(void) __asm__ __volatile__("": : :"memory"); } -static inline void __sti(void) +static inline void local_irq_enable(void) { unsigned long msr; __asm__ __volatile__("": : :"memory"); @@ -62,7 +62,7 @@ static inline void __do_save_and_cli(unsigned long *flags) __asm__ __volatile__("": : :"memory"); } -#define __save_and_cli(flags) __do_save_and_cli(&flags) +#define local_irq_save(flags) __do_save_and_cli(&flags) #endif /* CONFIG_PPC_ISERIES */ diff --git a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h index a6882fe53f77..c310eca6c5ef 100644 --- a/include/asm-ppc64/system.h +++ b/include/asm-ppc64/system.h @@ -116,11 +116,11 @@ extern void dump_regs(struct pt_regs *); #ifndef CONFIG_SMP -#define cli() __cli() -#define sti() __sti() -#define save_flags(flags) __save_flags(flags) -#define restore_flags(flags) __restore_flags(flags) -#define save_and_cli(flags) __save_and_cli(flags) +#define cli() local_irq_disable() +#define sti() local_irq_enable() +#define save_flags(flags) local_save_flags(flags) +#define restore_flags(flags) local_irq_restore(flags) +#define save_and_cli(flags) local_irq_save(flags) #else /* CONFIG_SMP */ @@ -135,11 +135,6 @@ extern void __global_restore_flags(unsigned long); #endif /* !CONFIG_SMP */ -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() -#define local_irq_save(flags) __save_and_cli(flags) -#define local_irq_restore(flags) __restore_flags(flags) - static __inline__ int __is_processor(unsigned long pv) { unsigned long pvr; diff --git a/include/asm-s390/smplock.h b/include/asm-s390/smplock.h index 1f6485fb0902..a12df4a3f882 100644 --- a/include/asm-s390/smplock.h +++ b/include/asm-s390/smplock.h @@ -21,7 +21,7 @@ do { \ if (task->lock_depth >= 0) \ spin_unlock(&kernel_flag); \ release_irqlock(cpu); \ - __sti(); \ + local_irq_enable(); \ } while (0) /* diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index cc66bc210fc0..ab7e6a28196f 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h @@ -132,23 +132,23 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) #define set_wmb(var, value) do { var = value; wmb(); } while (0) /* interrupt control.. */ -#define __sti() ({ \ +#define local_irq_enable() ({ \ __u8 __dummy; \ __asm__ __volatile__ ( \ "stosm 0(%0),0x03" : : "a" (&__dummy) : "memory"); \ }) -#define __cli() ({ \ +#define local_irq_disable() ({ \ __u32 __flags; \ __asm__ __volatile__ ( \ "stnsm 0(%0),0xFC" : : "a" (&__flags) : "memory"); \ __flags; \ }) -#define __save_flags(x) \ +#define local_save_flags(x) \ __asm__ __volatile__("stosm 0(%0),0" : : "a" (&x) : "memory") -#define __restore_flags(x) \ +#define local_irq_restore(x) \ __asm__ __volatile__("ssm 0(%0)" : : "a" (&x) : "memory") #define __load_psw(psw) \ @@ -211,10 +211,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) }) /* For spinlocks etc */ -#define local_irq_save(x) ((x) = __cli()) -#define local_irq_restore(x) __restore_flags(x) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() +#define local_irq_save(x) ((x) = local_irq_disable()) #ifdef CONFIG_SMP @@ -235,10 +232,10 @@ extern void smp_ctl_clear_bit(int cr, int bit); #else -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) +#define cli() local_irq_disable() +#define sti() local_irq_enable() +#define save_flags(x) local_save_flags(x) +#define restore_flags(x) local_irq_restore(x) #define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit) #define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit) diff --git a/include/asm-s390x/smplock.h b/include/asm-s390x/smplock.h index 1f6485fb0902..a12df4a3f882 100644 --- a/include/asm-s390x/smplock.h +++ b/include/asm-s390x/smplock.h @@ -21,7 +21,7 @@ do { \ if (task->lock_depth >= 0) \ spin_unlock(&kernel_flag); \ release_irqlock(cpu); \ - __sti(); \ + local_irq_enable(); \ } while (0) /* diff --git a/include/asm-s390x/system.h b/include/asm-s390x/system.h index 659a63bd2cac..2454658db855 100644 --- a/include/asm-s390x/system.h +++ b/include/asm-s390x/system.h @@ -144,23 +144,23 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) #define set_wmb(var, value) do { var = value; wmb(); } while (0) /* interrupt control.. */ -#define __sti() ({ \ +#define local_irq_enable() ({ \ unsigned long __dummy; \ __asm__ __volatile__ ( \ "stosm 0(%0),0x03" : : "a" (&__dummy) : "memory"); \ }) -#define __cli() ({ \ +#define local_irq_disable() ({ \ unsigned long __flags; \ __asm__ __volatile__ ( \ "stnsm 0(%0),0xFC" : : "a" (&__flags) : "memory"); \ __flags; \ }) -#define __save_flags(x) \ +#define local_save_flags(x) \ __asm__ __volatile__("stosm 0(%0),0" : : "a" (&x) : "memory") -#define __restore_flags(x) \ +#define local_irq_restore(x) \ __asm__ __volatile__("ssm 0(%0)" : : "a" (&x) : "memory") #define __load_psw(psw) \ @@ -221,10 +221,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) }) /* For spinlocks etc */ -#define local_irq_save(x) ((x) = __cli()) -#define local_irq_restore(x) __restore_flags(x) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() +#define local_irq_save(x) ((x) = local_irq_disable()) #ifdef CONFIG_SMP @@ -245,10 +242,10 @@ extern void smp_ctl_clear_bit(int cr, int bit); #else -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) +#define cli() local_irq_disable() +#define sti() local_irq_enable() +#define save_flags(x) local_save_flags(x) +#define restore_flags(x) local_irq_restore(x) #define ctl_set_bit(cr, bit) __ctl_set_bit(cr, bit) #define ctl_clear_bit(cr, bit) __ctl_clear_bit(cr, bit) diff --git a/include/asm-sh/system.h b/include/asm-sh/system.h index 20d9026a427d..c68ad7770d93 100644 --- a/include/asm-sh/system.h +++ b/include/asm-sh/system.h @@ -104,7 +104,7 @@ extern void __xchg_called_with_bad_pointer(void); #define set_wmb(var, value) do { var = value; wmb(); } while (0) /* Interrupt Control */ -static __inline__ void __sti(void) +static __inline__ void local_irq_enable(void) { unsigned long __dummy0, __dummy1; @@ -118,7 +118,7 @@ static __inline__ void __sti(void) : "memory"); } -static __inline__ void __cli(void) +static __inline__ void local_irq_disable(void) { unsigned long __dummy; __asm__ __volatile__("stc sr, %0\n\t" @@ -129,10 +129,10 @@ static __inline__ void __cli(void) : "memory"); } -#define __save_flags(x) \ +#define local_save_flags(x) \ __asm__("stc sr, %0; and #0xf0, %0" : "=&z" (x) :/**/: "memory" ) -static __inline__ unsigned long __save_and_cli(void) +static __inline__ unsigned long local_irq_save(void) { unsigned long flags, __dummy; @@ -149,34 +149,34 @@ static __inline__ unsigned long __save_and_cli(void) } #ifdef DEBUG_CLI_STI -static __inline__ void __restore_flags(unsigned long x) +static __inline__ void local_irq_restore(unsigned long x) { if ((x & 0x000000f0) != 0x000000f0) - __sti(); + local_irq_enable(); else { unsigned long flags; - __save_flags(flags); + local_save_flags(flags); if (flags == 0) { extern void dump_stack(void); printk(KERN_ERR "BUG!\n"); dump_stack(); - __cli(); + local_irq_disable(); } } } #else -#define __restore_flags(x) do { \ +#define local_irq_restore(x) do { \ if ((x & 0x000000f0) != 0x000000f0) \ - __sti(); \ + local_irq_enable(); \ } while (0) #endif #define really_restore_flags(x) do { \ if ((x & 0x000000f0) != 0x000000f0) \ - __sti(); \ + local_irq_enable(); \ else \ - __cli(); \ + local_irq_disable(); \ } while (0) /* @@ -216,10 +216,7 @@ do { \ } while (0) /* For spinlocks etc */ -#define local_irq_save(x) x = __save_and_cli() -#define local_irq_restore(x) __restore_flags(x) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() +#define local_irq_save(x) x = local_irq_save() #ifdef CONFIG_SMP @@ -234,11 +231,11 @@ extern void __global_restore_flags(unsigned long); #else -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define save_and_cli(x) x = __save_and_cli() -#define restore_flags(x) __restore_flags(x) +#define cli() local_irq_disable() +#define sti() local_irq_enable() +#define save_flags(x) local_save_flags(x) +#define save_and_cli(x) x = local_irq_save() +#define restore_flags(x) local_irq_restore(x) #endif diff --git a/include/asm-sparc/smplock.h b/include/asm-sparc/smplock.h index dd2cc2b54267..bd931bb5c511 100644 --- a/include/asm-sparc/smplock.h +++ b/include/asm-sparc/smplock.h @@ -21,7 +21,7 @@ do { \ if (unlikely(task->lock_depth >= 0)) { \ spin_unlock(&kernel_flag); \ release_irqlock(cpu); \ - __sti(); \ + local_irq_enable(); \ } \ } while (0) diff --git a/include/asm-sparc/softirq.h b/include/asm-sparc/softirq.h index 84c523031f8a..dd486a2d3932 100644 --- a/include/asm-sparc/softirq.h +++ b/include/asm-sparc/softirq.h @@ -19,7 +19,7 @@ do { if (!--local_bh_count(smp_processor_id()) && \ softirq_pending(smp_processor_id())) { \ do_softirq(); \ - __sti(); \ + local_irq_enable(); \ } \ } while (0) #define in_softirq() (local_bh_count(smp_processor_id()) != 0) diff --git a/include/asm-sparc/spinlock.h b/include/asm-sparc/spinlock.h index 478cec9542d4..2419711fc1e5 100644 --- a/include/asm-sparc/spinlock.h +++ b/include/asm-sparc/spinlock.h @@ -58,30 +58,30 @@ extern void _do_write_unlock(rwlock_t *rw); #define read_lock(lock) \ do { unsigned long flags; \ - __save_and_cli(flags); \ + local_irq_save(flags); \ _do_read_lock(lock, "read_lock"); \ - __restore_flags(flags); \ + local_irq_restore(flags); \ } while(0) #define read_unlock(lock) \ do { unsigned long flags; \ - __save_and_cli(flags); \ + local_irq_save(flags); \ _do_read_unlock(lock, "read_unlock"); \ - __restore_flags(flags); \ + local_irq_restore(flags); \ } while(0) #define write_lock(lock) \ do { unsigned long flags; \ - __save_and_cli(flags); \ + local_irq_save(flags); \ _do_write_lock(lock, "write_lock"); \ - __restore_flags(flags); \ + local_irq_restore(flags); \ } while(0) #define write_unlock(lock) \ do { unsigned long flags; \ - __save_and_cli(flags); \ + local_irq_save(flags); \ _do_write_unlock(lock); \ - __restore_flags(flags); \ + local_irq_restore(flags); \ } while(0) #else /* !SPIN_LOCK_DEBUG */ @@ -180,9 +180,9 @@ extern __inline__ void _read_lock(rwlock_t *rw) #define read_lock(lock) \ do { unsigned long flags; \ - __save_and_cli(flags); \ + local_irq_save(flags); \ _read_lock(lock); \ - __restore_flags(flags); \ + local_irq_restore(flags); \ } while(0) extern __inline__ void _read_unlock(rwlock_t *rw) @@ -200,9 +200,9 @@ extern __inline__ void _read_unlock(rwlock_t *rw) #define read_unlock(lock) \ do { unsigned long flags; \ - __save_and_cli(flags); \ + local_irq_save(flags); \ _read_unlock(lock); \ - __restore_flags(flags); \ + local_irq_restore(flags); \ } while(0) extern __inline__ void write_lock(rwlock_t *rw) diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h index 4725f9d31738..f44ed09e3c20 100644 --- a/include/asm-sparc/system.h +++ b/include/asm-sparc/system.h @@ -164,7 +164,7 @@ extern __inline__ void setipl(unsigned long __orig_psr) : "memory", "cc"); } -extern __inline__ void __cli(void) +extern __inline__ void local_irq_disable(void) { unsigned long tmp; @@ -179,7 +179,7 @@ extern __inline__ void __cli(void) : "memory"); } -extern __inline__ void __sti(void) +extern __inline__ void local_irq_enable(void) { unsigned long tmp; @@ -241,13 +241,9 @@ extern __inline__ unsigned long read_psr_and_cli(void) return retval; } -#define __save_flags(flags) ((flags) = getipl()) -#define __save_and_cli(flags) ((flags) = read_psr_and_cli()) -#define __restore_flags(flags) setipl((flags)) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() -#define local_irq_save(flags) __save_and_cli(flags) -#define local_irq_restore(flags) __restore_flags(flags) +#define local_save_flags(flags) ((flags) = getipl()) +#define local_irq_save(flags) ((flags) = read_psr_and_cli()) +#define local_irq_restore(flags) setipl((flags)) #ifdef CONFIG_SMP @@ -266,11 +262,11 @@ extern void __global_restore_flags(unsigned long flags); #else -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) -#define save_and_cli(x) __save_and_cli(x) +#define cli() local_irq_disable() +#define sti() local_irq_enable() +#define save_flags(x) local_save_flags(x) +#define restore_flags(x) local_irq_restore(x) +#define save_and_cli(x) local_irq_save(x) #endif diff --git a/include/asm-sparc64/smplock.h b/include/asm-sparc64/smplock.h index d9c87542f5c6..74cfc0e990e8 100644 --- a/include/asm-sparc64/smplock.h +++ b/include/asm-sparc64/smplock.h @@ -29,7 +29,7 @@ do { \ if (unlikely(task->lock_depth >= 0)) { \ spin_unlock(&kernel_flag); \ release_irqlock(cpu); \ - __sti(); \ + local_irq_enable(); \ } \ } while (0) diff --git a/include/asm-sparc64/softirq.h b/include/asm-sparc64/softirq.h index 0239b7275cd5..822c893a5065 100644 --- a/include/asm-sparc64/softirq.h +++ b/include/asm-sparc64/softirq.h @@ -16,7 +16,7 @@ do { if (!--local_bh_count(smp_processor_id()) && \ softirq_pending(smp_processor_id())) { \ do_softirq(); \ - __sti(); \ + local_irq_enable(); \ } \ preempt_enable(); \ } while (0) diff --git a/include/asm-sparc64/spinlock.h b/include/asm-sparc64/spinlock.h index 55fef65608c3..34c221d282a1 100644 --- a/include/asm-sparc64/spinlock.h +++ b/include/asm-sparc64/spinlock.h @@ -140,30 +140,30 @@ extern void _do_write_unlock(rwlock_t *rw); #define _raw_read_lock(lock) \ do { unsigned long flags; \ - __save_and_cli(flags); \ + local_irq_save(flags); \ _do_read_lock(lock, "read_lock"); \ - __restore_flags(flags); \ + local_irq_restore(flags); \ } while(0) #define _raw_read_unlock(lock) \ do { unsigned long flags; \ - __save_and_cli(flags); \ + local_irq_save(flags); \ _do_read_unlock(lock, "read_unlock"); \ - __restore_flags(flags); \ + local_irq_restore(flags); \ } while(0) #define _raw_write_lock(lock) \ do { unsigned long flags; \ - __save_and_cli(flags); \ + local_irq_save(flags); \ _do_write_lock(lock, "write_lock"); \ - __restore_flags(flags); \ + local_irq_restore(flags); \ } while(0) #define _raw_write_unlock(lock) \ do { unsigned long flags; \ - __save_and_cli(flags); \ + local_irq_save(flags); \ _do_write_unlock(lock); \ - __restore_flags(flags); \ + local_irq_restore(flags); \ } while(0) #endif /* CONFIG_DEBUG_SPINLOCK */ diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h index 8a8808dadc69..f98e5915e612 100644 --- a/include/asm-sparc64/system.h +++ b/include/asm-sparc64/system.h @@ -34,10 +34,10 @@ enum sparc_cpu { #define setipl(__new_ipl) \ __asm__ __volatile__("wrpr %0, %%pil" : : "r" (__new_ipl) : "memory") -#define __cli() \ +#define local_irq_disable() \ __asm__ __volatile__("wrpr 15, %%pil" : : : "memory") -#define __sti() \ +#define local_irq_enable() \ __asm__ __volatile__("wrpr 0, %%pil" : : : "memory") #define getipl() \ @@ -62,20 +62,16 @@ enum sparc_cpu { retval; \ }) -#define __save_flags(flags) ((flags) = getipl()) -#define __save_and_cli(flags) ((flags) = read_pil_and_cli()) -#define __restore_flags(flags) setipl((flags)) -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() -#define local_irq_save(flags) __save_and_cli(flags) -#define local_irq_restore(flags) __restore_flags(flags) +#define local_save_flags(flags) ((flags) = getipl()) +#define local_irq_save(flags) ((flags) = read_pil_and_cli()) +#define local_irq_restore(flags) setipl((flags)) #ifndef CONFIG_SMP -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) -#define save_and_cli(x) __save_and_cli(x) +#define cli() local_irq_disable() +#define sti() local_irq_enable() +#define save_flags(x) local_save_flags(x) +#define restore_flags(x) local_irq_restore(x) +#define save_and_cli(x) local_irq_save(x) #else #ifndef __ASSEMBLY__ @@ -150,7 +146,7 @@ extern void __flushw_user(void); do { spin_unlock(&(rq)->lock); \ flushw_all(); \ } while (0) -#define finish_arch_switch(rq) __sti() +#define finish_arch_switch(rq) local_irq_enable() #ifndef CONFIG_DEBUG_SPINLOCK #define CHECK_LOCKS(PREV) do { } while(0) diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h index 9d6c6f1f48d5..c9604630f910 100644 --- a/include/asm-x86_64/system.h +++ b/include/asm-x86_64/system.h @@ -240,18 +240,16 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, #define warn_if_not_ulong(x) do { unsigned long foo; (void) (&(x) == &foo); } while (0) /* interrupt control.. */ -#define __save_flags(x) do { warn_if_not_ulong(x); __asm__ __volatile__("# save_flags \n\t pushfq ; popq %q0":"=g" (x): /* no input */ :"memory"); } while (0) -#define __restore_flags(x) __asm__ __volatile__("# restore_flags \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory", "cc") -#define __cli() __asm__ __volatile__("cli": : :"memory") -#define __sti() __asm__ __volatile__("sti": : :"memory") +#define local_save_flags(x) do { warn_if_not_ulong(x); __asm__ __volatile__("# save_flags \n\t pushfq ; popq %q0":"=g" (x): /* no input */ :"memory"); } while (0) +#define local_irq_restore(x) __asm__ __volatile__("# restore_flags \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory", "cc") +#define local_irq_disable() __asm__ __volatile__("cli": : :"memory") +#define local_irq_enable() __asm__ __volatile__("sti": : :"memory") /* used in the idle loop; sti takes one instruction cycle to complete */ #define safe_halt() __asm__ __volatile__("sti; hlt": : :"memory") /* For spinlocks etc */ #define local_irq_save(x) do { warn_if_not_ulong(x); __asm__ __volatile__("# local_irq_save \n\t pushfq ; popq %0 ; cli":"=g" (x): /* no input */ :"memory"); } while (0) #define local_irq_restore(x) __asm__ __volatile__("# local_irq_restore \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory") -#define local_irq_disable() __cli() -#define local_irq_enable() __sti() #ifdef CONFIG_SMP @@ -266,10 +264,10 @@ extern void __global_restore_flags(unsigned long); #else -#define cli() __cli() -#define sti() __sti() -#define save_flags(x) __save_flags(x) -#define restore_flags(x) __restore_flags(x) +#define cli() local_irq_disable() +#define sti() local_irq_enable() +#define save_flags(x) local_save_flags(x) +#define restore_flags(x) local_irq_restore(x) #endif diff --git a/include/linux/bio.h b/include/linux/bio.h index 1b4004652cde..fee72762ad8d 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -215,7 +215,7 @@ extern inline char *bio_kmap_irq(struct bio *bio, unsigned long *flags) { unsigned long addr; - __save_flags(*flags); + local_save_flags(*flags); /* * could be low @@ -226,7 +226,7 @@ extern inline char *bio_kmap_irq(struct bio *bio, unsigned long *flags) /* * it's a highmem page */ - __cli(); + local_irq_disable(); addr = (unsigned long) kmap_atomic(bio_page(bio), KM_BIO_SRC_IRQ); if (addr & ~PAGE_MASK) @@ -240,7 +240,7 @@ extern inline void bio_kunmap_irq(char *buffer, unsigned long *flags) unsigned long ptr = (unsigned long) buffer & PAGE_MASK; kunmap_atomic((void *) ptr, KM_BIO_SRC_IRQ); - __restore_flags(*flags); + local_irq_restore(*flags); } #else diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 297cb0ba10c1..7460a98bb0b3 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -389,20 +389,6 @@ extern inline unsigned int block_size(struct block_device *bdev) return bdev->bd_block_size; } -static inline loff_t blkdev_size_in_bytes(kdev_t dev) -{ -#if 0 - if (blk_size_in_bytes[major(dev)]) - return blk_size_in_bytes[major(dev)][minor(dev)]; - else -#endif - if (blk_size[major(dev)]) - return (loff_t) blk_size[major(dev)][minor(dev)] - << BLOCK_SIZE_BITS; - else - return 0; -} - typedef struct {struct page *v;} Sector; unsigned char *read_dev_sector(struct block_device *, unsigned long, Sector *); diff --git a/include/linux/fs.h b/include/linux/fs.h index 84413138923e..b58c1b43f734 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -342,7 +342,7 @@ struct block_device { struct inode * bd_inode; dev_t bd_dev; /* not a kdev_t - it's a search key */ int bd_openers; - const struct block_device_operations *bd_op; + struct block_device_operations *bd_op; struct request_queue *bd_queue; struct semaphore bd_sem; /* open/close mutex */ struct list_head bd_inodes; @@ -350,6 +350,9 @@ struct block_device { int bd_holders; struct block_device * bd_contains; unsigned bd_block_size; + unsigned long bd_offset; + struct semaphore bd_part_sem; + unsigned bd_part_count; }; struct inode { @@ -1082,7 +1085,7 @@ extern void bd_release(struct block_device *); extern void blk_run_queues(void); /* fs/devices.c */ -extern const struct block_device_operations *get_blkfops(unsigned int); +extern struct block_device_operations *get_blkfops(unsigned int); extern int register_chrdev(unsigned int, const char *, struct file_operations *); extern int unregister_chrdev(unsigned int, const char *); extern int chrdev_open(struct inode *, struct file *); @@ -1292,5 +1295,31 @@ static inline ino_t parent_ino(struct dentry *dentry) return res; } +/* NOTE NOTE NOTE: this interface _will_ change in a couple of patches */ + +static inline int dev_lock_part(kdev_t dev) +{ + struct block_device *bdev = bdget(kdev_t_to_nr(dev)); + if (!bdev) + return -ENOMEM; + if (!down_trylock(&bdev->bd_part_sem)) { + if (!bdev->bd_part_count) + return 0; + up(&bdev->bd_part_sem); + } + bdput(bdev); + return -EBUSY; +} + +static inline void dev_unlock_part(kdev_t dev) +{ + struct block_device *bdev = bdget(kdev_t_to_nr(dev)); + if (!bdev) + BUG(); + up(&bdev->bd_part_sem); + bdput(bdev); + bdput(bdev); +} + #endif /* __KERNEL__ */ #endif /* _LINUX_FS_H */ diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 44a954b2c370..93755fee7f36 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -90,8 +90,10 @@ struct gendisk { extern void add_gendisk(struct gendisk *gp); extern void del_gendisk(struct gendisk *gp); extern struct gendisk *get_gendisk(kdev_t dev); -extern unsigned long get_start_sect(kdev_t dev); -extern unsigned long get_nr_sects(kdev_t dev); +static inline unsigned long get_start_sect(struct block_device *bdev) +{ + return bdev->bd_offset; +} #endif /* __KERNEL__ */ diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 3870d26066e9..09e6b86ee763 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -44,6 +44,16 @@ enum { #include <asm/hardirq.h> #include <asm/softirq.h> +/* + * Temporary defines for UP kernels, until all code gets fixed. + */ +#if !CONFIG_SMP +# define cli() local_irq_disable() +# define sti() local_irq_enable() +# define save_flags(x) local_irq_save(x) +# define restore_flags(x) local_irq_restore(x) +# define save_and_cli(x) local_irq_save_off(x) +#endif /* PLEASE, avoid to allocate new softirqs, if you need not _really_ high diff --git a/include/linux/irq_cpustat.h b/include/linux/irq_cpustat.h index dfd73c5ec60d..6eab29be1d61 100644 --- a/include/linux/irq_cpustat.h +++ b/include/linux/irq_cpustat.h @@ -29,8 +29,6 @@ extern irq_cpustat_t irq_stat[]; /* defined in asm/hardirq.h */ /* arch independent irq_stat fields */ #define softirq_pending(cpu) __IRQ_STAT((cpu), __softirq_pending) -#define local_irq_count(cpu) __IRQ_STAT((cpu), __local_irq_count) -#define local_bh_count(cpu) __IRQ_STAT((cpu), __local_bh_count) #define syscall_count(cpu) __IRQ_STAT((cpu), __syscall_count) #define ksoftirqd_task(cpu) __IRQ_STAT((cpu), __ksoftirqd_task) /* arch dependent irq_stat fields */ diff --git a/include/linux/preempt.h b/include/linux/preempt.h new file mode 100644 index 000000000000..172471f0dbde --- /dev/null +++ b/include/linux/preempt.h @@ -0,0 +1,46 @@ +#ifndef __LINUX_PREEMPT_H +#define __LINUX_PREEMPT_H + +#include <linux/config.h> + +#define preempt_count() (current_thread_info()->preempt_count) + +#ifdef CONFIG_PREEMPT + +extern void preempt_schedule(void); + +#define preempt_disable() \ +do { \ + preempt_count()++; \ + barrier(); \ +} while (0) + +#define preempt_enable_no_resched() \ +do { \ + preempt_count()--; \ + barrier(); \ +} while (0) + +#define preempt_enable() \ +do { \ + preempt_enable_no_resched(); \ + if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ + preempt_schedule(); \ +} while (0) + +#define preempt_check_resched() \ +do { \ + if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ + preempt_schedule(); \ +} while (0) + +#else + +#define preempt_disable() do { } while (0) +#define preempt_enable_no_resched() do {} while(0) +#define preempt_enable() do { } while (0) +#define preempt_check_resched() do { } while (0) + +#endif + +#endif /* __LINUX_PREEMPT_H */ diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h new file mode 100644 index 000000000000..19ab829b67e3 --- /dev/null +++ b/include/linux/serial_core.h @@ -0,0 +1,395 @@ +/* + * linux/drivers/char/serial_core.h + * + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * $Id: serial_core.h,v 1.49 2002/07/20 18:06:32 rmk Exp $ + */ + +/* + * The type definitions. These are from Ted Ts'o's serial.h + */ +#define PORT_UNKNOWN 0 +#define PORT_8250 1 +#define PORT_16450 2 +#define PORT_16550 3 +#define PORT_16550A 4 +#define PORT_CIRRUS 5 +#define PORT_16650 6 +#define PORT_16650V2 7 +#define PORT_16750 8 +#define PORT_STARTECH 9 +#define PORT_16C950 10 +#define PORT_16654 11 +#define PORT_16850 12 +#define PORT_RSA 13 +#define PORT_MAX_8250 13 /* max port ID */ + +/* + * ARM specific type numbers. These are not currently guaranteed + * to be implemented, and will change in the future. These are + * separate so any additions to the old serial.c that occur before + * we are merged can be easily merged here. + */ +#define PORT_AMBA 32 +#define PORT_CLPS711X 33 +#define PORT_SA1100 34 +#define PORT_UART00 35 +#define PORT_21285 37 + +#ifdef __KERNEL__ + +#include <linux/config.h> +#include <linux/interrupt.h> +#include <linux/circ_buf.h> +#include <linux/spinlock.h> + +struct uart_port; +struct uart_info; +struct serial_struct; + +/* + * This structure describes all the operations that can be + * done on the physical hardware. + */ +struct uart_ops { + unsigned int (*tx_empty)(struct uart_port *); + void (*set_mctrl)(struct uart_port *, unsigned int mctrl); + unsigned int (*get_mctrl)(struct uart_port *); + void (*stop_tx)(struct uart_port *, unsigned int tty_stop); + void (*start_tx)(struct uart_port *, unsigned int tty_start); + void (*send_xchar)(struct uart_port *, char ch); + void (*stop_rx)(struct uart_port *); + void (*enable_ms)(struct uart_port *); + void (*break_ctl)(struct uart_port *, int ctl); + int (*startup)(struct uart_port *); + void (*shutdown)(struct uart_port *); + void (*change_speed)(struct uart_port *, unsigned int cflag, + unsigned int iflag, unsigned int quot); + void (*pm)(struct uart_port *, unsigned int state, + unsigned int oldstate); + int (*set_wake)(struct uart_port *, unsigned int state); + + /* + * Return a string describing the type of the port + */ + const char *(*type)(struct uart_port *); + + /* + * Release IO and memory resources used by the port. + * This includes iounmap if necessary. + */ + void (*release_port)(struct uart_port *); + + /* + * Request IO and memory resources used by the port. + * This includes iomapping the port if necessary. + */ + int (*request_port)(struct uart_port *); + void (*config_port)(struct uart_port *, int); + int (*verify_port)(struct uart_port *, struct serial_struct *); + int (*ioctl)(struct uart_port *, unsigned int, unsigned long); +}; + +#define UART_CONFIG_TYPE (1 << 0) +#define UART_CONFIG_IRQ (1 << 1) + +struct uart_icount { + __u32 cts; + __u32 dsr; + __u32 rng; + __u32 dcd; + __u32 rx; + __u32 tx; + __u32 frame; + __u32 overrun; + __u32 parity; + __u32 brk; + __u32 buf_overrun; +}; + +struct uart_port { + spinlock_t lock; /* port lock */ + unsigned int iobase; /* in/out[bwl] */ + char *membase; /* read/write[bwl] */ + unsigned int irq; /* irq number */ + unsigned int uartclk; /* base uart clock */ + unsigned char fifosize; /* tx fifo size */ + unsigned char x_char; /* xon/xoff char */ + unsigned char regshift; /* reg offset shift */ + unsigned char iotype; /* io access style */ + +#define UPIO_PORT (0) +#define UPIO_HUB6 (1) +#define UPIO_MEM (2) + + unsigned int read_status_mask; /* driver specific */ + unsigned int ignore_status_mask; /* driver specific */ + struct uart_info *info; /* pointer to parent info */ + struct uart_icount icount; /* statistics */ + + struct console *cons; /* struct console, if any */ +#ifdef CONFIG_SERIAL_CORE_CONSOLE + unsigned long sysrq; /* sysrq timeout */ +#endif + + unsigned int flags; + +#define UPF_HUP_NOTIFY (1 << 0) +#define UPF_SAK (1 << 2) +#define UPF_SPD_MASK (0x1030) +#define UPF_SPD_HI (0x0010) +#define UPF_SPD_VHI (0x0020) +#define UPF_SPD_CUST (0x0030) +#define UPF_SPD_SHI (0x1000) +#define UPF_SPD_WARP (0x1010) +#define UPF_SKIP_TEST (1 << 6) +#define UPF_AUTO_IRQ (1 << 7) +#define UPF_HARDPPS_CD (1 << 11) +#define UPF_LOW_LATENCY (1 << 13) +#define UPF_BUGGY_UART (1 << 14) +#define UPF_AUTOPROBE (1 << 15) +#define UPF_BOOT_AUTOCONF (1 << 28) + +#define UPF_FLAGS (0x7fff) +#define UPF_USR_MASK (UPF_SPD_MASK|UPF_LOW_LATENCY) + + unsigned int mctrl; /* current modem ctrl settings */ + unsigned int timeout; /* character-based timeout */ + unsigned int type; /* port type */ + struct uart_ops *ops; + unsigned int line; /* port index */ + unsigned long mapbase; /* for ioremap */ + unsigned char hub6; /* this should be in the 8250 driver */ + unsigned char unused[3]; +}; + +/* + * This is the state information which is persistent across opens. + * The low level driver must not to touch any elements contained + * within. + */ +struct uart_state { + unsigned int close_delay; + unsigned int closing_wait; + +#define USF_CLOSING_WAIT_INF (0) +#define USF_CLOSING_WAIT_NONE (65535) + + unsigned int custom_divisor; + + int count; + struct uart_info *info; + struct uart_port *port; + +#ifdef CONFIG_PM + struct pm_dev *pm; +#endif +}; + +#define UART_XMIT_SIZE 1024 +/* + * This is the state information which is only valid when the port + * is open; it may be freed by the core driver once the device has + * been closed. Either the low level driver or the core can modify + * stuff here. + */ +struct uart_info { + struct uart_port *port; + struct uart_state *state; + struct tty_struct *tty; + struct circ_buf xmit; + unsigned int flags; + +/* + * These are the flags that specific to info->flags, and reflect our + * internal state. They can not be accessed via port->flags. Low + * level drivers must not change these, but may query them instead. + */ +#define UIF_CHECK_CD (1 << 25) +#define UIF_CTS_FLOW (1 << 26) +#define UIF_CLOSING (1 << 27) +#define UIF_NORMAL_ACTIVE (1 << 29) +#define UIF_INITIALIZED (1 << 31) + + unsigned char *tmpbuf; + struct semaphore tmpbuf_sem; + + unsigned long event; + int blocked_open; + + struct tasklet_struct tlet; + + wait_queue_head_t open_wait; + wait_queue_head_t delta_msr_wait; +}; + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +#define EVT_WRITE_WAKEUP 0 + +struct module; +struct tty_driver; + +struct uart_driver { + struct module *owner; + const char *driver_name; + const char *dev_name; + int major; + int minor; + int nr; + struct console *cons; + + /* + * these are private; the low level driver should not + * touch these; they should be initialised to NULL + */ + struct uart_state *state; + struct tty_driver *tty_driver; +}; + +void uart_event(struct uart_port *port, int event); +struct uart_port *uart_get_console(struct uart_port *ports, int nr, + struct console *c); +void uart_parse_options(char *options, int *baud, int *parity, int *bits, + int *flow); +int uart_set_options(struct uart_port *port, struct console *co, int baud, + int parity, int bits, int flow); +int uart_register_driver(struct uart_driver *uart); +void uart_unregister_driver(struct uart_driver *uart); +void uart_unregister_port(struct uart_driver *reg, int line); +int uart_register_port(struct uart_driver *reg, struct uart_port *port); +int uart_add_one_port(struct uart_driver *reg, struct uart_port *port); +int uart_remove_one_port(struct uart_driver *reg, struct uart_port *port); + +#define uart_circ_empty(circ) ((circ)->head == (circ)->tail) +#define uart_circ_clear(circ) ((circ)->head = (circ)->tail = 0) + +#define uart_circ_chars_pending(circ) \ + (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE)) + +#define uart_circ_chars_free(circ) \ + (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE)) + +#define uart_tx_stopped(port) \ + ((port)->info->tty->stopped || (port)->info->tty->hw_stopped) + +/* + * The following are helper functions for the low level drivers. + */ +#ifdef SUPPORT_SYSRQ +static inline int +uart_handle_sysrq_char(struct uart_port *port, unsigned int ch, + struct pt_regs *regs) +{ + if (port->sysrq) { + if (ch && time_before(jiffies, port->sysrq)) { + handle_sysrq(ch, regs, NULL); + port->sysrq = 0; + return 1; + } + port->sysrq = 0; + } + return 0; +} +#else +#define uart_handle_sysrq_char(port,ch,regs) (0) +#endif + +/* + * We do the SysRQ and SAK checking like this... + */ +static inline int uart_handle_break(struct uart_port *port) +{ + struct uart_info *info = port->info; +#ifdef SUPPORT_SYSRQ + if (port->cons && port->cons->index == port->line) { + if (!port->sysrq) { + port->sysrq = jiffies + HZ*5; + return 1; + } + port->sysrq = 0; + } +#endif + if (info->flags & UPF_SAK) + do_SAK(info->tty); + return 0; +} + +/** + * uart_handle_dcd_change - handle a change of carrier detect state + * @port: uart_port structure for the open port + * @status: new carrier detect status, nonzero if active + */ +static inline void +uart_handle_dcd_change(struct uart_port *port, unsigned int status) +{ + struct uart_info *info = port->info; + + port->icount.dcd++; + +#ifdef CONFIG_HARD_PPS + if ((port->flags & UPF_HARDPPS_CD) && status) + hardpps(); +#endif + + if (info->flags & UIF_CHECK_CD) { + if (status) + wake_up_interruptible(&info->open_wait); + else if (info->tty) + tty_hangup(info->tty); + } +} + +/** + * uart_handle_cts_change - handle a change of clear-to-send state + * @port: uart_port structure for the open port + * @status: new clear to send status, nonzero if active + */ +static inline void +uart_handle_cts_change(struct uart_port *port, unsigned int status) +{ + struct uart_info *info = port->info; + struct tty_struct *tty = info->tty; + + port->icount.cts++; + + if (info->flags & UIF_CTS_FLOW) { + if (tty->hw_stopped) { + if (status) { + tty->hw_stopped = 0; + port->ops->start_tx(port, 0); + uart_event(port, EVT_WRITE_WAKEUP); + } + } else { + if (!status) { + tty->hw_stopped = 1; + port->ops->stop_tx(port, 0); + } + } + } +} + +/* + * UART_ENABLE_MS - determine if port should enable modem status irqs + */ +#define UART_ENABLE_MS(port,cflag) ((port)->flags & UPF_HARDPPS_CD || \ + (cflag) & CRTSCTS || \ + !(cflag) & CLOCAL) + +#endif diff --git a/include/linux/smp.h b/include/linux/smp.h index 6e89d1d34bd8..fff7c165ac2d 100644 --- a/include/linux/smp.h +++ b/include/linux/smp.h @@ -95,7 +95,8 @@ static inline void smp_send_reschedule_all(void) { } #endif /* !SMP */ -#define get_cpu() ({ preempt_disable(); smp_processor_id(); }) -#define put_cpu() preempt_enable() +#define get_cpu() ({ preempt_disable(); smp_processor_id(); }) +#define put_cpu() preempt_enable() +#define put_cpu_no_resched() preempt_enable_no_resched() #endif /* __LINUX_SMP_H */ diff --git a/include/linux/smp_lock.h b/include/linux/smp_lock.h index 13d8c7ace0bb..cfb23f363e61 100644 --- a/include/linux/smp_lock.h +++ b/include/linux/smp_lock.h @@ -7,7 +7,7 @@ #define lock_kernel() do { } while(0) #define unlock_kernel() do { } while(0) -#define release_kernel_lock(task, cpu) do { } while(0) +#define release_kernel_lock(task) do { } while(0) #define reacquire_kernel_lock(task) do { } while(0) #define kernel_locked() 1 diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h index 194541968c6a..d9f4af4103e4 100644 --- a/include/linux/spinlock.h +++ b/include/linux/spinlock.h @@ -2,6 +2,7 @@ #define __LINUX_SPINLOCK_H #include <linux/config.h> +#include <linux/preempt.h> #include <linux/linkage.h> #include <linux/compiler.h> #include <linux/thread_info.h> @@ -120,36 +121,6 @@ #ifdef CONFIG_PREEMPT -asmlinkage void preempt_schedule(void); - -#define preempt_get_count() (current_thread_info()->preempt_count) - -#define preempt_disable() \ -do { \ - ++current_thread_info()->preempt_count; \ - barrier(); \ -} while (0) - -#define preempt_enable_no_resched() \ -do { \ - --current_thread_info()->preempt_count; \ - barrier(); \ -} while (0) - -#define preempt_enable() \ -do { \ - --current_thread_info()->preempt_count; \ - barrier(); \ - if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ - preempt_schedule(); \ -} while (0) - -#define preempt_check_resched() \ -do { \ - if (unlikely(test_thread_flag(TIF_NEED_RESCHED))) \ - preempt_schedule(); \ -} while (0) - #define spin_lock(lock) \ do { \ preempt_disable(); \ @@ -179,12 +150,6 @@ do { \ #else -#define preempt_get_count() (0) -#define preempt_disable() do { } while (0) -#define preempt_enable_no_resched() do {} while(0) -#define preempt_enable() do { } while (0) -#define preempt_check_resched() do { } while (0) - #define spin_lock(lock) _raw_spin_lock(lock) #define spin_trylock(lock) _raw_spin_trylock(lock) #define spin_unlock(lock) _raw_spin_unlock(lock) diff --git a/include/scsi/scsicam.h b/include/scsi/scsicam.h index 8b0a3c197220..5a525fd995b2 100644 --- a/include/scsi/scsicam.h +++ b/include/scsi/scsicam.h @@ -12,9 +12,8 @@ #ifndef SCSICAM_H #define SCSICAM_H -#include <linux/kdev_t.h> -extern int scsicam_bios_param (Disk *disk, kdev_t dev, int *ip); +extern int scsicam_bios_param (Disk *disk, struct block_device *bdev, int *ip); extern int scsi_partsize(unsigned char *buf, unsigned long capacity, unsigned int *cyls, unsigned int *hds, unsigned int *secs); -extern unsigned char *scsi_bios_ptable(kdev_t dev); +extern unsigned char *scsi_bios_ptable(struct block_device *bdev); #endif /* def SCSICAM_H */ diff --git a/init/main.c b/init/main.c index 2133b32001de..3a50b7b197a6 100644 --- a/init/main.c +++ b/init/main.c @@ -373,7 +373,7 @@ asmlinkage void __init start_kernel(void) } kmem_cache_init(); - sti(); + local_irq_enable(); calibrate_delay(); #ifdef CONFIG_BLK_DEV_INITRD if (initrd_start && !initrd_below_start_ok && diff --git a/kernel/exit.c b/kernel/exit.c index f727a3c511c8..71d017f2fd8f 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -530,10 +530,10 @@ NORET_TYPE void do_exit(long code) tsk->flags |= PF_EXITING; del_timer_sync(&tsk->real_timer); - if (unlikely(preempt_get_count())) + if (unlikely(preempt_count())) printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", current->comm, current->pid, - preempt_get_count()); + preempt_count()); fake_volatile: acct_process(code); diff --git a/kernel/fork.c b/kernel/fork.c index f99f9e69521a..99ac5e5799d3 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -740,8 +740,8 @@ struct task_struct *do_fork(unsigned long clone_flags, * total amount of pending timeslices in the system doesnt change, * resulting in more scheduling fairness. */ - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); p->time_slice = (current->time_slice + 1) >> 1; current->time_slice >>= 1; if (!current->time_slice) { @@ -754,7 +754,7 @@ struct task_struct *do_fork(unsigned long clone_flags, scheduler_tick(0, 0); } p->sleep_timestamp = jiffies; - __restore_flags(flags); + local_irq_restore(flags); /* * Ok, add it to the run-queues and make it diff --git a/kernel/panic.c b/kernel/panic.c index 5281e7cce9f8..69f1f9123956 100644 --- a/kernel/panic.c +++ b/kernel/panic.c @@ -94,7 +94,7 @@ NORET_TYPE void panic(const char * fmt, ...) #if defined(CONFIG_ARCH_S390) disabled_wait(caller); #endif - sti(); + local_irq_enable(); for(;;) { CHECK_EMERGENCY_SYNC } diff --git a/kernel/sched.c b/kernel/sched.c index c8a11b29794e..1a6ce9d15d8a 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -427,11 +427,11 @@ void wake_up_forked_process(task_t * p) */ void sched_exit(task_t * p) { - __cli(); + local_irq_disable(); current->time_slice += p->time_slice; if (unlikely(current->time_slice > MAX_TIMESLICE)) current->time_slice = MAX_TIMESLICE; - __sti(); + local_irq_enable(); /* * If the child was a (relative-) CPU hog then decrease * the sleep_avg of the parent as well. @@ -727,7 +727,8 @@ void scheduler_tick(int user_tick, int system) task_t *p = current; if (p == rq->idle) { - if (local_bh_count(cpu) || local_irq_count(cpu) > 1) + /* note: this timer irq context must be accounted for as well */ + if (preempt_count() >= 2*IRQ_OFFSET) kstat.per_cpu_system[cpu] += system; #if CONFIG_SMP idle_tick(); @@ -816,7 +817,7 @@ need_resched: prev = current; rq = this_rq(); - release_kernel_lock(prev, smp_processor_id()); + release_kernel_lock(prev); prepare_arch_schedule(prev); prev->sleep_timestamp = jiffies; spin_lock_irq(&rq->lock); @@ -825,7 +826,7 @@ need_resched: * if entering off of a kernel preemption go straight * to picking the next task. */ - if (unlikely(preempt_get_count() & PREEMPT_ACTIVE)) + if (unlikely(preempt_count() & PREEMPT_ACTIVE)) goto pick_next_task; switch (prev->state) { @@ -1679,8 +1680,8 @@ void __init init_idle(task_t *idle, int cpu) runqueue_t *idle_rq = cpu_rq(cpu), *rq = cpu_rq(task_cpu(idle)); unsigned long flags; - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); double_rq_lock(idle_rq, rq); idle_rq->curr = idle_rq->idle = idle; @@ -1691,10 +1692,12 @@ void __init init_idle(task_t *idle, int cpu) set_task_cpu(idle, cpu); double_rq_unlock(idle_rq, rq); set_tsk_need_resched(idle); - __restore_flags(flags); + local_irq_restore(flags); /* Set the preempt count _outside_ the spinlocks! */ +#if CONFIG_PREEMPT idle->thread_info->preempt_count = (idle->lock_depth >= 0); +#endif } extern void init_timervecs(void); diff --git a/kernel/softirq.c b/kernel/softirq.c index e0093420e169..135106c390c4 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -26,10 +26,6 @@ execution. Hence, we get something sort of weak cpu binding. Though it is still not clear, will it result in better locality or will not. - - These softirqs are not masked by global cli() and start_bh_atomic() - (by clear reasons). Hence, old parts of code still using global locks - MUST NOT use softirqs, but insert interfacing routines acquiring - global locks. F.e. look at BHs implementation. Examples: - NET RX softirq. It is multithreaded and does not require @@ -61,17 +57,17 @@ static inline void wakeup_softirqd(unsigned cpu) asmlinkage void do_softirq() { - int cpu; __u32 pending; long flags; __u32 mask; + int cpu; if (in_interrupt()) return; local_irq_save(flags); - cpu = smp_processor_id(); + pending = softirq_pending(cpu); if (pending) { @@ -111,7 +107,7 @@ restart: } /* - * This function must run with irq disabled! + * This function must run with irqs disabled! */ inline void cpu_raise_softirq(unsigned int cpu, unsigned int nr) { @@ -126,7 +122,7 @@ inline void cpu_raise_softirq(unsigned int cpu, unsigned int nr) * Otherwise we wake up ksoftirqd to make sure we * schedule the softirq soon. */ - if (!(local_irq_count(cpu) | local_bh_count(cpu))) + if (!in_interrupt()) wakeup_softirqd(cpu); } @@ -290,22 +286,16 @@ spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED; static void bh_action(unsigned long nr) { - int cpu = smp_processor_id(); - if (!spin_trylock(&global_bh_lock)) goto resched; - if (!hardirq_trylock(cpu)) - goto resched_unlock; - if (bh_base[nr]) bh_base[nr](); - hardirq_endlock(cpu); + hardirq_endlock(); spin_unlock(&global_bh_lock); return; -resched_unlock: spin_unlock(&global_bh_lock); resched: mark_bh(nr); diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 74cbdeb53734..0f327d594231 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -318,7 +318,7 @@ void __kfree_skb(struct sk_buff *skb) dst_release(skb->dst); if(skb->destructor) { - if (in_irq()) + if (0 && in_irq()) printk(KERN_WARNING "Warning: kfree_skb on " "hard IRQ %p\n", NET_CALLER(skb)); skb->destructor(skb); diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c index a44086ad9548..0b148d05bb6a 100644 --- a/sound/oss/esssolo1.c +++ b/sound/oss/esssolo1.c @@ -235,16 +235,16 @@ static inline void write_seq(struct solo1_state *s, unsigned char data) int i; unsigned long flags; - /* the __cli stunt is to send the data within the command window */ + /* the local_irq_disable stunt is to send the data within the command window */ for (i = 0; i < 0xffff; i++) { - __save_flags(flags); - __cli(); + local_save_flags(flags); + local_irq_disable(); if (!(inb(s->sbbase+0xc) & 0x80)) { outb(data, s->sbbase+0xc); - __restore_flags(flags); + local_irq_restore(flags); return; } - __restore_flags(flags); + local_irq_restore(flags); } printk(KERN_ERR "esssolo1: write_seq timeout\n"); outb(data, s->sbbase+0xc); diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 52562c9fe677..2600281f8a1d 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -1532,7 +1532,7 @@ static int snd_ensoniq_free(ensoniq_t *ensoniq) outl(0, ES_REG(ensoniq, CONTROL)); /* switch everything off */ outl(0, ES_REG(ensoniq, SERIAL)); /* clear serial interface */ #endif - synchronize_irq(); + synchronize_irq(ensoniq->irq); pci_set_power_state(ensoniq->pci, 3); __hw_end: #ifdef CHIP1370 @@ -1720,7 +1720,7 @@ static int __devinit snd_ensoniq_create(snd_card_t * card, #ifdef CHIP1371 snd_ctl_add(card, snd_ctl_new1(&snd_es1371_joystick_addr, ensoniq)); #endif - synchronize_irq(); + synchronize_irq(ensoniq->irq); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ensoniq, &ops)) < 0) { snd_ensoniq_free(ensoniq); diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index f67cc0f4e9fa..fed9bb159112 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1104,7 +1104,7 @@ static int snd_intel8x0_free(intel8x0_t *chip) outb(ICH_RESETREGS, ICHREG(chip, PO_CR)); outb(ICH_RESETREGS, ICHREG(chip, MC_CR)); /* --- */ - synchronize_irq(); + synchronize_irq(chip->irq); __hw_end: if (chip->bdbars) snd_free_pci_pages(chip->pci, 3 * sizeof(u32) * ICH_MAX_FRAGS * 2, chip->bdbars, chip->bdbars_addr); @@ -1335,7 +1335,7 @@ static int __devinit snd_intel8x0_create(snd_card_t * card, } chip->irq = pci->irq; pci_set_master(pci); - synchronize_irq(); + synchronize_irq(chip->irq); /* initialize offsets */ chip->reg_pi_sr = ICH_REG_PI_SR; |
