2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/* rio_linux.c -- Linux driver for the Specialix RIO series cards.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* (C) 1999 R.E.Wolff@BitWizard.nl
|
|
|
|
*
|
|
|
|
* Specialix pays for the development and support of this driver.
|
|
|
|
* Please DO contact support@specialix.co.uk if you require
|
|
|
|
* support. But please read the documentation (rio.txt) first.
|
|
|
|
*
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License as
|
|
|
|
* published by the Free Software Foundation; either version 2 of
|
|
|
|
* the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be
|
|
|
|
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public
|
|
|
|
* License along with this program; if not, write to the Free
|
|
|
|
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
|
|
|
|
* USA.
|
|
|
|
*
|
|
|
|
* Revision history:
|
|
|
|
* $Log: rio.c,v $
|
|
|
|
* Revision 1.1 1999/07/11 10:13:54 wolff
|
|
|
|
* Initial revision
|
|
|
|
*
|
|
|
|
* */
|
|
|
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
#include <linux/kdev_t.h>
|
|
|
|
#include <asm/io.h>
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/sched.h>
|
|
|
|
#include <linux/ioport.h>
|
|
|
|
#include <linux/interrupt.h>
|
|
|
|
#include <linux/errno.h>
|
|
|
|
#include <linux/tty.h>
|
|
|
|
#include <linux/tty_flip.h>
|
|
|
|
#include <linux/mm.h>
|
|
|
|
#include <linux/serial.h>
|
|
|
|
#include <linux/fcntl.h>
|
|
|
|
#include <linux/major.h>
|
|
|
|
#include <linux/delay.h>
|
|
|
|
#include <linux/pci.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/miscdevice.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
|
|
|
|
#include <linux/generic_serial.h>
|
|
|
|
#include <asm/uaccess.h>
|
|
|
|
|
|
|
|
#include "linux_compat.h"
|
|
|
|
#include "pkt.h"
|
|
|
|
#include "daemon.h"
|
|
|
|
#include "rio.h"
|
|
|
|
#include "riospace.h"
|
|
|
|
#include "cmdpkt.h"
|
|
|
|
#include "map.h"
|
|
|
|
#include "rup.h"
|
|
|
|
#include "port.h"
|
|
|
|
#include "riodrvr.h"
|
|
|
|
#include "rioinfo.h"
|
|
|
|
#include "func.h"
|
|
|
|
#include "errors.h"
|
|
|
|
#include "pci.h"
|
|
|
|
|
|
|
|
#include "parmmap.h"
|
|
|
|
#include "unixrup.h"
|
|
|
|
#include "board.h"
|
|
|
|
#include "host.h"
|
|
|
|
#include "phb.h"
|
|
|
|
#include "link.h"
|
|
|
|
#include "cmdblk.h"
|
|
|
|
#include "route.h"
|
|
|
|
#include "cirrus.h"
|
|
|
|
#include "rioioctl.h"
|
|
|
|
#include "param.h"
|
|
|
|
#include "protsts.h"
|
|
|
|
#include "rioboard.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include "rio_linux.h"
|
|
|
|
|
|
|
|
/* I don't think that this driver can handle more than 512 ports on
|
|
|
|
one machine. Specialix specifies max 4 boards in one machine. I don't
|
|
|
|
know why. If you want to try anyway you'll have to increase the number
|
|
|
|
of boards in rio.h. You'll have to allocate more majors if you need
|
|
|
|
more than 512 ports.... */
|
|
|
|
|
|
|
|
#ifndef RIO_NORMAL_MAJOR0
|
|
|
|
/* This allows overriding on the compiler commandline, or in a "major.h"
|
|
|
|
include or something like that */
|
|
|
|
#define RIO_NORMAL_MAJOR0 154
|
|
|
|
#define RIO_NORMAL_MAJOR1 156
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8
|
|
|
|
#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
|
|
|
|
#endif
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
#ifndef RIO_WINDOW_LEN
|
2005-04-17 05:20:36 +07:00
|
|
|
#define RIO_WINDOW_LEN 0x10000
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/* Configurable options:
|
|
|
|
(Don't be too sure that it'll work if you toggle them) */
|
|
|
|
|
|
|
|
/* Am I paranoid or not ? ;-) */
|
|
|
|
#undef RIO_PARANOIA_CHECK
|
|
|
|
|
|
|
|
|
|
|
|
/* 20 -> 2000 per second. The card should rate-limit interrupts at 1000
|
|
|
|
Hz, but it is user configurable. I don't recommend going above 1000
|
|
|
|
Hz. The interrupt ratelimit might trigger if the interrupt is
|
|
|
|
shared with a very active other device.
|
|
|
|
undef this if you want to disable the check....
|
|
|
|
*/
|
|
|
|
#define IRQ_RATE_LIMIT 200
|
|
|
|
|
|
|
|
|
|
|
|
/* These constants are derived from SCO Source */
|
|
|
|
static struct Conf
|
2006-01-12 03:17:49 +07:00
|
|
|
RIOConf = {
|
|
|
|
/* locator */ "RIO Config here",
|
|
|
|
/* startuptime */ HZ * 2,
|
|
|
|
/* how long to wait for card to run */
|
|
|
|
/* slowcook */ 0,
|
|
|
|
/* TRUE -> always use line disc. */
|
|
|
|
/* intrpolltime */ 1,
|
|
|
|
/* The frequency of OUR polls */
|
|
|
|
/* breakinterval */ 25,
|
|
|
|
/* x10 mS XXX: units seem to be 1ms not 10! -- REW */
|
|
|
|
/* timer */ 10,
|
|
|
|
/* mS */
|
|
|
|
/* RtaLoadBase */ 0x7000,
|
|
|
|
/* HostLoadBase */ 0x7C00,
|
|
|
|
/* XpHz */ 5,
|
|
|
|
/* number of Xprint hits per second */
|
|
|
|
/* XpCps */ 120,
|
|
|
|
/* Xprint characters per second */
|
|
|
|
/* XpOn */ "\033d#",
|
|
|
|
/* start Xprint for a wyse 60 */
|
|
|
|
/* XpOff */ "\024",
|
|
|
|
/* end Xprint for a wyse 60 */
|
|
|
|
/* MaxXpCps */ 2000,
|
|
|
|
/* highest Xprint speed */
|
|
|
|
/* MinXpCps */ 10,
|
|
|
|
/* slowest Xprint speed */
|
|
|
|
/* SpinCmds */ 1,
|
|
|
|
/* non-zero for mega fast boots */
|
|
|
|
/* First Addr */ 0x0A0000,
|
|
|
|
/* First address to look at */
|
|
|
|
/* Last Addr */ 0xFF0000,
|
|
|
|
/* Last address looked at */
|
|
|
|
/* BufferSize */ 1024,
|
|
|
|
/* Bytes per port of buffering */
|
|
|
|
/* LowWater */ 256,
|
|
|
|
/* how much data left before wakeup */
|
|
|
|
/* LineLength */ 80,
|
|
|
|
/* how wide is the console? */
|
|
|
|
/* CmdTimeout */ HZ,
|
|
|
|
/* how long a close command may take */
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Function prototypes */
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void rio_disable_tx_interrupts(void *ptr);
|
|
|
|
static void rio_enable_tx_interrupts(void *ptr);
|
|
|
|
static void rio_disable_rx_interrupts(void *ptr);
|
|
|
|
static void rio_enable_rx_interrupts(void *ptr);
|
|
|
|
static int rio_get_CD(void *ptr);
|
|
|
|
static void rio_shutdown_port(void *ptr);
|
|
|
|
static int rio_set_real_termios(void *ptr);
|
|
|
|
static void rio_hungup(void *ptr);
|
|
|
|
static void rio_close(void *ptr);
|
|
|
|
static int rio_chars_in_buffer(void *ptr);
|
|
|
|
static int rio_fw_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
|
2005-04-17 05:20:36 +07:00
|
|
|
static int rio_init_drivers(void);
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void my_hd(void *addr, int len);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
static struct tty_driver *rio_driver, *rio_driver2;
|
|
|
|
|
|
|
|
/* The name "p" is a bit non-descript. But that's what the rio-lynxos
|
|
|
|
sources use all over the place. */
|
|
|
|
struct rio_info *p;
|
|
|
|
|
|
|
|
int rio_debug;
|
|
|
|
|
|
|
|
|
|
|
|
/* You can have the driver poll your card.
|
|
|
|
- Set rio_poll to 1 to poll every timer tick (10ms on Intel).
|
|
|
|
This is used when the card cannot use an interrupt for some reason.
|
|
|
|
*/
|
|
|
|
static int rio_poll = 1;
|
|
|
|
|
|
|
|
|
|
|
|
/* These are the only open spaces in my computer. Yours may have more
|
|
|
|
or less.... */
|
2006-01-12 03:17:49 +07:00
|
|
|
static int rio_probe_addrs[] = { 0xc0000, 0xd0000, 0xe0000 };
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-10 11:54:02 +07:00
|
|
|
#define NR_RIO_ADDRS ARRAY_SIZE(rio_probe_addrs)
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
|
|
|
|
/* Set the mask to all-ones. This alas, only supports 32 interrupts.
|
|
|
|
Some architectures may need more. -- Changed to LONG to
|
|
|
|
support up to 64 bits on 64bit architectures. -- REW 20/06/99 */
|
2005-05-01 22:59:29 +07:00
|
|
|
static long rio_irqmask = -1;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
MODULE_AUTHOR("Rogier Wolff <R.E.Wolff@bitwizard.nl>, Patrick van de Lageweg <patrick@bitwizard.nl>");
|
|
|
|
MODULE_DESCRIPTION("RIO driver");
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
module_param(rio_poll, int, 0);
|
|
|
|
module_param(rio_debug, int, 0644);
|
|
|
|
module_param(rio_irqmask, long, 0);
|
|
|
|
|
|
|
|
static struct real_driver rio_real_driver = {
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_disable_tx_interrupts,
|
|
|
|
rio_enable_tx_interrupts,
|
|
|
|
rio_disable_rx_interrupts,
|
|
|
|
rio_enable_rx_interrupts,
|
|
|
|
rio_get_CD,
|
|
|
|
rio_shutdown_port,
|
|
|
|
rio_set_real_termios,
|
|
|
|
rio_chars_in_buffer,
|
|
|
|
rio_close,
|
|
|
|
rio_hungup,
|
|
|
|
NULL
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Firmware loader driver specific routines
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2006-07-03 14:24:21 +07:00
|
|
|
static const struct file_operations rio_fw_fops = {
|
2006-01-12 03:17:49 +07:00
|
|
|
.owner = THIS_MODULE,
|
|
|
|
.ioctl = rio_fw_ioctl,
|
2005-04-17 05:20:36 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct miscdevice rio_fw_device = {
|
|
|
|
RIOCTL_MISC_MINOR, "rioctl", &rio_fw_fops
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef RIO_PARANOIA_CHECK
|
|
|
|
|
|
|
|
/* This doesn't work. Who's paranoid around here? Not me! */
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static inline int rio_paranoia_check(struct rio_port const *port, char *name, const char *routine)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static const char *badmagic = KERN_ERR "rio: Warning: bad rio port magic number for device %s in %s\n";
|
|
|
|
static const char *badinfo = KERN_ERR "rio: Warning: null rio port for device %s in %s\n";
|
|
|
|
|
|
|
|
if (!port) {
|
|
|
|
printk(badinfo, name, routine);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (port->magic != RIO_MAGIC) {
|
|
|
|
printk(badmagic, name, routine);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define rio_paranoia_check(a,b,c) 0
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
2006-01-12 03:17:49 +07:00
|
|
|
static void my_hd(void *ad, int len)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
int i, j, ch;
|
|
|
|
unsigned char *addr = ad;
|
|
|
|
|
|
|
|
for (i = 0; i < len; i += 16) {
|
2006-03-24 18:18:28 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_PARAM, "%08lx ", (unsigned long) addr + i);
|
2006-01-12 03:17:49 +07:00
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
rio_dprintk(RIO_DEBUG_PARAM, "%02x %s", addr[j + i], (j == 7) ? " " : "");
|
|
|
|
}
|
|
|
|
for (j = 0; j < 16; j++) {
|
|
|
|
ch = addr[j + i];
|
|
|
|
rio_dprintk(RIO_DEBUG_PARAM, "%c", (ch < 0x20) ? '.' : ((ch > 0x7f) ? '.' : ch));
|
|
|
|
}
|
|
|
|
rio_dprintk(RIO_DEBUG_PARAM, "\n");
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
#else
|
|
|
|
#define my_hd(ad,len) do{/* nothing*/ } while (0)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
/* Delay a number of jiffies, allowing a signal to interrupt */
|
|
|
|
int RIODelay(struct Port *PortP, int njiffies)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_DELAY, "delaying %d jiffies\n", njiffies);
|
|
|
|
msleep_interruptible(jiffies_to_msecs(njiffies));
|
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
if (signal_pending(current))
|
|
|
|
return RIO_FAIL;
|
|
|
|
else
|
|
|
|
return !RIO_FAIL;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
/* Delay a number of jiffies, disallowing a signal to interrupt */
|
|
|
|
int RIODelay_ni(struct Port *PortP, int njiffies)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_DELAY, "delaying %d jiffies (ni)\n", njiffies);
|
|
|
|
msleep(jiffies_to_msecs(njiffies));
|
|
|
|
func_exit();
|
|
|
|
return !RIO_FAIL;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2006-05-27 11:15:09 +07:00
|
|
|
void rio_copy_to_card(void *from, void __iomem *to, int len)
|
2006-03-24 18:18:28 +07:00
|
|
|
{
|
2006-05-27 12:48:08 +07:00
|
|
|
rio_copy_toio(to, from, len);
|
2006-03-24 18:18:28 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
int rio_minor(struct tty_struct *tty)
|
|
|
|
{
|
|
|
|
return tty->index + (tty->driver == rio_driver) ? 0 : 256;
|
|
|
|
}
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static int rio_set_real_termios(void *ptr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2008-04-30 14:53:57 +07:00
|
|
|
return RIOParam((struct Port *) ptr, RIOC_CONFIG, 1, 1);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void rio_reset_interrupt(struct Host *HostP)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
switch (HostP->Type) {
|
|
|
|
case RIO_AT:
|
|
|
|
case RIO_MCA:
|
|
|
|
case RIO_PCI:
|
2006-03-24 18:18:28 +07:00
|
|
|
writeb(0xFF, &HostP->ResetInt);
|
2006-01-12 03:17:49 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 20:55:46 +07:00
|
|
|
static irqreturn_t rio_interrupt(int irq, void *ptr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
struct Host *HostP;
|
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-10-07 02:00:58 +07:00
|
|
|
HostP = ptr; /* &p->RIOHosts[(long)ptr]; */
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_IFLOW, "rio: enter rio_interrupt (%d/%d)\n", irq, HostP->Ivec);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
/* AAargh! The order in which to do these things is essential and
|
|
|
|
not trivial.
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
- hardware twiddling goes before "recursive". Otherwise when we
|
|
|
|
poll the card, and a recursive interrupt happens, we won't
|
|
|
|
ack the card, so it might keep on interrupting us. (especially
|
|
|
|
level sensitive interrupt systems like PCI).
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
- Rate limit goes before hardware twiddling. Otherwise we won't
|
|
|
|
catch a card that has gone bonkers.
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
- The "initialized" test goes after the hardware twiddling. Otherwise
|
|
|
|
the card will stick us in the interrupt routine again.
|
|
|
|
|
|
|
|
- The initialized test goes before recursive.
|
|
|
|
*/
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_IFLOW, "rio: We've have noticed the interrupt\n");
|
|
|
|
if (HostP->Ivec == irq) {
|
|
|
|
/* Tell the card we've noticed the interrupt. */
|
|
|
|
rio_reset_interrupt(HostP);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((HostP->Flags & RUN_STATE) != RC_RUNNING)
|
|
|
|
return IRQ_HANDLED;
|
|
|
|
|
|
|
|
if (test_and_set_bit(RIO_BOARD_INTR_LOCK, &HostP->locks)) {
|
2006-03-24 18:18:28 +07:00
|
|
|
printk(KERN_ERR "Recursive interrupt! (host %p/irq%d)\n", ptr, HostP->Ivec);
|
2006-01-12 03:17:49 +07:00
|
|
|
return IRQ_HANDLED;
|
|
|
|
}
|
|
|
|
|
2006-10-07 02:00:58 +07:00
|
|
|
RIOServiceHost(p, HostP);
|
2006-01-12 03:17:49 +07:00
|
|
|
|
2006-03-24 18:18:28 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_IFLOW, "riointr() doing host %p type %d\n", ptr, HostP->Type);
|
2006-01-12 03:17:49 +07:00
|
|
|
|
|
|
|
clear_bit(RIO_BOARD_INTR_LOCK, &HostP->locks);
|
|
|
|
rio_dprintk(RIO_DEBUG_IFLOW, "rio: exit rio_interrupt (%d/%d)\n", irq, HostP->Ivec);
|
|
|
|
func_exit();
|
|
|
|
return IRQ_HANDLED;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void rio_pollfunc(unsigned long data)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
IRQ: Maintain regs pointer globally rather than passing to IRQ handlers
Maintain a per-CPU global "struct pt_regs *" variable which can be used instead
of passing regs around manually through all ~1800 interrupt handlers in the
Linux kernel.
The regs pointer is used in few places, but it potentially costs both stack
space and code to pass it around. On the FRV arch, removing the regs parameter
from all the genirq function results in a 20% speed up of the IRQ exit path
(ie: from leaving timer_interrupt() to leaving do_IRQ()).
Where appropriate, an arch may override the generic storage facility and do
something different with the variable. On FRV, for instance, the address is
maintained in GR28 at all times inside the kernel as part of general exception
handling.
Having looked over the code, it appears that the parameter may be handed down
through up to twenty or so layers of functions. Consider a USB character
device attached to a USB hub, attached to a USB controller that posts its
interrupts through a cascaded auxiliary interrupt controller. A character
device driver may want to pass regs to the sysrq handler through the input
layer which adds another few layers of parameter passing.
I've build this code with allyesconfig for x86_64 and i386. I've runtested the
main part of the code on FRV and i386, though I can't test most of the drivers.
I've also done partial conversion for powerpc and MIPS - these at least compile
with minimal configurations.
This will affect all archs. Mostly the changes should be relatively easy.
Take do_IRQ(), store the regs pointer at the beginning, saving the old one:
struct pt_regs *old_regs = set_irq_regs(regs);
And put the old one back at the end:
set_irq_regs(old_regs);
Don't pass regs through to generic_handle_irq() or __do_IRQ().
In timer_interrupt(), this sort of change will be necessary:
- update_process_times(user_mode(regs));
- profile_tick(CPU_PROFILING, regs);
+ update_process_times(user_mode(get_irq_regs()));
+ profile_tick(CPU_PROFILING);
I'd like to move update_process_times()'s use of get_irq_regs() into itself,
except that i386, alone of the archs, uses something other than user_mode().
Some notes on the interrupt handling in the drivers:
(*) input_dev() is now gone entirely. The regs pointer is no longer stored in
the input_dev struct.
(*) finish_unlinks() in drivers/usb/host/ohci-q.c needs checking. It does
something different depending on whether it's been supplied with a regs
pointer or not.
(*) Various IRQ handler function pointers have been moved to type
irq_handler_t.
Signed-Off-By: David Howells <dhowells@redhat.com>
(cherry picked from 1b16e7ac850969f38b375e511e3fa2f474a33867 commit)
2006-10-05 20:55:46 +07:00
|
|
|
rio_interrupt(0, &p->RIOHosts[data]);
|
2007-02-12 15:52:31 +07:00
|
|
|
mod_timer(&p->RIOHosts[data].timer, jiffies + rio_poll);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ********************************************************************** *
|
|
|
|
* Here are the routines that actually *
|
|
|
|
* interface with the generic_serial driver *
|
|
|
|
* ********************************************************************** */
|
|
|
|
|
|
|
|
/* Ehhm. I don't know how to fiddle with interrupts on the Specialix
|
|
|
|
cards. .... Hmm. Ok I figured it out. You don't. -- REW */
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void rio_disable_tx_interrupts(void *ptr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
/* port->gs.flags &= ~GS_TX_INTEN; */
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void rio_enable_tx_interrupts(void *ptr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
struct Port *PortP = ptr;
|
|
|
|
/* int hn; */
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
/* hn = PortP->HostP - p->RIOHosts;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk (RIO_DEBUG_TTY, "Pushing host %d\n", hn);
|
|
|
|
rio_interrupt (-1,(void *) hn, NULL); */
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
RIOTxEnable((char *) PortP);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
/*
|
|
|
|
* In general we cannot count on "tx empty" interrupts, although
|
|
|
|
* the interrupt routine seems to be able to tell the difference.
|
|
|
|
*/
|
|
|
|
PortP->gs.flags &= ~GS_TX_INTEN;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void rio_disable_rx_interrupts(void *ptr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void rio_enable_rx_interrupts(void *ptr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
/* struct rio_port *port = ptr; */
|
|
|
|
func_enter();
|
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Jeez. Isn't this simple? */
|
2006-01-12 03:17:49 +07:00
|
|
|
static int rio_get_CD(void *ptr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
struct Port *PortP = ptr;
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
func_enter();
|
2008-04-30 14:53:57 +07:00
|
|
|
rv = (PortP->ModemState & RIOC_MSVR1_CD) != 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "Getting CD status: %d\n", rv);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_exit();
|
|
|
|
return rv;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Jeez. Isn't this simple? Actually, we can sync with the actual port
|
|
|
|
by just pushing stuff into the queue going to the port... */
|
2006-01-12 03:17:49 +07:00
|
|
|
static int rio_chars_in_buffer(void *ptr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_exit();
|
|
|
|
return 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Nothing special here... */
|
2006-01-12 03:17:49 +07:00
|
|
|
static void rio_shutdown_port(void *ptr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
struct Port *PortP;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
PortP = (struct Port *) ptr;
|
|
|
|
PortP->gs.tty = NULL;
|
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* I haven't the foggiest why the decrement use count has to happen
|
|
|
|
here. The whole linux serial drivers stuff needs to be redesigned.
|
|
|
|
My guess is that this is a hack to minimize the impact of a bug
|
|
|
|
elsewhere. Thinking about it some more. (try it sometime) Try
|
|
|
|
running minicom on a serial port that is driven by a modularized
|
|
|
|
driver. Have the modem hangup. Then remove the driver module. Then
|
|
|
|
exit minicom. I expect an "oops". -- REW */
|
2006-01-12 03:17:49 +07:00
|
|
|
static void rio_hungup(void *ptr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
struct Port *PortP;
|
|
|
|
|
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
PortP = (struct Port *) ptr;
|
|
|
|
PortP->gs.tty = NULL;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* The standard serial_close would become shorter if you'd wrap it like
|
|
|
|
this.
|
|
|
|
rs_close (...){save_flags;cli;real_close();dec_use_count;restore_flags;}
|
|
|
|
*/
|
2006-01-12 03:17:49 +07:00
|
|
|
static void rio_close(void *ptr)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
struct Port *PortP;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
PortP = (struct Port *) ptr;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
riotclose(ptr);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
if (PortP->gs.count) {
|
|
|
|
printk(KERN_ERR "WARNING port count:%d\n", PortP->gs.count);
|
|
|
|
PortP->gs.count = 0;
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
PortP->gs.tty = NULL;
|
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static int rio_fw_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
int rc = 0;
|
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
/* The "dev" argument isn't used. */
|
2006-05-27 11:08:25 +07:00
|
|
|
rc = riocontrol(p, 0, cmd, arg, capable(CAP_SYS_ADMIN));
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_exit();
|
|
|
|
return rc;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
extern int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static int rio_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-05-27 11:08:25 +07:00
|
|
|
void __user *argp = (void __user *)arg;
|
2006-01-12 03:17:49 +07:00
|
|
|
int rc;
|
|
|
|
struct Port *PortP;
|
|
|
|
int ival;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
PortP = (struct Port *) tty->driver_data;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
rc = 0;
|
|
|
|
switch (cmd) {
|
|
|
|
case TIOCSSOFTCAR:
|
2006-05-27 11:08:25 +07:00
|
|
|
if ((rc = get_user(ival, (unsigned __user *) argp)) == 0) {
|
2006-01-12 03:17:49 +07:00
|
|
|
tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (ival ? CLOCAL : 0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TIOCGSERIAL:
|
|
|
|
rc = -EFAULT;
|
2006-05-27 11:08:25 +07:00
|
|
|
if (access_ok(VERIFY_WRITE, argp, sizeof(struct serial_struct)))
|
|
|
|
rc = gs_getserial(&PortP->gs, argp);
|
2006-01-12 03:17:49 +07:00
|
|
|
break;
|
|
|
|
case TCSBRK:
|
|
|
|
if (PortP->State & RIO_DELETED) {
|
|
|
|
rio_dprintk(RIO_DEBUG_TTY, "BREAK on deleted RTA\n");
|
|
|
|
rc = -EIO;
|
|
|
|
} else {
|
2008-04-30 14:53:57 +07:00
|
|
|
if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2, 250) ==
|
|
|
|
RIO_FAIL) {
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
|
|
|
|
rc = -EIO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TCSBRKP:
|
|
|
|
if (PortP->State & RIO_DELETED) {
|
|
|
|
rio_dprintk(RIO_DEBUG_TTY, "BREAK on deleted RTA\n");
|
|
|
|
rc = -EIO;
|
|
|
|
} else {
|
|
|
|
int l;
|
|
|
|
l = arg ? arg * 100 : 250;
|
|
|
|
if (l > 255)
|
|
|
|
l = 255;
|
2008-04-30 14:53:57 +07:00
|
|
|
if (RIOShortCommand(p, PortP, RIOC_SBREAK, 2,
|
|
|
|
arg ? arg * 100 : 250) == RIO_FAIL) {
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n");
|
|
|
|
rc = -EIO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case TIOCSSERIAL:
|
|
|
|
rc = -EFAULT;
|
2006-05-27 11:08:25 +07:00
|
|
|
if (access_ok(VERIFY_READ, argp, sizeof(struct serial_struct)))
|
|
|
|
rc = gs_setserial(&PortP->gs, argp);
|
2006-01-12 03:17:49 +07:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rc = -ENOIOCTLCMD;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
func_exit();
|
|
|
|
return rc;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* The throttle/unthrottle scheme for the Specialix card is different
|
|
|
|
* from other drivers and deserves some explanation.
|
|
|
|
* The Specialix hardware takes care of XON/XOFF
|
|
|
|
* and CTS/RTS flow control itself. This means that all we have to
|
|
|
|
* do when signalled by the upper tty layer to throttle/unthrottle is
|
|
|
|
* to make a note of it here. When we come to read characters from the
|
|
|
|
* rx buffers on the card (rio_receive_chars()) we look to see if the
|
|
|
|
* upper layer can accept more (as noted here in rio_rx_throt[]).
|
|
|
|
* If it can't we simply don't remove chars from the cards buffer.
|
|
|
|
* When the tty layer can accept chars, we again note that here and when
|
|
|
|
* rio_receive_chars() is called it will remove them from the cards buffer.
|
|
|
|
* The card will notice that a ports buffer has drained below some low
|
|
|
|
* water mark and will unflow control the line itself, using whatever
|
|
|
|
* flow control scheme is in use for that port. -- Simon Allen
|
|
|
|
*/
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void rio_throttle(struct tty_struct *tty)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
struct Port *port = (struct Port *) tty->driver_data;
|
|
|
|
|
|
|
|
func_enter();
|
|
|
|
/* If the port is using any type of input flow
|
|
|
|
* control then throttle the port.
|
|
|
|
*/
|
|
|
|
|
|
|
|
if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty))) {
|
|
|
|
port->State |= RIO_THROTTLE_RX;
|
|
|
|
}
|
|
|
|
|
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void rio_unthrottle(struct tty_struct *tty)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
struct Port *port = (struct Port *) tty->driver_data;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
|
|
|
/* Always unthrottle even if flow control is not enabled on
|
|
|
|
* this port in case we disabled flow control while the port
|
|
|
|
* was throttled
|
|
|
|
*/
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
port->State &= ~RIO_THROTTLE_RX;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_exit();
|
|
|
|
return;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* ********************************************************************** *
|
|
|
|
* Here are the initialization routines. *
|
|
|
|
* ********************************************************************** */
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static struct vpd_prom *get_VPD_PROM(struct Host *hp)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
static struct vpd_prom vpdp;
|
|
|
|
char *p;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
func_enter();
|
|
|
|
rio_dprintk(RIO_DEBUG_PROBE, "Going to verify vpd prom at %p.\n", hp->Caddr + RIO_VPD_ROM);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
p = (char *) &vpdp;
|
|
|
|
for (i = 0; i < sizeof(struct vpd_prom); i++)
|
|
|
|
*p++ = readb(hp->Caddr + RIO_VPD_ROM + i * 2);
|
|
|
|
/* read_rio_byte (hp, RIO_VPD_ROM + i*2); */
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
/* Terminate the identifier string.
|
|
|
|
*** requires one extra byte in struct vpd_prom *** */
|
|
|
|
*p++ = 0;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
if (rio_debug & RIO_DEBUG_PROBE)
|
|
|
|
my_hd((char *) &vpdp, 0x20);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
return &vpdp;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2006-10-02 16:17:18 +07:00
|
|
|
static const struct tty_operations rio_ops = {
|
2006-01-12 03:17:49 +07:00
|
|
|
.open = riotopen,
|
2005-04-17 05:20:36 +07:00
|
|
|
.close = gs_close,
|
|
|
|
.write = gs_write,
|
|
|
|
.put_char = gs_put_char,
|
|
|
|
.flush_chars = gs_flush_chars,
|
|
|
|
.write_room = gs_write_room,
|
|
|
|
.chars_in_buffer = gs_chars_in_buffer,
|
|
|
|
.flush_buffer = gs_flush_buffer,
|
|
|
|
.ioctl = rio_ioctl,
|
|
|
|
.throttle = rio_throttle,
|
|
|
|
.unthrottle = rio_unthrottle,
|
|
|
|
.set_termios = gs_set_termios,
|
|
|
|
.stop = gs_stop,
|
|
|
|
.start = gs_start,
|
|
|
|
.hangup = gs_hangup,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int rio_init_drivers(void)
|
|
|
|
{
|
|
|
|
int error = -ENOMEM;
|
|
|
|
|
|
|
|
rio_driver = alloc_tty_driver(256);
|
|
|
|
if (!rio_driver)
|
|
|
|
goto out;
|
|
|
|
rio_driver2 = alloc_tty_driver(256);
|
|
|
|
if (!rio_driver2)
|
|
|
|
goto out1;
|
|
|
|
|
|
|
|
func_enter();
|
|
|
|
|
|
|
|
rio_driver->owner = THIS_MODULE;
|
|
|
|
rio_driver->driver_name = "specialix_rio";
|
|
|
|
rio_driver->name = "ttySR";
|
|
|
|
rio_driver->major = RIO_NORMAL_MAJOR0;
|
|
|
|
rio_driver->type = TTY_DRIVER_TYPE_SERIAL;
|
|
|
|
rio_driver->subtype = SERIAL_TYPE_NORMAL;
|
|
|
|
rio_driver->init_termios = tty_std_termios;
|
|
|
|
rio_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
|
|
|
|
rio_driver->flags = TTY_DRIVER_REAL_RAW;
|
|
|
|
tty_set_operations(rio_driver, &rio_ops);
|
|
|
|
|
|
|
|
rio_driver2->owner = THIS_MODULE;
|
|
|
|
rio_driver2->driver_name = "specialix_rio";
|
|
|
|
rio_driver2->name = "ttySR";
|
|
|
|
rio_driver2->major = RIO_NORMAL_MAJOR1;
|
|
|
|
rio_driver2->type = TTY_DRIVER_TYPE_SERIAL;
|
|
|
|
rio_driver2->subtype = SERIAL_TYPE_NORMAL;
|
|
|
|
rio_driver2->init_termios = tty_std_termios;
|
|
|
|
rio_driver2->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
|
|
|
|
rio_driver2->flags = TTY_DRIVER_REAL_RAW;
|
|
|
|
tty_set_operations(rio_driver2, &rio_ops);
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "set_termios = %p\n", gs_set_termios);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
if ((error = tty_register_driver(rio_driver)))
|
|
|
|
goto out2;
|
|
|
|
if ((error = tty_register_driver(rio_driver2)))
|
|
|
|
goto out3;
|
|
|
|
func_exit();
|
|
|
|
return 0;
|
2006-01-12 03:17:49 +07:00
|
|
|
out3:
|
2005-04-17 05:20:36 +07:00
|
|
|
tty_unregister_driver(rio_driver);
|
2006-01-12 03:17:49 +07:00
|
|
|
out2:
|
2005-04-17 05:20:36 +07:00
|
|
|
put_tty_driver(rio_driver2);
|
2006-01-12 03:17:49 +07:00
|
|
|
out1:
|
2005-04-17 05:20:36 +07:00
|
|
|
put_tty_driver(rio_driver);
|
2006-01-12 03:17:49 +07:00
|
|
|
out:
|
|
|
|
printk(KERN_ERR "rio: Couldn't register a rio driver, error = %d\n", error);
|
2005-04-17 05:20:36 +07:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void *ckmalloc(int size)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
void *p;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 15:49:03 +07:00
|
|
|
p = kzalloc(size, GFP_KERNEL);
|
2006-01-12 03:17:49 +07:00
|
|
|
return p;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static int rio_init_datastructures(void)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
int i;
|
|
|
|
struct Port *port;
|
|
|
|
func_enter();
|
|
|
|
|
|
|
|
/* Many drivers statically allocate the maximum number of ports
|
|
|
|
There is no reason not to allocate them dynamically. Is there? -- REW */
|
|
|
|
/* However, the RIO driver allows users to configure their first
|
|
|
|
RTA as the ports numbered 504-511. We therefore need to allocate
|
|
|
|
the whole range. :-( -- REW */
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
#define RI_SZ sizeof(struct rio_info)
|
|
|
|
#define HOST_SZ sizeof(struct Host)
|
|
|
|
#define PORT_SZ sizeof(struct Port *)
|
|
|
|
#define TMIO_SZ sizeof(struct termios *)
|
2006-03-24 18:18:28 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "getting : %Zd %Zd %Zd %Zd %Zd bytes\n", RI_SZ, RIO_HOSTS * HOST_SZ, RIO_PORTS * PORT_SZ, RIO_PORTS * TMIO_SZ, RIO_PORTS * TMIO_SZ);
|
2006-01-12 03:17:49 +07:00
|
|
|
|
|
|
|
if (!(p = ckmalloc(RI_SZ)))
|
|
|
|
goto free0;
|
|
|
|
if (!(p->RIOHosts = ckmalloc(RIO_HOSTS * HOST_SZ)))
|
|
|
|
goto free1;
|
|
|
|
if (!(p->RIOPortp = ckmalloc(RIO_PORTS * PORT_SZ)))
|
|
|
|
goto free2;
|
|
|
|
p->RIOConf = RIOConf;
|
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "Got : %p %p %p\n", p, p->RIOHosts, p->RIOPortp);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
#if 1
|
2006-01-12 03:17:49 +07:00
|
|
|
for (i = 0; i < RIO_PORTS; i++) {
|
|
|
|
port = p->RIOPortp[i] = ckmalloc(sizeof(struct Port));
|
|
|
|
if (!port) {
|
|
|
|
goto free6;
|
|
|
|
}
|
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "initing port %d (%d)\n", i, port->Mapped);
|
|
|
|
port->PortNum = i;
|
|
|
|
port->gs.magic = RIO_MAGIC;
|
|
|
|
port->gs.close_delay = HZ / 2;
|
|
|
|
port->gs.closing_wait = 30 * HZ;
|
|
|
|
port->gs.rd = &rio_real_driver;
|
|
|
|
spin_lock_init(&port->portSem);
|
|
|
|
/*
|
|
|
|
* Initializing wait queue
|
|
|
|
*/
|
|
|
|
init_waitqueue_head(&port->gs.open_wait);
|
|
|
|
init_waitqueue_head(&port->gs.close_wait);
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
#else
|
2006-01-12 03:17:49 +07:00
|
|
|
/* We could postpone initializing them to when they are configured. */
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
if (rio_debug & RIO_DEBUG_INIT) {
|
|
|
|
my_hd(&rio_real_driver, sizeof(rio_real_driver));
|
|
|
|
}
|
|
|
|
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_exit();
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
free6:for (i--; i >= 0; i--)
|
|
|
|
kfree(p->RIOPortp[i]);
|
2005-04-17 05:20:36 +07:00
|
|
|
/*free5:
|
|
|
|
free4:
|
2006-01-12 03:17:49 +07:00
|
|
|
free3:*/ kfree(p->RIOPortp);
|
|
|
|
free2:kfree(p->RIOHosts);
|
|
|
|
free1:
|
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "Not enough memory! %p %p %p\n", p, p->RIOHosts, p->RIOPortp);
|
|
|
|
kfree(p);
|
|
|
|
free0:
|
|
|
|
return -ENOMEM;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void __exit rio_release_drivers(void)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
|
|
|
tty_unregister_driver(rio_driver2);
|
|
|
|
tty_unregister_driver(rio_driver);
|
|
|
|
put_tty_driver(rio_driver2);
|
|
|
|
put_tty_driver(rio_driver);
|
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_PCI
|
|
|
|
/* This was written for SX, but applies to RIO too...
|
|
|
|
(including bugs....)
|
|
|
|
|
|
|
|
There is another bit besides Bit 17. Turning that bit off
|
|
|
|
(on boards shipped with the fix in the eeprom) results in a
|
|
|
|
hang on the next access to the card.
|
2006-01-12 03:17:49 +07:00
|
|
|
*/
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
/********************************************************
|
|
|
|
* Setting bit 17 in the CNTRL register of the PLX 9050 *
|
|
|
|
* chip forces a retry on writes while a read is pending.*
|
|
|
|
* This is to prevent the card locking up on Intel Xeon *
|
|
|
|
* multiprocessor systems with the NX chipset. -- NV *
|
|
|
|
********************************************************/
|
|
|
|
|
|
|
|
/* Newer cards are produced with this bit set from the configuration
|
|
|
|
EEprom. As the bit is read/write for the CPU, we can fix it here,
|
|
|
|
if we detect that it isn't set correctly. -- REW */
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void fix_rio_pci(struct pci_dev *pdev)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-03-24 18:18:28 +07:00
|
|
|
unsigned long hwbase;
|
2006-05-27 11:08:25 +07:00
|
|
|
unsigned char __iomem *rebase;
|
2006-01-12 03:17:49 +07:00
|
|
|
unsigned int t;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
#define CNTRL_REG_OFFSET 0x50
|
|
|
|
#define CNTRL_REG_GOODVALUE 0x18260000
|
|
|
|
|
2006-03-24 18:18:28 +07:00
|
|
|
hwbase = pci_resource_start(pdev, 0);
|
|
|
|
rebase = ioremap(hwbase, 0x80);
|
2006-01-12 03:17:49 +07:00
|
|
|
t = readl(rebase + CNTRL_REG_OFFSET);
|
|
|
|
if (t != CNTRL_REG_GOODVALUE) {
|
|
|
|
printk(KERN_DEBUG "rio: performing cntrl reg fix: %08x -> %08x\n", t, CNTRL_REG_GOODVALUE);
|
|
|
|
writel(CNTRL_REG_GOODVALUE, rebase + CNTRL_REG_OFFSET);
|
|
|
|
}
|
2006-03-24 18:18:28 +07:00
|
|
|
iounmap(rebase);
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static int __init rio_init(void)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
int found = 0;
|
|
|
|
int i;
|
|
|
|
struct Host *hp;
|
|
|
|
int retval;
|
|
|
|
struct vpd_prom *vpdp;
|
|
|
|
int okboard;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
#ifdef CONFIG_PCI
|
2006-01-12 03:17:49 +07:00
|
|
|
struct pci_dev *pdev = NULL;
|
|
|
|
unsigned short tshort;
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_enter();
|
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "Initing rio module... (rio_debug=%d)\n", rio_debug);
|
|
|
|
|
|
|
|
if (abs((long) (&rio_debug) - rio_debug) < 0x10000) {
|
|
|
|
printk(KERN_WARNING "rio: rio_debug is an address, instead of a value. " "Assuming -1. Was %x/%p.\n", rio_debug, &rio_debug);
|
|
|
|
rio_debug = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (misc_register(&rio_fw_device) < 0) {
|
|
|
|
printk(KERN_ERR "RIO: Unable to register firmware loader driver.\n");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = rio_init_datastructures();
|
|
|
|
if (retval < 0) {
|
|
|
|
misc_deregister(&rio_fw_device);
|
|
|
|
return retval;
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
#ifdef CONFIG_PCI
|
2006-01-12 03:17:49 +07:00
|
|
|
/* First look for the JET devices: */
|
|
|
|
while ((pdev = pci_get_device(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, pdev))) {
|
2006-03-24 18:18:32 +07:00
|
|
|
u32 tint;
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
if (pci_enable_device(pdev))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Specialix has a whole bunch of cards with
|
|
|
|
0x2000 as the device ID. They say its because
|
|
|
|
the standard requires it. Stupid standard. */
|
|
|
|
/* It seems that reading a word doesn't work reliably on 2.0.
|
|
|
|
Also, reading a non-aligned dword doesn't work. So we read the
|
|
|
|
whole dword at 0x2c and extract the word at 0x2e (SUBSYSTEM_ID)
|
|
|
|
ourselves */
|
|
|
|
pci_read_config_dword(pdev, 0x2c, &tint);
|
|
|
|
tshort = (tint >> 16) & 0xffff;
|
|
|
|
rio_dprintk(RIO_DEBUG_PROBE, "Got a specialix card: %x.\n", tint);
|
|
|
|
if (tshort != 0x0100) {
|
|
|
|
rio_dprintk(RIO_DEBUG_PROBE, "But it's not a RIO card (%d)...\n", tshort);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
rio_dprintk(RIO_DEBUG_PROBE, "cp1\n");
|
|
|
|
|
|
|
|
hp = &p->RIOHosts[p->RIONumHosts];
|
2006-03-24 18:18:32 +07:00
|
|
|
hp->PaddrP = pci_resource_start(pdev, 2);
|
2006-01-12 03:17:49 +07:00
|
|
|
hp->Ivec = pdev->irq;
|
|
|
|
if (((1 << hp->Ivec) & rio_irqmask) == 0)
|
|
|
|
hp->Ivec = 0;
|
|
|
|
hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
|
2006-05-27 11:08:25 +07:00
|
|
|
hp->CardP = (struct DpRam __iomem *) hp->Caddr;
|
2006-01-12 03:17:49 +07:00
|
|
|
hp->Type = RIO_PCI;
|
2006-03-24 18:18:28 +07:00
|
|
|
hp->Copy = rio_copy_to_card;
|
2006-01-12 03:17:49 +07:00
|
|
|
hp->Mode = RIO_PCI_BOOT_FROM_RAM;
|
|
|
|
spin_lock_init(&hp->HostLock);
|
|
|
|
rio_reset_interrupt(hp);
|
|
|
|
rio_start_card_running(hp);
|
|
|
|
|
|
|
|
rio_dprintk(RIO_DEBUG_PROBE, "Going to test it (%p/%p).\n", (void *) p->RIOHosts[p->RIONumHosts].PaddrP, p->RIOHosts[p->RIONumHosts].Caddr);
|
2006-03-24 18:18:32 +07:00
|
|
|
if (RIOBoardTest(p->RIOHosts[p->RIONumHosts].PaddrP, p->RIOHosts[p->RIONumHosts].Caddr, RIO_PCI, 0) == 0) {
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "Done RIOBoardTest\n");
|
2006-03-24 18:18:28 +07:00
|
|
|
writeb(0xFF, &p->RIOHosts[p->RIONumHosts].ResetInt);
|
2006-01-12 03:17:49 +07:00
|
|
|
p->RIOHosts[p->RIONumHosts].UniqueNum =
|
2006-03-24 18:18:28 +07:00
|
|
|
((readb(&p->RIOHosts[p->RIONumHosts].Unique[0]) & 0xFF) << 0) |
|
|
|
|
((readb(&p->RIOHosts[p->RIONumHosts].Unique[1]) & 0xFF) << 8) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[2]) & 0xFF) << 16) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[3]) & 0xFF) << 24);
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum);
|
|
|
|
|
|
|
|
fix_rio_pci(pdev);
|
2006-10-22 00:24:01 +07:00
|
|
|
|
|
|
|
p->RIOHosts[p->RIONumHosts].pdev = pdev;
|
|
|
|
pci_dev_get(pdev);
|
|
|
|
|
2006-03-24 18:18:32 +07:00
|
|
|
p->RIOLastPCISearch = 0;
|
2006-01-12 03:17:49 +07:00
|
|
|
p->RIONumHosts++;
|
|
|
|
found++;
|
|
|
|
} else {
|
2006-05-27 11:08:25 +07:00
|
|
|
iounmap(p->RIOHosts[p->RIONumHosts].Caddr);
|
2006-12-07 11:35:19 +07:00
|
|
|
p->RIOHosts[p->RIONumHosts].Caddr = NULL;
|
2006-01-12 03:17:49 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Then look for the older PCI card.... : */
|
|
|
|
|
|
|
|
/* These older PCI cards have problems (only byte-mode access is
|
|
|
|
supported), which makes them a bit awkward to support.
|
|
|
|
They also have problems sharing interrupts. Be careful.
|
|
|
|
(The driver now refuses to share interrupts for these
|
|
|
|
cards. This should be sufficient).
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Then look for the older RIO/PCI devices: */
|
|
|
|
while ((pdev = pci_get_device(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_RIO, pdev))) {
|
|
|
|
if (pci_enable_device(pdev))
|
|
|
|
continue;
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
#ifdef CONFIG_RIO_OLDPCI
|
2006-01-12 03:17:49 +07:00
|
|
|
hp = &p->RIOHosts[p->RIONumHosts];
|
2006-03-24 18:18:32 +07:00
|
|
|
hp->PaddrP = pci_resource_start(pdev, 0);
|
2006-01-12 03:17:49 +07:00
|
|
|
hp->Ivec = pdev->irq;
|
|
|
|
if (((1 << hp->Ivec) & rio_irqmask) == 0)
|
|
|
|
hp->Ivec = 0;
|
|
|
|
hp->Ivec |= 0x8000; /* Mark as non-sharable */
|
|
|
|
hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
|
2006-05-27 11:08:25 +07:00
|
|
|
hp->CardP = (struct DpRam __iomem *) hp->Caddr;
|
2006-01-12 03:17:49 +07:00
|
|
|
hp->Type = RIO_PCI;
|
2006-03-24 18:18:28 +07:00
|
|
|
hp->Copy = rio_copy_to_card;
|
2006-01-12 03:17:49 +07:00
|
|
|
hp->Mode = RIO_PCI_BOOT_FROM_RAM;
|
|
|
|
spin_lock_init(&hp->HostLock);
|
|
|
|
|
|
|
|
rio_dprintk(RIO_DEBUG_PROBE, "Ivec: %x\n", hp->Ivec);
|
|
|
|
rio_dprintk(RIO_DEBUG_PROBE, "Mode: %x\n", hp->Mode);
|
|
|
|
|
|
|
|
rio_reset_interrupt(hp);
|
|
|
|
rio_start_card_running(hp);
|
|
|
|
rio_dprintk(RIO_DEBUG_PROBE, "Going to test it (%p/%p).\n", (void *) p->RIOHosts[p->RIONumHosts].PaddrP, p->RIOHosts[p->RIONumHosts].Caddr);
|
2006-03-24 18:18:32 +07:00
|
|
|
if (RIOBoardTest(p->RIOHosts[p->RIONumHosts].PaddrP, p->RIOHosts[p->RIONumHosts].Caddr, RIO_PCI, 0) == 0) {
|
2006-03-24 18:18:28 +07:00
|
|
|
writeb(0xFF, &p->RIOHosts[p->RIONumHosts].ResetInt);
|
2006-01-12 03:17:49 +07:00
|
|
|
p->RIOHosts[p->RIONumHosts].UniqueNum =
|
2006-03-24 18:18:28 +07:00
|
|
|
((readb(&p->RIOHosts[p->RIONumHosts].Unique[0]) & 0xFF) << 0) |
|
|
|
|
((readb(&p->RIOHosts[p->RIONumHosts].Unique[1]) & 0xFF) << 8) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[2]) & 0xFF) << 16) | ((readb(&p->RIOHosts[p->RIONumHosts].Unique[3]) & 0xFF) << 24);
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum);
|
|
|
|
|
2006-10-22 00:24:01 +07:00
|
|
|
p->RIOHosts[p->RIONumHosts].pdev = pdev;
|
|
|
|
pci_dev_get(pdev);
|
|
|
|
|
2006-03-24 18:18:32 +07:00
|
|
|
p->RIOLastPCISearch = 0;
|
2006-01-12 03:17:49 +07:00
|
|
|
p->RIONumHosts++;
|
|
|
|
found++;
|
|
|
|
} else {
|
2006-05-27 11:08:25 +07:00
|
|
|
iounmap(p->RIOHosts[p->RIONumHosts].Caddr);
|
2006-12-07 11:35:19 +07:00
|
|
|
p->RIOHosts[p->RIONumHosts].Caddr = NULL;
|
2006-01-12 03:17:49 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
#else
|
2006-01-12 03:17:49 +07:00
|
|
|
printk(KERN_ERR "Found an older RIO PCI card, but the driver is not " "compiled to support it.\n");
|
2005-04-17 05:20:36 +07:00
|
|
|
#endif
|
2006-01-12 03:17:49 +07:00
|
|
|
}
|
|
|
|
#endif /* PCI */
|
|
|
|
|
|
|
|
/* Now probe for ISA cards... */
|
|
|
|
for (i = 0; i < NR_RIO_ADDRS; i++) {
|
|
|
|
hp = &p->RIOHosts[p->RIONumHosts];
|
|
|
|
hp->PaddrP = rio_probe_addrs[i];
|
|
|
|
/* There was something about the IRQs of these cards. 'Forget what.--REW */
|
|
|
|
hp->Ivec = 0;
|
|
|
|
hp->Caddr = ioremap(p->RIOHosts[p->RIONumHosts].PaddrP, RIO_WINDOW_LEN);
|
2006-05-27 11:08:25 +07:00
|
|
|
hp->CardP = (struct DpRam __iomem *) hp->Caddr;
|
2006-01-12 03:17:49 +07:00
|
|
|
hp->Type = RIO_AT;
|
2006-03-24 18:18:28 +07:00
|
|
|
hp->Copy = rio_copy_to_card; /* AT card PCI???? - PVDL
|
|
|
|
* -- YES! this is now a normal copy. Only the
|
2006-01-12 03:17:49 +07:00
|
|
|
* old PCI card uses the special PCI copy.
|
|
|
|
* Moreover, the ISA card will work with the
|
|
|
|
* special PCI copy anyway. -- REW */
|
|
|
|
hp->Mode = 0;
|
|
|
|
spin_lock_init(&hp->HostLock);
|
|
|
|
|
|
|
|
vpdp = get_VPD_PROM(hp);
|
|
|
|
rio_dprintk(RIO_DEBUG_PROBE, "Got VPD ROM\n");
|
|
|
|
okboard = 0;
|
|
|
|
if ((strncmp(vpdp->identifier, RIO_ISA_IDENT, 16) == 0) || (strncmp(vpdp->identifier, RIO_ISA2_IDENT, 16) == 0) || (strncmp(vpdp->identifier, RIO_ISA3_IDENT, 16) == 0)) {
|
|
|
|
/* Board is present... */
|
2006-03-24 18:18:32 +07:00
|
|
|
if (RIOBoardTest(hp->PaddrP, hp->Caddr, RIO_AT, 0) == 0) {
|
2006-01-12 03:17:49 +07:00
|
|
|
/* ... and feeling fine!!!! */
|
|
|
|
rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, uniqid = %x.\n", p->RIOHosts[p->RIONumHosts].UniqueNum);
|
|
|
|
if (RIOAssignAT(p, hp->PaddrP, hp->Caddr, 0)) {
|
|
|
|
rio_dprintk(RIO_DEBUG_PROBE, "Hmm Tested ok, host%d uniqid = %x.\n", p->RIONumHosts, p->RIOHosts[p->RIONumHosts - 1].UniqueNum);
|
|
|
|
okboard++;
|
|
|
|
found++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-12-07 11:35:19 +07:00
|
|
|
if (!okboard) {
|
2006-05-27 11:08:25 +07:00
|
|
|
iounmap(hp->Caddr);
|
2006-12-07 11:35:19 +07:00
|
|
|
hp->Caddr = NULL;
|
|
|
|
}
|
2006-01-12 03:17:49 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < p->RIONumHosts; i++) {
|
|
|
|
hp = &p->RIOHosts[i];
|
|
|
|
if (hp->Ivec) {
|
2006-07-02 09:29:41 +07:00
|
|
|
int mode = IRQF_SHARED;
|
2006-01-12 03:17:49 +07:00
|
|
|
if (hp->Ivec & 0x8000) {
|
|
|
|
mode = 0;
|
|
|
|
hp->Ivec &= 0x7fff;
|
|
|
|
}
|
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "Requesting interrupt hp: %p rio_interrupt: %d Mode: %x\n", hp, hp->Ivec, hp->Mode);
|
|
|
|
retval = request_irq(hp->Ivec, rio_interrupt, mode, "rio", hp);
|
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "Return value from request_irq: %d\n", retval);
|
|
|
|
if (retval) {
|
|
|
|
printk(KERN_ERR "rio: Cannot allocate irq %d.\n", hp->Ivec);
|
|
|
|
hp->Ivec = 0;
|
|
|
|
}
|
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "Got irq %d.\n", hp->Ivec);
|
|
|
|
if (hp->Ivec != 0) {
|
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "Enabling interrupts on rio card.\n");
|
|
|
|
hp->Mode |= RIO_PCI_INT_ENABLE;
|
|
|
|
} else
|
2007-02-18 00:57:09 +07:00
|
|
|
hp->Mode &= ~RIO_PCI_INT_ENABLE;
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "New Mode: %x\n", hp->Mode);
|
|
|
|
rio_start_card_running(hp);
|
|
|
|
}
|
|
|
|
/* Init the timer "always" to make sure that it can safely be
|
|
|
|
deleted when we unload... */
|
|
|
|
|
2007-02-12 15:52:31 +07:00
|
|
|
setup_timer(&hp->timer, rio_pollfunc, i);
|
2006-01-12 03:17:49 +07:00
|
|
|
if (!hp->Ivec) {
|
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "Starting polling at %dj intervals.\n", rio_poll);
|
2007-02-12 15:52:31 +07:00
|
|
|
mod_timer(&hp->timer, jiffies + rio_poll);
|
2006-01-12 03:17:49 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (found) {
|
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "rio: total of %d boards detected.\n", found);
|
|
|
|
rio_init_drivers();
|
|
|
|
} else {
|
|
|
|
/* deregister the misc device we created earlier */
|
|
|
|
misc_deregister(&rio_fw_device);
|
|
|
|
}
|
|
|
|
|
|
|
|
func_exit();
|
|
|
|
return found ? 0 : -EIO;
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
static void __exit rio_exit(void)
|
2005-04-17 05:20:36 +07:00
|
|
|
{
|
2006-01-12 03:17:49 +07:00
|
|
|
int i;
|
|
|
|
struct Host *hp;
|
|
|
|
|
|
|
|
func_enter();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
for (i = 0, hp = p->RIOHosts; i < p->RIONumHosts; i++, hp++) {
|
|
|
|
RIOHostReset(hp->Type, hp->CardP, hp->Slot);
|
|
|
|
if (hp->Ivec) {
|
|
|
|
free_irq(hp->Ivec, hp);
|
|
|
|
rio_dprintk(RIO_DEBUG_INIT, "freed irq %d.\n", hp->Ivec);
|
|
|
|
}
|
|
|
|
/* It is safe/allowed to del_timer a non-active timer */
|
2007-02-12 15:52:31 +07:00
|
|
|
del_timer_sync(&hp->timer);
|
2006-12-07 11:35:19 +07:00
|
|
|
if (hp->Caddr)
|
|
|
|
iounmap(hp->Caddr);
|
2006-10-22 00:24:01 +07:00
|
|
|
if (hp->Type == RIO_PCI)
|
|
|
|
pci_dev_put(hp->pdev);
|
2006-01-12 03:17:49 +07:00
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
if (misc_deregister(&rio_fw_device) < 0) {
|
|
|
|
printk(KERN_INFO "rio: couldn't deregister control-device\n");
|
|
|
|
}
|
2005-04-17 05:20:36 +07:00
|
|
|
|
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_dprintk(RIO_DEBUG_CLEANUP, "Cleaning up drivers\n");
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
rio_release_drivers();
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
/* Release dynamically allocated memory */
|
|
|
|
kfree(p->RIOPortp);
|
|
|
|
kfree(p->RIOHosts);
|
|
|
|
kfree(p);
|
2005-04-17 05:20:36 +07:00
|
|
|
|
2006-01-12 03:17:49 +07:00
|
|
|
func_exit();
|
2005-04-17 05:20:36 +07:00
|
|
|
}
|
|
|
|
|
|
|
|
module_init(rio_init);
|
|
|
|
module_exit(rio_exit);
|