Update to Rocketport

Theodore Y. Ts'o (tytso@mit.edu)
Fri, 10 Jul 1998 04:36:30 -0400


Hi Linus,

Could you please apply this patch to the mainline kernel,
please. It's an update of the Comtrol Rocketport driver, and it fixes a
number of problems, including:

* A race condition which could happen if the carrier detect line
pulsed quickly on and off while the port was being
opened.

* Fixed rs_write so that we aren't trying to read from user
space while interrupts are disabled.

* Fix incorrect numbers in include/linux/pci.h which caused a
few Rocketport boards to be incorrectly identified by
/proc/pci. (As well as requiring hair in the driver to
detect the incorrect numbers in include/linux/pci.h, and
override them.)

Could you apply these patches to the 2.1 tree, please? Thanks!!

- Ted

Patch generated: on Fri Jul 10 03:58:08 EDT 1998 by tytso@rsts-11.mit.edu
against Linux version 2.1.108

===================================================================
RCS file: drivers/char/RCS/rocket.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/rocket.c
--- drivers/char/rocket.c 1998/07/03 20:00:57 1.1
+++ drivers/char/rocket.c 1998/07/10 07:55:13
@@ -48,6 +48,9 @@

#if (LINUX_VERSION_CODE > 66304)
#define NEW_MODULES
+#ifdef LOCAL_ROCKET_H /* We're building standalone */
+#define MODULE
+#endif
#endif

#ifdef NEW_MODULES
@@ -81,6 +84,9 @@
#include <linux/ioport.h>
#ifdef ENABLE_PCI
#include <linux/pci.h>
+#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
+#include <linux/bios32.h>
+#endif
#endif
#if (LINUX_VERSION_CODE >= 131343) /* 2.1.15 -- XX get correct version */
#include <linux/init.h>
@@ -89,12 +95,17 @@
#endif

#include "rocket_int.h"
+#ifdef LOCAL_ROCKET_H
+#include "rocket.h"
+#include "version.h"
+#else
#include <linux/rocket.h>
-
-#define ROCKET_VERSION "1.14a"
-#define ROCKET_DATE "19-Jul-97"
+#define ROCKET_VERSION "1.14b"
+#define ROCKET_DATE "29-Jun-98"
+#endif /* LOCAL_ROCKET_H */

#define ROCKET_PARANOIA_CHECK
+#define ROCKET_SOFT_FLOW

#undef ROCKET_DEBUG_OPEN
#undef ROCKET_DEBUG_INTR
@@ -177,9 +188,30 @@
static unsigned long time_counter = 0;
#endif

