#define MXSERCUMAJOR 175
#define MXSER_EVENT_TXLOW 1
-#define MXSER_EVENT_HANGUP 2
#define MXSER_BOARDS 4 /* Max. boards */
-#define MXSER_PORTS 32 /* Max. ports */
#define MXSER_PORTS_PER_BOARD 8 /* Max. ports per board */
+#define MXSER_PORTS (MXSER_BOARDS * MXSER_PORTS_PER_BOARD)
#define MXSER_ISR_PASS_LIMIT 99999L
#define MXSER_ERR_IOADDR -1
#define MXSER_ERR_IRQ_CONFLIT -3
#define MXSER_ERR_VECTOR -4
-#define SERIAL_TYPE_NORMAL 1
-#define SERIAL_TYPE_CALLOUT 2
-
#define WAKEUP_CHARS 256
#define UART_MCR_AFE 0x20
};
struct mxser_board {
- struct pci_dev *pdev; /* temporary (until pci probing) */
-
+ unsigned int idx;
int irq;
const struct mxser_cardinfo *info;
unsigned long vector;
static struct mxser_board mxser_boards[MXSER_BOARDS];
static struct tty_driver *mxvar_sdriver;
-static struct tty_struct *mxvar_tty[MXSER_PORTS + 1];
-static struct termios *mxvar_termios[MXSER_PORTS + 1];
-static struct termios *mxvar_termios_locked[MXSER_PORTS + 1];
static struct mxser_log mxvar_log;
static int mxvar_diagflag;
static unsigned char mxser_msr[MXSER_PORTS + 1];
static void mxser_do_softint(void *private_)
{
struct mxser_port *info = private_;
- struct tty_struct *tty;
-
- tty = info->tty;
+ struct tty_struct *tty = info->tty;
if (test_and_clear_bit(MXSER_EVENT_TXLOW, &info->event))
tty_wakeup(tty);
- if (test_and_clear_bit(MXSER_EVENT_HANGUP, &info->event))
- tty_hangup(tty);
}
static unsigned char mxser_get_msr(int baseaddr, int mode, int port)
* The MOXA Smartio/Industio serial driver boot-time initialization code!
*/
-static void mxser_release_res(struct mxser_board *brd, unsigned int irq)
+static void mxser_release_res(struct mxser_board *brd, struct pci_dev *pdev,
+ unsigned int irq)
{
- struct pci_dev *pdev = brd->pdev;
-
if (irq)
free_irq(brd->irq, brd);
if (pdev != NULL) { /* PCI */
}
}
-static int __devinit mxser_initbrd(struct mxser_board *brd)
+static int __devinit mxser_initbrd(struct mxser_board *brd,
+ struct pci_dev *pdev)
{
struct mxser_port *info;
unsigned int i;
"conflict with another device.\n",
brd->info->name, brd->irq);
/* We hold resources, we need to release them. */
- mxser_release_res(brd, 0);
+ mxser_release_res(brd, pdev, 0);
return retval;
}
return 0;
return brd->info->nports;
}
-static int __init mxser_get_PCI_conf(const struct pci_device_id *ent,
- struct mxser_board *brd, struct pci_dev *pdev)
+static int __devinit mxser_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
+ struct mxser_board *brd;
unsigned int i, j;
unsigned long ioaddress;
- int retval;
+ int retval = -EINVAL;
+
+ for (i = 0; i < MXSER_BOARDS; i++)
+ if (mxser_boards[i].info == NULL)
+ break;
+
+ if (i >= MXSER_BOARDS) {
+ printk(KERN_ERR "Too many Smartio/Industio family boards found "
+ "(maximum %d), board not configured\n", MXSER_BOARDS);
+ goto err;
+ }
+
+ brd = &mxser_boards[i];
+ brd->idx = i * MXSER_PORTS_PER_BOARD;
+ printk(KERN_INFO "Found MOXA %s board (BusNo=%d, DevNo=%d)\n",
+ mxser_cards[ent->driver_data].name,
+ pdev->bus->number, PCI_SLOT(pdev->devfn));
+
+ retval = pci_enable_device(pdev);
+ if (retval) {
+ printk(KERN_ERR "Moxa SmartI/O PCI enable fail !\n");
+ goto err;
+ }
/* io address */
- brd->info = &mxser_cards[ent->driver_data];
ioaddress = pci_resource_start(pdev, 2);
retval = pci_request_region(pdev, 2, "mxser(IO)");
if (retval)
goto err;
+ brd->info = &mxser_cards[ent->driver_data];
for (i = 0; i < brd->info->nports; i++)
brd->ports[i].ioaddr = ioaddress + 8 * i;
brd->vector_mask |= (1 << i);
brd->ports[i].baud_base = 921600;
}
+
+ /* mxser_initbrd will hook ISR. */
+ if (mxser_initbrd(brd, pdev) < 0)
+ goto err_relvec;
+
+ for (i = 0; i < brd->info->nports; i++)
+ tty_register_device(mxvar_sdriver, brd->idx + i, &pdev->dev);
+
+ pci_set_drvdata(pdev, brd);
+
return 0;
+err_relvec:
+ pci_release_region(pdev, 3);
err_relio:
pci_release_region(pdev, 2);
+ brd->info = NULL;
err:
return retval;
}
+static void __devexit mxser_remove(struct pci_dev *pdev)
+{
+ struct mxser_board *brd = pci_get_drvdata(pdev);
+ unsigned int i;
+
+ for (i = 0; i < brd->info->nports; i++)
+ tty_unregister_device(mxvar_sdriver, brd->idx + i);
+
+ mxser_release_res(brd, pdev, 1);
+}
+
+static struct pci_driver mxser_driver = {
+ .name = "mxser",
+ .id_table = mxser_pcibrds,
+ .probe = mxser_probe,
+ .remove = __devexit_p(mxser_remove)
+};
+
static int __init mxser_module_init(void)
{
- struct pci_dev *pdev = NULL;
struct mxser_board *brd;
unsigned long cap;
unsigned int i, m, isaloop;
- int retval, b, n;
+ int retval, b;
pr_debug("Loading module mxser ...\n");
/* Initialize the tty_driver structure */
mxvar_sdriver->magic = TTY_DRIVER_MAGIC;
- mxvar_sdriver->name = "ttyM";
+ mxvar_sdriver->name = "ttyMI";
mxvar_sdriver->major = ttymajor;
mxvar_sdriver->minor_start = 0;
mxvar_sdriver->num = MXSER_PORTS + 1;
mxvar_sdriver->init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL;
mxvar_sdriver->flags = TTY_DRIVER_REAL_RAW|TTY_DRIVER_DYNAMIC_DEV;
tty_set_operations(mxvar_sdriver, &mxser_ops);
- mxvar_sdriver->ttys = mxvar_tty;
- mxvar_sdriver->termios = mxvar_termios;
- mxvar_sdriver->termios_locked = mxvar_termios_locked;
retval = tty_register_driver(mxvar_sdriver);
if (retval) {
printk(KERN_ERR "Invalid I/O address, "
"board not configured\n");
+ brd->info = NULL;
continue;
}
- brd->pdev = NULL;
-
/* mxser_initbrd will hook ISR. */
- if (mxser_initbrd(brd) < 0)
- continue;
-
- for (i = 0; i < brd->info->nports; i++)
- tty_register_device(mxvar_sdriver,
- m * MXSER_PORTS_PER_BOARD + i, NULL);
-
- m++;
- }
-
- /* start finding PCI board here */
- n = ARRAY_SIZE(mxser_pcibrds) - 1;
- b = 0;
- while (b < n) {
- pdev = pci_get_device(mxser_pcibrds[b].vendor,
- mxser_pcibrds[b].device, pdev);
- if (pdev == NULL) {
- b++;
- continue;
- }
- printk(KERN_INFO "Found MOXA %s board(BusNo=%d,DevNo=%d)\n",
- mxser_cards[mxser_pcibrds[b].driver_data].name,
- pdev->bus->number, PCI_SLOT(pdev->devfn));
- if (m >= MXSER_BOARDS)
- printk(KERN_ERR
- "Too many Smartio/Industio family boards find "
- "(maximum %d), board not configured\n",
- MXSER_BOARDS);
- else {
- if (pci_enable_device(pdev)) {
- printk(KERN_ERR "Moxa SmartI/O PCI enable "
- "fail !\n");
- continue;
- }
- brd = &mxser_boards[m];
- brd->pdev = pdev;
- retval = mxser_get_PCI_conf(&mxser_pcibrds[b],
- brd, pdev);
- if (retval < 0) {
- if (retval == MXSER_ERR_IRQ)
- printk(KERN_ERR
- "Invalid interrupt number, "
- "board not configured\n");
- else if (retval == MXSER_ERR_IRQ_CONFLIT)
- printk(KERN_ERR
- "Invalid interrupt number, "
- "board not configured\n");
- else if (retval == MXSER_ERR_VECTOR)
- printk(KERN_ERR
- "Invalid interrupt vector, "
- "board not configured\n");
- else if (retval == MXSER_ERR_IOADDR)
- printk(KERN_ERR
- "Invalid I/O address, "
- "board not configured\n");
+ if (mxser_initbrd(brd, NULL) < 0) {
+ brd->info = NULL;
continue;
}
- /* mxser_initbrd will hook ISR. */
- if (mxser_initbrd(brd) < 0)
- continue;
+
+ brd->idx = m * MXSER_PORTS_PER_BOARD;
for (i = 0; i < brd->info->nports; i++)
- tty_register_device(mxvar_sdriver,
- m * MXSER_PORTS_PER_BOARD + i,
- &pdev->dev);
+ tty_register_device(mxvar_sdriver, brd->idx + i,
+ NULL);
m++;
- /* Keep an extra reference if we succeeded. It will
- be returned at unload time */
- pci_dev_get(pdev);
}
- }
- if (!m) {
- retval = -ENODEV;
- goto err_unr;
+ retval = pci_register_driver(&mxser_driver);
+ if (retval) {
+ printk(KERN_ERR "Can't register pci driver\n");
+ if (!m) {
+ retval = -ENODEV;
+ goto err_unr;
+ } /* else: we have some ISA cards under control */
}
pr_debug("Done.\n");
static void __exit mxser_module_exit(void)
{
- unsigned int i;
+ unsigned int i, j;
pr_debug("Unloading module mxser ...\n");
- for (i = 0; i < MXSER_PORTS; i++)
- tty_unregister_device(mxvar_sdriver, i);
+ pci_unregister_driver(&mxser_driver);
+
+ for (i = 0; i < MXSER_BOARDS; i++) /* ISA remains */
+ if (mxser_boards[i].info != NULL)
+ for (j = 0; j < mxser_boards[i].info->nports; j++)
+ tty_unregister_device(mxvar_sdriver,
+ mxser_boards[i].idx + j);
tty_unregister_driver(mxvar_sdriver);
put_tty_driver(mxvar_sdriver);
for (i = 0; i < MXSER_BOARDS; i++)
if (mxser_boards[i].info != NULL)
- mxser_release_res(&mxser_boards[i], 1);
+ mxser_release_res(&mxser_boards[i], NULL, 1);
pr_debug("Done.\n");
}