* This driver will also support the older SI, and XIO cards.
*
*
- * (C) 1998 - 2000 R.E.Wolff@BitWizard.nl
+ * (C) 1998 - 2004 R.E.Wolff@BitWizard.nl
*
* Simon Allen (simonallen@cix.compulink.co.uk) wrote a previous
* version of this driver. Some fragments may have been copied. (none
#define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000
#endif
+#ifdef CONFIG_PCI
static struct pci_device_id sx_pci_tbl[] = {
{ PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8, PCI_ANY_ID, PCI_ANY_ID },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, sx_pci_tbl);
+#endif /* CONFIG_PCI */
/* Configurable options:
(Don't be too sure that it'll work if you toggle them) */
0xc8000, 0xd8000, 0xe8000, 0xa0000};
static int si1_probe_addrs[]= { 0xd0000};
-#define NR_SX_ADDRS (sizeof(sx_probe_addrs)/sizeof (int))
-#define NR_SI_ADDRS (sizeof(si_probe_addrs)/sizeof (int))
-#define NR_SI1_ADDRS (sizeof(si1_probe_addrs)/sizeof (int))
+#define NR_SX_ADDRS ARRAY_SIZE(sx_probe_addrs)
+#define NR_SI_ADDRS ARRAY_SIZE(si_probe_addrs)
+#define NR_SI1_ADDRS ARRAY_SIZE(si1_probe_addrs)
/* Set the mask to all-ones. This alas, only supports 32 interrupts.
Some architectures may need more. */
static int sx_irqmask = -1;
-MODULE_PARM(sx_probe_addrs, "i");
-MODULE_PARM(si_probe_addrs, "i");
-MODULE_PARM(sx_poll, "i");
-MODULE_PARM(sx_slowpoll, "i");
-MODULE_PARM(sx_maxints, "i");
-MODULE_PARM(sx_debug, "i");
-MODULE_PARM(sx_irqmask, "i");
+module_param_array(sx_probe_addrs, int, NULL, 0);
+module_param_array(si_probe_addrs, int, NULL, 0);
+module_param(sx_poll, int, 0);
+module_param(sx_slowpoll, int, 0);
+module_param(sx_maxints, int, 0);
+module_param(sx_debug, int, 0);
+module_param(sx_irqmask, int, 0);
MODULE_LICENSE("GPL");
-#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s\b",__FUNCTION__)
+#define func_enter() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s\n",__FUNCTION__)
#define func_exit() sx_dprintk (SX_DEBUG_FLOW, "sx: exit %s\n", __FUNCTION__)
#define func_enter2() sx_dprintk (SX_DEBUG_FLOW, "sx: enter %s (port %d)\n", \
#ifdef DEBUG
-static void my_hd (unsigned char *addr, int len)
+static void my_hd_io(void __iomem *p, int len)
+{
+ int i, j, ch;
+ unsigned char __iomem *addr = p;
+
+ for (i=0;i<len;i+=16) {
+ printk ("%p ", addr+i);
+ for (j=0;j<16;j++) {
+ printk ("%02x %s", readb(addr+j+i), (j==7)?" ":"");
+ }
+ for (j=0;j<16;j++) {
+ ch = readb(addr+j+i);
+ printk ("%c", (ch < 0x20)?'.':((ch > 0x7f)?'.':ch));
+ }
+ printk ("\n");
+ }
+}
+static void my_hd(void *p, int len)
{
int i, j, ch;
+ unsigned char *addr = p;
for (i=0;i<len;i+=16) {
printk ("%p ", addr+i);
case CS6:sx_write_channel_byte (port, hi_mask, 0x3f);break;
case CS5:sx_write_channel_byte (port, hi_mask, 0x1f);break;
default:
- printk (KERN_INFO "sx: Invalid wordsize: %d\n", CFLAG & CSIZE);
+ printk (KERN_INFO "sx: Invalid wordsize: %u\n", CFLAG & CSIZE);
break;
}
} else {
set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
}
- sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
+ sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
port->gs.tty->termios->c_iflag,
I_OTHER(port->gs.tty));
} else {
clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
}
- sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
+ sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
port->gs.tty->termios->c_oflag,
O_OTHER(port->gs.tty));
/* port->c_dcd = sx_get_CD (port); */
}
if ((port->gs.xmit_cnt <= port->gs.wakeup_chars) && port->gs.tty) {
- if ((port->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- port->gs.tty->ldisc.write_wakeup)
- (port->gs.tty->ldisc.write_wakeup)(port->gs.tty);
+ tty_wakeup(port->gs.tty);
sx_dprintk (SX_DEBUG_TRANSMIT, "Waking up.... ldisc (%d)....\n",
port->gs.wakeup_chars);
- wake_up_interruptible(&port->gs.tty->write_wait);
}
clear_bit (SX_PORT_TRANSMIT_LOCK, &port->locks);
int rx_op;
struct tty_struct *tty;
int copied=0;
+ unsigned char *rp;
func_enter2 ();
tty = port->gs.tty;
sx_dprintk (SX_DEBUG_RECEIVE, "rxop=%d, c = %d.\n", rx_op, c);
- /* Don't copy more bytes than there is room for in the buffer */
- if (tty->flip.count + c > TTY_FLIPBUF_SIZE)
- c = TTY_FLIPBUF_SIZE - tty->flip.count;
-
- sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c);
-
/* Don't copy past the end of the hardware receive buffer */
if (rx_op + c > 0x100) c = 0x100 - rx_op;
sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c);
+ /* Don't copy more bytes than there is room for in the buffer */
+
+ c = tty_prepare_flip_string(tty, &rp, c);
+
+ sx_dprintk (SX_DEBUG_RECEIVE, "c = %d.\n", c);
+
/* If for one reason or another, we can't copy more data, we're done! */
if (c == 0) break;
sx_dprintk (SX_DEBUG_RECEIVE , "Copying over %d chars. First is %d at %lx\n", c,
read_sx_byte (port->board, CHAN_OFFSET(port,hi_rxbuf) + rx_op),
CHAN_OFFSET(port, hi_rxbuf));
- memcpy_fromio (tty->flip.char_buf_ptr,
+ memcpy_fromio (rp,
port->board->base + CHAN_OFFSET(port,hi_rxbuf) + rx_op, c);
- memset(tty->flip.flag_buf_ptr, TTY_NORMAL, c);
-
- /* Update the kernel buffer end */
- tty->flip.count += c;
- tty->flip.char_buf_ptr += c;
- tty->flip.flag_buf_ptr += c;
/* This one last. ( Not essential.)
It allows the card to start putting more data into the buffer!
if (hi_state & ST_BREAK) {
hi_state &= ~ST_BREAK;
sx_dprintk (SX_DEBUG_MODEMSIGNALS, "got a break.\n");
-
sx_write_channel_byte (port, hi_state, hi_state);
gs_got_break (&port->gs);
}
struct sx_port *port;
int i;
- /* func_enter (); */
+ func_enter ();
sx_dprintk (SX_DEBUG_FLOW, "sx: enter sx_interrupt (%d/%d)\n", irq, board->irq);
/* AAargh! The order in which to do these things is essential and
clear_bit (SX_BOARD_INTR_LOCK, &board->locks);
sx_dprintk (SX_DEBUG_FLOW, "sx: exit sx_interrupt (%d/%d)\n", irq, board->irq);
- /* func_exit (); */
+ func_exit ();
return IRQ_HANDLED;
}
{
struct sx_port *port;
int retval, line;
+ unsigned long flags;
func_enter();
sx_dprintk (SX_DEBUG_OPEN, "port = %p c_dcd = %d\n", port, port->c_dcd);
+ spin_lock_irqsave(&port->gs.driver_lock, flags);
+
tty->driver_data = port;
port->gs.tty = tty;
port->gs.count++;
+ spin_unlock_irqrestore(&port->gs.driver_lock, flags);
sx_dprintk (SX_DEBUG_OPEN, "starting port\n");
}
port->gs.flags |= GS_ACTIVE;
- sx_setsignals (port, 1,1);
+ if (port->gs.count <= 1)
+ sx_setsignals (port, 1,1);
#if 0
if (sx_debug & SX_DEBUG_OPEN)
- my_hd ((unsigned char *)port, sizeof (*port));
+ my_hd (port, sizeof (*port));
#else
if (sx_debug & SX_DEBUG_OPEN)
- my_hd ((unsigned char *)port->board->base + port->ch_base,
- sizeof (*port));
+ my_hd_io (port->board->base + port->ch_base, sizeof (*port));
#endif
- if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
- printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n");
- port->gs.count--;
- return -EIO;
+ if (port->gs.count <= 1) {
+ if (sx_send_command (port, HS_LOPEN, -1, HS_IDLE_OPEN) != 1) {
+ printk (KERN_ERR "sx: Card didn't respond to LOPEN command.\n");
+ spin_lock_irqsave(&port->gs.driver_lock, flags);
+ port->gs.count--;
+ spin_unlock_irqrestore(&port->gs.driver_lock, flags);
+ return -EIO;
+ }
}
retval = gs_block_til_ready(port, filp);
port->c_dcd = sx_get_CD (port);
sx_dprintk (SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd);
+
func_exit();
return 0;
sx_reconfigure_port(port);
sx_send_command (port, HS_CLOSE, 0, 0);
- while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED)) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout (1);
- if (signal_pending (current))
- break;
- }
- current->state = TASK_RUNNING;
+ while (to-- && (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED))
+ if (msleep_interruptible(10))
+ break;
if (sx_read_channel_byte (port, hi_hstat) != HS_IDLE_CLOSED) {
if (sx_send_command (port, HS_FORCE_CLOSED, -1, HS_IDLE_CLOSED) != 1) {
printk (KERN_ERR
if(port->gs.count) {
sx_dprintk(SX_DEBUG_CLOSE, "WARNING port count:%d\n", port->gs.count);
- port->gs.count = 0;
+ //printk ("%s SETTING port count to zero: %p count: %d\n", __FUNCTION__, port, port->gs.count);
+ //port->gs.count = 0;
}
func_exit ();
unsigned int cmd, unsigned long arg)
{
int rc = 0;
- int *descr = (int *)arg, i;
+ int __user *descr = (int __user *)arg;
+ int i;
static struct sx_board *board = NULL;
int nbytes, offset;
unsigned long data;
get_user (data, descr++);
while (nbytes && data) {
for (i=0;i<nbytes;i += SX_CHUNK_SIZE) {
- if (copy_from_user(tmp, (char *)data + i,
+ if (copy_from_user(tmp, (char __user *)data+i,
(i + SX_CHUNK_SIZE >
nbytes) ? nbytes - i :
SX_CHUNK_SIZE)) {
kfree (tmp);
return -EFAULT;
}
- memcpy_toio ((char *) (board->base2 + offset + i), tmp,
+ memcpy_toio(board->base2 + offset + i, tmp,
(i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE);
}
struct sx_port *port = tty->driver_data;
int rv;
+ func_enter ();
+
if (flag)
rv = sx_send_command (port, HS_START, -1, HS_IDLE_BREAK);
else
rv = sx_send_command (port, HS_STOP, -1, HS_IDLE_OPEN);
if (rv != 1) printk (KERN_ERR "sx: couldn't send break (%x).\n",
read_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat)));
+
+ func_exit ();
}
{
int rc;
struct sx_port *port = tty->driver_data;
+ void __user *argp = (void __user *)arg;
int ival;
/* func_enter2(); */
switch (cmd) {
case TIOCGSOFTCAR:
rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0),
- (unsigned int *) arg);
+ (unsigned __user *) argp);
break;
case TIOCSSOFTCAR:
- if ((rc = get_user(ival, (unsigned int *) arg)) == 0) {
+ if ((rc = get_user(ival, (unsigned __user *) argp)) == 0) {
tty->termios->c_cflag =
(tty->termios->c_cflag & ~CLOCAL) |
(ival ? CLOCAL : 0);
}
break;
case TIOCGSERIAL:
- if ((rc = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct serial_struct))) == 0)
- rc = gs_getserial(&port->gs, (struct serial_struct *) arg);
+ rc = gs_getserial(&port->gs, argp);
break;
case TIOCSSERIAL:
- if ((rc = verify_area(VERIFY_READ, (void *) arg,
- sizeof(struct serial_struct))) == 0)
- rc = gs_setserial(&port->gs, (struct serial_struct *) arg);
+ rc = gs_setserial(&port->gs, argp);
break;
default:
rc = -ENOIOCTLCMD;
/* Ok. So now the processor on the card is running. It gathered
some info for us... */
sx_dprintk (SX_DEBUG_INIT, "The sxcard structure:\n");
- if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base), 0x10);
+ if (sx_debug & SX_DEBUG_INIT) my_hd_io (board->base, 0x10);
sx_dprintk (SX_DEBUG_INIT, "the first sx_module structure:\n");
- if (sx_debug & SX_DEBUG_INIT) my_hd ((char *)(board->base + 0x80), 0x30);
+ if (sx_debug & SX_DEBUG_INIT) my_hd_io (board->base + 0x80, 0x30);
sx_dprintk (SX_DEBUG_INIT,
"init_status: %x, %dk memory, firmware V%x.%02x,\n",
func_enter();
if (!IS_CF_BOARD (board)) {
- sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %lx.\n",
+ sx_dprintk (SX_DEBUG_PROBE, "Going to verify vpd prom at %p.\n",
board->base + SX_VPD_ROM);
if (sx_debug & SX_DEBUG_PROBE)
- my_hd ((char *)(board->base + SX_VPD_ROM), 0x40);
+ my_hd_io(board->base + SX_VPD_ROM, 0x40);
p = (char *) &vpdp;
for (i=0;i< sizeof (struct vpd_prom);i++)
*p++ = read_sx_byte (board, SX_VPD_ROM + i*2);
if (sx_debug & SX_DEBUG_PROBE)
- my_hd ((char *)&vpdp, 0x20);
+ my_hd (&vpdp, 0x20);
sx_dprintk (SX_DEBUG_PROBE, "checking identifier...\n");
}
if (((vpdp.uniqid >> 24) & SX_UNIQUEID_MASK) == SX_ISA_UNIQUEID1) {
- if (board->base & 0x8000) {
- printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %lx.\n", board->base);
+ if (((unsigned long)board->hw_base) & 0x8000) {
+ printk (KERN_WARNING "sx: Warning: There may be hardware problems with the card at %lx.\n", board->hw_base);
printk (KERN_WARNING "sx: Read sx.txt for more info.\n");
}
}
int i;
func_enter();
- sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature hw %lx at %lx.\n", board->hw_base,
+ sx_dprintk (SX_DEBUG_PROBE, "Going to verify SI signature hw %lx at %p.\n", board->hw_base,
board->base + SI2_ISA_ID_BASE);
if (sx_debug & SX_DEBUG_PROBE)
- my_hd ((char *)(board->base + SI2_ISA_ID_BASE), 0x8);
+ my_hd_io(board->base + SI2_ISA_ID_BASE, 0x8);
if (!IS_EISA_BOARD(board)) {
if( IS_SI1_BOARD(board) )
}
for (i=0;i<8;i++) {
if ((read_sx_byte (board, SI2_ISA_ID_BASE+7-i) & 7) != i) {
+ func_exit ();
return 0;
}
}
if ( IS_SI1_BOARD(board)) {
/* This should be an SI1 board, which has this
location writable... */
- if (read_sx_byte (board, SI2_ISA_ID_BASE) != 0x10)
+ if (read_sx_byte (board, SI2_ISA_ID_BASE) != 0x10) {
+ func_exit ();
return 0;
+ }
} else {
/* This should be an SI2 board, which has the bottom
3 bits non-writable... */
- if (read_sx_byte (board, SI2_ISA_ID_BASE) == 0x10)
+ if (read_sx_byte (board, SI2_ISA_ID_BASE) == 0x10) {
+ func_exit ();
return 0;
+ }
}
/* Now we're pretty much convinced that there is an SI board here,
if ( IS_SI1_BOARD(board)) {
/* This should be an SI1 board, which has this
location writable... */
- if (read_sx_byte (board, SI2_ISA_ID_BASE) != 0x10)
+ if (read_sx_byte (board, SI2_ISA_ID_BASE) != 0x10) {
+ func_exit();
return 0;
+ }
} else {
/* This should be an SI2 board, which has the bottom
3 bits non-writable... */
- if (read_sx_byte (board, SI2_ISA_ID_BASE) == 0x10)
+ if (read_sx_byte (board, SI2_ISA_ID_BASE) == 0x10) {
+ func_exit ();
return 0;
+ }
}
printheader ();
port->board = board;
port->gs.rd = &sx_real_driver;
#ifdef NEW_WRITE_LOCKING
- port->gs.port_write_sem = MUTEX;
+ port->gs.port_write_mutex = MUTEX;
#endif
+ port->gs.driver_lock = SPIN_LOCK_UNLOCKED;
/*
* Initializing wait queue
*/
static void fix_sx_pci (struct pci_dev *pdev, struct sx_board *board)
{
unsigned int hwbase;
- unsigned long rebase;
+ void __iomem *rebase;
unsigned int t;
#define CNTRL_REG_OFFSET 0x50
pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &hwbase);
hwbase &= PCI_BASE_ADDRESS_MEM_MASK;
- rebase = (ulong) ioremap(hwbase, 0x80);
+ rebase = ioremap(hwbase, 0x80);
t = readl (rebase + CNTRL_REG_OFFSET);
if (t != CNTRL_REG_GOODVALUE) {
printk (KERN_DEBUG "sx: performing cntrl reg fix: %08x -> %08x\n", t, CNTRL_REG_GOODVALUE);
writel (CNTRL_REG_GOODVALUE, rebase + CNTRL_REG_OFFSET);
}
- iounmap ((char *) rebase);
+ iounmap(rebase);
}
#endif
else
board->hw_base = pci_resource_start (pdev, 2);
board->base2 =
- board->base = (ulong) ioremap(board->hw_base, WINDOW_LEN (board));
+ board->base = ioremap(board->hw_base, WINDOW_LEN (board));
if (!board->base) {
printk(KERN_ERR "ioremap failed\n");
/* XXX handle error */
board->irq = pdev->irq;
- sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%lx(%d) %x.\n",
+ sx_dprintk (SX_DEBUG_PROBE, "Got a specialix card: %x/%p(%d) %x.\n",
tint, boards[found].base, board->irq, board->flags);
if (probe_sx (board)) {
found++;
fix_sx_pci (pdev, board);
} else
- iounmap ((char *) (board->base));
+ iounmap(board->base2);
}
#endif
board = &boards[found];
board->hw_base = sx_probe_addrs[i];
board->base2 =
- board->base = (ulong) ioremap(board->hw_base, SX_WINDOW_LEN);
+ board->base = ioremap(board->hw_base, SX_WINDOW_LEN);
board->flags &= ~SX_BOARD_TYPE;
board->flags |= SX_ISA_BOARD;
board->irq = sx_irqmask?-1:0;
if (probe_sx (board)) {
found++;
} else {
- iounmap ((char *) (board->base));
+ iounmap(board->base);
}
}
board = &boards[found];
board->hw_base = si_probe_addrs[i];
board->base2 =
- board->base = (ulong) ioremap(board->hw_base, SI2_ISA_WINDOW_LEN);
+ board->base = ioremap(board->hw_base, SI2_ISA_WINDOW_LEN);
board->flags &= ~SX_BOARD_TYPE;
board->flags |= SI_ISA_BOARD;
board->irq = sx_irqmask ?-1:0;
if (probe_si (board)) {
found++;
} else {
- iounmap ((char *) (board->base));
+ iounmap (board->base);
}
}
for (i=0;i<NR_SI1_ADDRS;i++) {
board = &boards[found];
board->hw_base = si1_probe_addrs[i];
board->base2 =
- board->base = (ulong) ioremap(board->hw_base, SI1_ISA_WINDOW_LEN);
+ board->base = ioremap(board->hw_base, SI1_ISA_WINDOW_LEN);
board->flags &= ~SX_BOARD_TYPE;
board->flags |= SI1_ISA_BOARD;
board->irq = sx_irqmask ?-1:0;
if (probe_si (board)) {
found++;
} else {
- iounmap ((char *) (board->base));
+ iounmap (board->base);
}
}
board->hw_base = (((inb(0xc01+eisa_slot) << 8) + inb(0xc00+eisa_slot)) << 16);
board->base2 =
- board->base = (ulong) ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
+ board->base = ioremap(board->hw_base, SI2_EISA_WINDOW_LEN);
sx_dprintk(SX_DEBUG_PROBE, "IO hw_base address: %lx\n", board->hw_base);
- sx_dprintk(SX_DEBUG_PROBE, "base: %lx\n", board->base);
+ sx_dprintk(SX_DEBUG_PROBE, "base: %p\n", board->base);
board->irq = inb(board->eisa_base+0xc02)>>4;
sx_dprintk(SX_DEBUG_PROBE, "IRQ: %d\n", board->irq);
for (i = 0; i < SX_NBOARDS; i++) {
board = &boards[i];
if (board->flags & SX_BOARD_INITIALIZED) {
- sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %lx\n", board->base);
+ sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up board at %p\n", board->base);
/* The board should stop messing with us.
(actually I mean the interrupt) */
sx_reset (board);
/* It is safe/allowed to del_timer a non-active timer */
del_timer (& board->timer);
- iounmap ((char *) (board->base));
+ iounmap(board->base);
}
}
if (misc_deregister(&sx_fw_device) < 0) {
- printk (KERN_INFO "sx: couldn't deregister firmware loader device\n");
+ printk (KERN_INFO "sx: couldn't deregister firmware loader devic\n");
}
sx_dprintk (SX_DEBUG_CLEANUP, "Cleaning up drivers (%d)\n", sx_initialized);
if (sx_initialized)