+#if ((LINUX_VERSION_CODE > 0x020111) && defined(MODULE))
+MODULE_AUTHOR("Theodore Ts'o");
+MODULE_DESCRIPTION("Comtrol Rocketport driver");
+MODULE_PARM(board1, "i");
+MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1");
+MODULE_PARM(board2, "i");
+MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2");
+MODULE_PARM(board3, "i");
+MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3");
+MODULE_PARM(board4, "i");
+MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4");
+MODULE_PARM(controller, "i");
+MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller");
+MODULE_PARM(support_low_speed, "i");
+MODULE_PARM_DESC(support_low_speed, "0 means support 50 baud, 1 means support 460400 baud");
+#endif
+
/*
* Provide backwards compatibility for kernels prior to 2.1.8.
*/
+#if (LINUX_VERSION_CODE < 0x20000)
+typedef dev_t kdev_t;
+#endif
+
#if (LINUX_VERSION_CODE < 131336)
int copy_from_user(void *to, const void *from_user, unsigned long len)
{
@@ -202,6 +234,12 @@
memcpy_tofs(to_user, from, len);
return 0;
}
+
+static inline int signal_pending(struct task_struct *p)
+{
+ return (p->signal & (~p->blocked != 0));
+}
+
#else
#include <asm/uaccess.h>
#endif
@@ -720,6 +758,27 @@
info->intmask |= DELTA_CD;
restore_flags(flags);
}
+
+ /*
+ * Handle software flow control in the board
+ */
+#ifdef ROCKET_SOFT_FLOW
+ if (I_IXON(info->tty)) {
+ sEnTxSoftFlowCtl(cp);
+ if (I_IXANY(info->tty)) {
+ sEnIXANY(cp);
+ } else {
+ sDisIXANY(cp);
+ }
+ sSetTxXONChar(cp, START_CHAR(info->tty));
+ sSetTxXOFFChar(cp, STOP_CHAR(info->tty));
+ } else {
+ sDisTxSoftFlowCtl(cp);
+ sDisIXANY(cp);
+ sClrTxXOFF(cp);
+ }
+#endif
+
/*
* Set up ignore/read mask words
*/
@@ -728,7 +787,7 @@
info->read_status_mask |= STMFRAMEH | STMPARITYH;
if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
info->read_status_mask |= STMBREAKH;
-
+
/*
* Characters to ignore
*/
@@ -751,7 +810,7 @@
{
struct wait_queue wait = { current, NULL };
int retval;
- int do_clocal = 0;
+ int do_clocal = 0, extra_count = 0;
unsigned long flags;

/*
@@ -820,8 +879,10 @@
info->line, info->count);
#endif
save_flags(flags); cli();
- if (!tty_hung_up_p(filp))
+ if (!tty_hung_up_p(filp)) {
+ extra_count = 1;
info->count--;
+ }
restore_flags(flags);
info->blocked_open++;
while (1) {
@@ -857,7 +918,7 @@
current->state = TASK_RUNNING;
remove_wait_queue(&info->open_wait, &wait);
cli();
- if (!tty_hung_up_p(filp))
+ if (extra_count)
info->count++;
restore_flags(flags);
info->blocked_open--;
@@ -1315,7 +1376,12 @@
if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
return -EFAULT;

- if (!capable(CAP_SYS_ADMIN)) {
+#ifdef CAP_SYS_ADMIN
+ if (!capable(CAP_SYS_ADMIN))
+#else
+ if (!suser())
+#endif
+ {
if ((new_serial.flags & ~ROCKET_USR_MASK) !=
(info->flags & ~ROCKET_USR_MASK))
return -EPERM;
@@ -1754,7 +1820,6 @@

save_flags(flags);
while (1) {
- cli();
if (info->tty == 0) {
restore_flags(flags);
goto end;
@@ -1778,10 +1843,10 @@
/* In case we got pre-empted */
if (info->tty == 0)
goto end_intr;
- c = MIN(c, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1,
- XMIT_BUF_SIZE - info->xmit_head));
-
}
+ cli();
+ c = MIN(c, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1,
+ XMIT_BUF_SIZE - info->xmit_head));
memcpy(info->xmit_buf + info->xmit_head, b, c);
info->xmit_head = (info->xmit_head + c) & (XMIT_BUF_SIZE-1);
info->xmit_cnt += c;
@@ -1868,6 +1933,35 @@
}

