* Added support for: C102, CI-132, CI-134, CP-132, CP-114, CT-114 cards
* by Damian Wrobel <dwrobel@ertel.com.pl>
*
+ * Added support for serial card CP104
+ * by James Nelson Provident Solutions <linux-info@provident-solutions.com>
*/
#include <linux/config.h>
#define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
/*
* Define the Moxa PCI vendor and device IDs.
*/
#ifndef PCI_DEVICE_ID_C104
#define PCI_DEVICE_ID_C104 0x1040
#endif
+#ifndef PCI_DEVICE_ID_CP104
+#define PCI_DEVICE_ID_CP104 0x1041
+#endif
#ifndef PCI_DEVICE_ID_CP132
#define PCI_DEVICE_ID_CP132 0x1320
#endif
MXSER_BOARD_CI104J,
MXSER_BOARD_C168_PCI,
MXSER_BOARD_C104_PCI,
+ MXSER_BOARD_CP104_PCI,
MXSER_BOARD_C102_ISA,
MXSER_BOARD_CI132,
MXSER_BOARD_CI134,
"CI-104J series",
"C168H/PCI series",
"C104H/PCI series",
+ "CP104/PCI series",
"C102 series",
"CI-132 series",
"CI-134 series",
4,
8,
4,
+ 4,
2,
2,
4,
#define MOXA_GET_CUMAJOR (MOXA + 64)
#define MOXA_GETMSTATUS (MOXA + 65)
+#ifdef CONFIG_PCI
static struct pci_device_id mxser_pcibrds[] = {
{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C168, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
MXSER_BOARD_C168_PCI },
{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_C104, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
MXSER_BOARD_C104_PCI },
+ { PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP104, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ MXSER_BOARD_CP104_PCI },
{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP132, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
MXSER_BOARD_CP132_PCI },
{ PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_CP114, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
{ 0 }
};
MODULE_DEVICE_TABLE(pci, mxser_pcibrds);
+#endif /* CONFIG_PCI */
static int ioaddr[MXSER_BOARDS];
static int ttymajor = MXSERMAJOR;
static void mxser_getcfg(int board, struct mxser_hwconf *hwconf);
static int mxser_get_ISA_conf(int, struct mxser_hwconf *);
-static int mxser_get_PCI_conf(struct pci_dev *, int, struct mxser_hwconf *);
static void mxser_do_softint(void *);
static int mxser_open(struct tty_struct *, struct file *);
static void mxser_close(struct tty_struct *, struct file *);
static void mxser_stop(struct tty_struct *);
static void mxser_start(struct tty_struct *);
static void mxser_hangup(struct tty_struct *);
-static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *);
static inline void mxser_receive_chars(struct mxser_struct *, int *);
static inline void mxser_transmit_chars(struct mxser_struct *);
static inline void mxser_check_modem_status(struct mxser_struct *, int);
+static irqreturn_t mxser_interrupt(int, void *, struct pt_regs *);
static int mxser_block_til_ready(struct tty_struct *, struct file *, struct mxser_struct *);
static int mxser_startup(struct mxser_struct *);
static void mxser_shutdown(struct mxser_struct *);
static int mxser_change_speed(struct mxser_struct *, struct termios *old_termios);
-static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct *);
-static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct *);
-static int mxser_get_lsr_info(struct mxser_struct *, unsigned int *);
+static int mxser_get_serial_info(struct mxser_struct *, struct serial_struct __user *);
+static int mxser_set_serial_info(struct mxser_struct *, struct serial_struct __user *);
+static int mxser_get_lsr_info(struct mxser_struct *, unsigned int __user *);
static void mxser_send_break(struct mxser_struct *, int);
static int mxser_tiocmget(struct tty_struct *, struct file *);
static int mxser_tiocmset(struct tty_struct *, struct file *, unsigned int, unsigned int);
mxsercfg[board] = *hwconf;
}
+#ifdef CONFIG_PCI
static int mxser_get_PCI_conf(struct pci_dev *pdev, int board_type, struct mxser_hwconf *hwconf)
{
int i;
}
return (0);
}
+#endif /* CONFIG_PCI */
static struct tty_operations mxser_ops = {
.open = mxser_open,
{
struct pci_dev *pdev = NULL;
int n = (sizeof(mxser_pcibrds) / sizeof(mxser_pcibrds[0])) - 1;
- int index = 0;
for (b = 0; b < n; b++) {
while ((pdev = pci_find_device(mxser_pcibrds[b].vendor, mxser_pcibrds[b].device, pdev)))
{
tty = info->tty;
if (tty) {
if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event)) {
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup) (tty);
+ tty_wakeup(tty);
wake_up_interruptible(&tty->write_wait);
}
if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event)) {
mxser_shutdown(info);
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
+ tty_ldisc_flush(tty);
+
tty->closing = 0;
info->event = 0;
- info->tty = 0;
+ info->tty = NULL;
if (info->blocked_open) {
if (info->close_delay) {
set_current_state(TASK_INTERRUPTIBLE);
if (from_user) {
down(&mxvar_tmp_buf_sem);
while (1) {
- c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
if (c <= 0)
break;
}
cli();
- c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ c = min_t(int, c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
memcpy(info->xmit_buf + info->xmit_head, mxvar_tmp_buf, c);
info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1);
} else {
while (1) {
cli();
- c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+ c = min_t(int, count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
SERIAL_XMIT_SIZE - info->xmit_head));
if (c <= 0) {
restore_flags(flags);
info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
restore_flags(flags);
wake_up_interruptible(&tty->write_wait);
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup) (tty);
+ tty_wakeup(tty);
}
static int mxser_ioctl(struct tty_struct *tty, struct file *file,
struct mxser_struct *info = (struct mxser_struct *) tty->driver_data;
int retval;
struct async_icount cprev, cnow; /* kernel counter temps */
- struct serial_icounter_struct *p_cuser; /* user space */
+ struct serial_icounter_struct __user *p_cuser;
unsigned long templ;
+ void __user *argp = (void __user *)arg;
if (PORTNO(tty) == MXSER_PORTS)
return (mxser_ioctl_special(cmd, arg));
mxser_send_break(info, arg ? arg * (HZ / 10) : HZ / 4);
return (0);
case TIOCGSOFTCAR:
- return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg);
+ return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);
case TIOCSSOFTCAR:
- if(get_user(templ, (unsigned long *) arg))
+ if(get_user(templ, (unsigned long __user *) arg))
return -EFAULT;
arg = templ;
tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
return (0);
case TIOCGSERIAL:
- return (mxser_get_serial_info(info, (struct serial_struct *) arg));
+ return mxser_get_serial_info(info, argp);
case TIOCSSERIAL:
- return (mxser_set_serial_info(info, (struct serial_struct *) arg));
+ return mxser_set_serial_info(info, argp);
case TIOCSERGETLSR: /* Get line status register */
- return (mxser_get_lsr_info(info, (unsigned int *) arg));
+ return mxser_get_lsr_info(info, argp);
/*
* Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
* - mask passed in arg for lines of interest
cli();
cnow = info->icount;
restore_flags(flags);
- p_cuser = (struct serial_icounter_struct *) arg;
+ p_cuser = argp;
if(put_user(cnow.cts, &p_cuser->cts))
return -EFAULT;
if(put_user(cnow.dsr, &p_cuser->dsr))
return -EFAULT;
return put_user(cnow.dcd, &p_cuser->dcd);
case MOXA_HighSpeedOn:
- return put_user(info->baud_base != 115200 ? 1 : 0, (int *) arg);
+ return put_user(info->baud_base != 115200 ? 1 : 0, (int __user *)argp);
default:
return (-ENOIOCTLCMD);
}
static int mxser_ioctl_special(unsigned int cmd, unsigned long arg)
{
int i, result, status;
+ void __user *argp = (void __user *)arg;
switch (cmd) {
case MOXA_GET_CONF:
- if(copy_to_user((struct mxser_hwconf *) arg, mxsercfg,
+ if(copy_to_user(argp, mxsercfg,
sizeof(struct mxser_hwconf) * 4))
return -EFAULT;
return 0;
case MOXA_GET_MAJOR:
- if(copy_to_user((int *) arg, &ttymajor, sizeof(int)))
+ if(copy_to_user(argp, &ttymajor, sizeof(int)))
return -EFAULT;
return 0;
case MOXA_GET_CUMAJOR:
result = 0;
- if(copy_to_user((int *) arg, &result, sizeof(int)))
+ if(copy_to_user(argp, &result, sizeof(int)))
return -EFAULT;
return 0;
if (mxvar_table[i].base)
result |= (1 << i);
}
- return put_user(result, (unsigned long *) arg);
+ return put_user(result, (unsigned long __user *) argp);
case MOXA_GETDATACOUNT:
- if(copy_to_user((struct mxser_log *) arg, &mxvar_log, sizeof(mxvar_log)))
+ if (copy_to_user(argp, &mxvar_log, sizeof(mxvar_log)))
return -EFAULT;
return (0);
case MOXA_GETMSTATUS:
else
GMStatus[i].cts = 0;
}
- if(copy_to_user((struct mxser_mstatus *) arg, GMStatus,
+ if(copy_to_user(argp, GMStatus,
sizeof(struct mxser_mstatus) * MXSER_PORTS))
return -EFAULT;
return 0;
info->event = 0;
info->count = 0;
info->flags &= ~ASYNC_NORMAL_ACTIVE;
- info->tty = 0;
+ info->tty = NULL;
wake_up_interruptible(&info->open_wait);
}
-/*
- * This is the serial driver's generic interrupt routine
- */
-static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
- int status, i;
- struct mxser_struct *info;
- struct mxser_struct *port;
- int max, irqbits, bits, msr;
- int pass_counter = 0;
- int handled = 0;
-
- port = 0;
- for (i = 0; i < MXSER_BOARDS; i++) {
- if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) {
- port = dev_id;
- break;
- }
- }
-
- if (i == MXSER_BOARDS)
- return IRQ_NONE;
- if (port == 0)
- return IRQ_NONE;
- max = mxser_numports[mxsercfg[i].board_type];
-
- while (1) {
- irqbits = inb(port->vector) & port->vectormask;
- if (irqbits == port->vectormask)
- break;
- handled = 1;
- for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
- if (irqbits == port->vectormask)
- break;
- if (bits & irqbits)
- continue;
- info = port + i;
- if (!info->tty ||
- (inb(info->base + UART_IIR) & UART_IIR_NO_INT))
- continue;
- status = inb(info->base + UART_LSR) & info->read_status_mask;
- if (status & UART_LSR_DR)
- mxser_receive_chars(info, &status);
- msr = inb(info->base + UART_MSR);
- if (msr & UART_MSR_ANY_DELTA)
- mxser_check_modem_status(info, msr);
- if (status & UART_LSR_THRE) {
-/* 8-2-99 by William
- if ( info->x_char || (info->xmit_cnt > 0) )
- */
- mxser_transmit_chars(info);
- }
- }
- if (pass_counter++ > MXSER_ISR_PASS_LIMIT) {
-#if 0
- printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n");
-#endif
- break; /* Prevent infinite loops */
- }
- }
- return IRQ_RETVAL(handled);
-}
-
static inline void mxser_receive_chars(struct mxser_struct *info,
int *status)
{
}
}
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+static irqreturn_t mxser_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ int status, i;
+ struct mxser_struct *info;
+ struct mxser_struct *port;
+ int max, irqbits, bits, msr;
+ int pass_counter = 0;
+ int handled = 0;
+
+ port = NULL;
+ for (i = 0; i < MXSER_BOARDS; i++) {
+ if (dev_id == &(mxvar_table[i * MXSER_PORTS_PER_BOARD])) {
+ port = dev_id;
+ break;
+ }
+ }
+
+ if (i == MXSER_BOARDS)
+ return IRQ_NONE;
+ if (port == 0)
+ return IRQ_NONE;
+ max = mxser_numports[mxsercfg[i].board_type];
+
+ while (1) {
+ irqbits = inb(port->vector) & port->vectormask;
+ if (irqbits == port->vectormask)
+ break;
+ handled = 1;
+ for (i = 0, bits = 1; i < max; i++, irqbits |= bits, bits <<= 1) {
+ if (irqbits == port->vectormask)
+ break;
+ if (bits & irqbits)
+ continue;
+ info = port + i;
+ if (!info->tty ||
+ (inb(info->base + UART_IIR) & UART_IIR_NO_INT))
+ continue;
+ status = inb(info->base + UART_LSR) & info->read_status_mask;
+ if (status & UART_LSR_DR)
+ mxser_receive_chars(info, &status);
+ msr = inb(info->base + UART_MSR);
+ if (msr & UART_MSR_ANY_DELTA)
+ mxser_check_modem_status(info, msr);
+ if (status & UART_LSR_THRE) {
+/* 8-2-99 by William
+ if ( info->x_char || (info->xmit_cnt > 0) )
+ */
+ mxser_transmit_chars(info);
+ }
+ }
+ if (pass_counter++ > MXSER_ISR_PASS_LIMIT) {
+#if 0
+ printk("MOXA Smartio/Indusrtio family driver interrupt loop break\n");
+#endif
+ break; /* Prevent infinite loops */
+ }
+ }
+ return IRQ_RETVAL(handled);
+}
+
static int mxser_block_til_ready(struct tty_struct *tty, struct file *filp,
struct mxser_struct *info)
{
/*
* and set the speed of the serial port
*/
- mxser_change_speed(info, 0);
+ mxser_change_speed(info, NULL);
info->flags |= ASYNC_INITIALIZED;
restore_flags(flags);
*/
if (info->xmit_buf) {
free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
+ info->xmit_buf = NULL;
}
info->IER = 0;
outb(0x00, info->base + UART_IER); /* disable all intrs */
* ------------------------------------------------------------
*/
static int mxser_get_serial_info(struct mxser_struct *info,
- struct serial_struct *retinfo)
+ struct serial_struct __user *retinfo)
{
struct serial_struct tmp;
}
static int mxser_set_serial_info(struct mxser_struct *info,
- struct serial_struct *new_info)
+ struct serial_struct __user *new_info)
{
struct serial_struct new_serial;
unsigned int flags;
if (info->flags & ASYNC_INITIALIZED) {
if (flags != (info->flags & ASYNC_SPD_MASK)) {
- mxser_change_speed(info, 0);
+ mxser_change_speed(info, NULL);
}
} else
retval = mxser_startup(info);
* transmit holding register is empty. This functionality
* allows an RS485 driver to be written in user space.
*/
-static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int *value)
+static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int __user *value)
{
unsigned char status;
unsigned int result;