#ifdef ENABLE_PCI
+#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
+/* For compatibility */
+static struct pci_dev *pci_find_slot(char bus, char device_fn)
+{
+ unsigned short vendor_id, device_id;
+ int ret, error;
+ static struct pci_dev ret_struct;
+
+ error = pcibios_read_config_word(bus, device_fn, PCI_VENDOR_ID,
+ &vendor_id);
+ ret = pcibios_read_config_word(bus, device_fn, PCI_DEVICE_ID,
+ &device_id);
+ if (error == 0)
+ error = ret;
+
+ if (error) {
+ printk("PCI RocketPort error: %s not initializing due to error"
+ "reading configuration space\n",
+ pcibios_strerror(error));
+ return(0);
+ }
+
+ memset(&ret_struct, 0, sizeof(ret_struct));
+ ret_struct.device = device_id;
+
+ return &ret_struct;
+}
+#endif
+
__initfunc(int register_PCI(int i, char bus, char device_fn))
{
int num_aiops, aiop, max_num_aiops, num_chan, chan;
@@ -1875,8 +1969,23 @@
char *str;
CONTROLLER_t *ctlp;
struct pci_dev *dev = pci_find_slot(bus, device_fn);
+#if (LINUX_VERSION_CODE < 0x020163) /* 2.1.99 */
+ int ret;
+ unsigned int port;
+#endif

+ if (!dev)
+ return 0;
+
+#if (LINUX_VERSION_CODE >= 0x020163) /* 2.1.99 */
rcktpt_io_addr[i] = dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+#else
+ ret = pcibios_read_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0,
+ &port);
+ if (ret)
+ return 0;
+ rcktpt_io_addr[i] = port & PCI_BASE_ADDRESS_IO_MASK;
+#endif
switch(dev->device) {
case PCI_DEVICE_ID_RP4QUAD:
str = "Quadcable";
@@ -1902,6 +2011,18 @@
str = "32";
max_num_aiops = 4;
break;
+ case PCI_DEVICE_ID_RPP4:
+ str = "Plus Quadcable";
+ max_num_aiops = 1;
+ break;
+ case PCI_DEVICE_ID_RPP8:
+ str = "Plus Octacable";
+ max_num_aiops = 1;
+ break;
+ case PCI_DEVICE_ID_RP8M:
+ str = "8-port Modem";
+ max_num_aiops = 1;
+ break;
default:
str = "(unknown/unsupported)";
max_num_aiops = 0;
@@ -1936,20 +2057,48 @@
int i, count = 0;

for(i=0; i < (NUM_BOARDS - boards_found); i++) {
- if(!pcibios_find_device(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8OCTA,
- i, &bus, &device_fn))
+ if (!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP4QUAD, i, &bus, &device_fn))
+ if (register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if (!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP8J, i, &bus, &device_fn))
+ if (register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP8OCTA, i, &bus, &device_fn))
+ if(register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP8INTF, i, &bus, &device_fn))
+ if(register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP16INTF, i, &bus, &device_fn))
+ if(register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP32INTF, i, &bus, &device_fn))
+ if(register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP4QUAD, i, &bus, &device_fn))
+ if(register_PCI(count+boards_found, bus, device_fn))
+ count++;
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP8J, i, &bus, &device_fn))
if(register_PCI(count+boards_found, bus, device_fn))
count++;
- if(!pcibios_find_device(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP8INTF,
- i, &bus, &device_fn))
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RPP4, i, &bus, &device_fn))
if(register_PCI(count+boards_found, bus, device_fn))
count++;
- if(!pcibios_find_device(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP16INTF,
- i, &bus, &device_fn))
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RPP8, i, &bus, &device_fn))
if(register_PCI(count+boards_found, bus, device_fn))
count++;
- if(!pcibios_find_device(PCI_VENDOR_ID_RP, PCI_DEVICE_ID_RP32INTF,
- i, &bus, &device_fn))
+ if(!pcibios_find_device(PCI_VENDOR_ID_RP,
+ PCI_DEVICE_ID_RP8M, i, &bus, &device_fn))
if(register_PCI(count+boards_found, bus, device_fn))
count++;
}
@@ -2073,7 +2222,7 @@
isa_boards_found++;
}
#ifdef ENABLE_PCI
- if (pci_present()) {
+ if (pcibios_present()) {
if(isa_boards_found < NUM_BOARDS)
pci_boards_found = init_PCI(isa_boards_found);
} else {
===================================================================
RCS file: drivers/char/RCS/rocket_int.h,v
retrieving revision 1.1
diff -u -r1.1 drivers/char/rocket_int.h
--- drivers/char/rocket_int.h 1998/07/03 20:00:57 1.1
+++ drivers/char/rocket_int.h 1998/07/09 05:11:30
@@ -483,6 +483,18 @@
}

/***************************************************************************
+Function: sDisIXANY
+Purpose: Disable IXANY Software Flow Control
+Call: sDisIXANY(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sDisIXANY(ChP) \
+{ \
+ (ChP)->R[0x0e] = 0x86; \
+ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x0c]); \
+}
+
+/***************************************************************************
Function: DisParity
Purpose: Disable parity
Call: sDisParity(ChP)
@@ -573,6 +585,18 @@
}

/***************************************************************************
+Function: sEnIXANY
+Purpose: Enable IXANY Software Flow Control
+Call: sEnIXANY(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sEnIXANY(ChP) \
+{ \
+ (ChP)->R[0x0e] = 0x21; \
+ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x0c]); \
+}
+
+/***************************************************************************
Function: EnParity
Purpose: Enable parity
Call: sEnParity(ChP)
@@ -647,6 +671,18 @@
}

/***************************************************************************
+Function: sEnTxSoftFlowCtl
+Purpose: Enable Tx Software Flow Control
+Call: sEnTxSoftFlowCtl(ChP)
+ CHANNEL_T *ChP; Ptr to channel structure
+*/
+#define sEnTxSoftFlowCtl(ChP) \
+{ \
+ (ChP)->R[0x06] = 0xc5; \
+ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x04]); \
+}
+
+/***************************************************************************
Function: sGetAiopIntStatus
Purpose: Get the AIOP interrupt status
Call: sGetAiopIntStatus(CtlP,AiopNum)
@@ -985,6 +1021,32 @@
}

/***************************************************************************
+Function: sSetTxXOFFChar
+Purpose: Set the Tx XOFF flow control character
+Call: sSetTxXOFFChar(ChP,Ch)
+ CHANNEL_T *ChP; Ptr to channel structure
+ Byte_t Ch; The value to set the Tx XOFF character to
+*/
+#define sSetTxXOFFChar(ChP,CH) \
+{ \
+ (ChP)->R[0x07] = (CH); \
+ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x04]); \
+}
+
+/***************************************************************************
+Function: sSetTxXONChar
+Purpose: Set the Tx XON flow control character
+Call: sSetTxXONChar(ChP,Ch)
+ CHANNEL_T *ChP; Ptr to channel structure
+ Byte_t Ch; The value to set the Tx XON character to
+*/
+#define sSetTxXONChar(ChP,CH) \
+{ \
+ (ChP)->R[0x0b] = (CH); \
+ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x08]); \
+}
+
+/***************************************************************************
Function: sStartRxProcessor
Purpose: Start a channel's receive processor
Call: sStartRxProcessor(ChP)
@@ -1133,17 +1195,25 @@
#undef PCI_DEVICE_ID_RP32INTF
#endif

-#define PCI_VENDOR_ID_RP 0x11fe
-#define PCI_DEVICE_ID_RP32INTF 0x0001
-#define PCI_DEVICE_ID_RP8INTF 0x0002
-#define PCI_DEVICE_ID_RP16INTF 0x0003
-#define PCI_DEVICE_ID_RP8OCTA 0x0005
+#define PCI_VENDOR_ID_RP 0x11fe
+#define PCI_DEVICE_ID_RP32INTF 0x0001
+#define PCI_DEVICE_ID_RP8INTF 0x0002
+#define PCI_DEVICE_ID_RP16INTF 0x0003
+#define PCI_DEVICE_ID_RP8OCTA 0x0005

-#ifndef RP4QUAD
-#define PCI_DEVICE_ID_RP4QUAD 0x0004
+#ifndef PCI_DEVICE_ID_RP4QUAD
+#define PCI_DEVICE_ID_RP4QUAD 0x0004
#endif
-#ifndef RP8J
-#define PCI_DEVICE_ID_RP8J 0x0006
+#ifndef PCI_DEVICE_ID_RP8J
+#define PCI_DEVICE_ID_RP8J 0x0006
#endif
-
+#ifndef PCI_DEVICE_ID_RPP4
+#define PCI_DEVICE_ID_RPP4 0x000A
+#endif
+#ifndef PCI_DEVICE_ID_RPP8
+#define PCI_DEVICE_ID_RPP8 0x000B
+#endif
+#ifndef PCI_DEVICE_ID_RP8M
+#define PCI_DEVICE_ID_RP8M 0x000C
+#endif

===================================================================
RCS file: include/linux/RCS/pci.h,v
retrieving revision 1.1
diff -u -r1.1 include/linux/pci.h
--- include/linux/pci.h 1998/07/03 20:00:58 1.1
+++ include/linux/pci.h 1998/07/09 05:00:21
@@ -839,10 +839,15 @@
#define PCI_DEVICE_ID_COMPEX_RL2000 0x1401

#define PCI_VENDOR_ID_RP 0x11fe
-#define PCI_DEVICE_ID_RP8OCTA 0x0001
+#define PCI_DEVICE_ID_RP32INTF 0x0001
#define PCI_DEVICE_ID_RP8INTF 0x0002
#define PCI_DEVICE_ID_RP16INTF 0x0003
-#define PCI_DEVICE_ID_RP32INTF 0x0004
+#define PCI_DEVICE_ID_RP4QUAD 0x0004
+#define PCI_DEVICE_ID_RP8OCTA 0x0005
+#define PCI_DEVICE_ID_RP8J 0x0006
+#define PCI_DEVICE_ID_RPP4 0x000A
+#define PCI_DEVICE_ID_RPP8 0x000B
+#define PCI_DEVICE_ID_RP8M 0x000C

#define PCI_VENDOR_ID_CYCLADES 0x120e
#define PCI_DEVICE_ID_CYCLOM_Y_Lo 0x0100
===================================================================
RCS file: drivers/pci/RCS/oldproc.c,v
retrieving revision 1.1
diff -u -r1.1 drivers/pci/oldproc.c
--- drivers/pci/oldproc.c 1998/07/03 20:00:58 1.1
+++ drivers/pci/oldproc.c 1998/07/09 05:02:27
@@ -403,10 +403,15 @@
DEVICE( KINETIC, KINETIC_2915, "2915 CAMAC"),
DEVICE( COMPEX, COMPEX_ENET100VG4, "Readylink ENET100-VG4"),
DEVICE( COMPEX, COMPEX_RL2000, "ReadyLink 2000"),
- DEVICE( RP, RP8OCTA, "RocketPort 8 Oct"),
+ DEVICE( RP, RP32INTF, "RocketPort 32 Intf"),
DEVICE( RP, RP8INTF, "RocketPort 8 Intf"),
DEVICE( RP, RP16INTF, "RocketPort 16 Intf"),
- DEVICE( RP, RP32INTF, "RocketPort 32 Intf"),
+ DEVICE( RP, RP4QUAD, "Rocketport 4 Quad"),
+ DEVICE( RP, RP8OCTA, "RocketPort 8 Oct"),
+ DEVICE( RP, RP8J, "RocketPort 8 J"),
+ DEVICE( RP, RPP4, "RocketPort Plus 4 Quad"),
+ DEVICE( RP, RPP8, "RocketPort Plus 8 Oct"),
+ DEVICE( RP, RP8M, "RocketModem 8 J"),
DEVICE( CYCLADES, CYCLOM_Y_Lo, "Cyclom-Y below 1Mbyte"),
DEVICE( CYCLADES, CYCLOM_Y_Hi, "Cyclom-Y above 1Mbyte"),
DEVICE( CYCLADES, CYCLOM_Z_Lo, "Cyclom-Z below 1Mbyte"),

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu