in devices/ipoctal.c [274:437]
static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr,
unsigned int slot)
{
int res;
int i;
struct tty_driver *drv;
struct ipoctal_channel *channel;
struct ipack_region *region;
void __iomem *addr;
union scc2698_channel __iomem *chan_regs;
union scc2698_block __iomem *block_regs;
ipoctal->board_id = ipoctal->dev->id_device;
region = &ipoctal->dev->region[IPACK_IO_SPACE];
addr = devm_ioremap(&ipoctal->dev->dev,
region->start, region->size);
if (!addr) {
dev_err(&ipoctal->dev->dev,
"Unable to map slot [%d:%d] IO space!\n",
bus_nr, slot);
return -EADDRNOTAVAIL;
}
/* Save the virtual address to access the registers easily */
chan_regs =
(union scc2698_channel __iomem *) addr;
block_regs =
(union scc2698_block __iomem *) addr;
region = &ipoctal->dev->region[IPACK_INT_SPACE];
ipoctal->int_space =
devm_ioremap(&ipoctal->dev->dev,
region->start, region->size);
if (!ipoctal->int_space) {
dev_err(&ipoctal->dev->dev,
"Unable to map slot [%d:%d] INT space!\n",
bus_nr, slot);
return -EADDRNOTAVAIL;
}
region = &ipoctal->dev->region[IPACK_MEM8_SPACE];
ipoctal->mem8_space =
devm_ioremap(&ipoctal->dev->dev,
region->start, 0x8000);
if (!ipoctal->mem8_space) {
dev_err(&ipoctal->dev->dev,
"Unable to map slot [%d:%d] MEM8 space!\n",
bus_nr, slot);
return -EADDRNOTAVAIL;
}
/* Disable RX and TX before touching anything */
for (i = 0; i < NR_CHANNELS ; i++) {
struct ipoctal_channel *channel = &ipoctal->channel[i];
channel->regs = chan_regs + i;
channel->block_regs = block_regs + (i >> 1);
channel->board_id = ipoctal->board_id;
if (i & 1) {
channel->isr_tx_rdy_mask = ISR_TxRDY_B;
channel->isr_rx_rdy_mask = ISR_RxRDY_FFULL_B;
} else {
channel->isr_tx_rdy_mask = ISR_TxRDY_A;
channel->isr_rx_rdy_mask = ISR_RxRDY_FFULL_A;
}
ipoctal_reset_channel(channel);
iowrite8(MR1_CHRL_8_BITS | MR1_ERROR_CHAR | MR1_RxINT_RxRDY,
&channel->regs->w.mr); /* mr1 */
iowrite8(0, &channel->regs->w.mr); /* mr2 */
iowrite8(TX_CLK_9600 | RX_CLK_9600, &channel->regs->w.csr);
}
for (i = 0; i < IP_OCTAL_NB_BLOCKS; i++) {
iowrite8(ACR_BRG_SET2, &block_regs[i].w.acr);
iowrite8(OPCR_MPP_OUTPUT | OPCR_MPOa_RTSN | OPCR_MPOb_RTSN,
&block_regs[i].w.opcr);
iowrite8(IMR_TxRDY_A | IMR_RxRDY_FFULL_A | IMR_DELTA_BREAK_A |
IMR_TxRDY_B | IMR_RxRDY_FFULL_B | IMR_DELTA_BREAK_B,
&block_regs[i].w.imr);
}
/* Dummy write */
iowrite8(1, ipoctal->mem8_space + 1);
/* Register the TTY device */
/* Each IP-OCTAL channel is a TTY port */
drv = tty_alloc_driver(NR_CHANNELS, TTY_DRIVER_REAL_RAW |
TTY_DRIVER_DYNAMIC_DEV);
if (IS_ERR(drv))
return PTR_ERR(drv);
/* Fill struct tty_driver with ipoctal data */
drv->owner = THIS_MODULE;
drv->driver_name = KBUILD_MODNAME;
drv->name = kasprintf(GFP_KERNEL, KBUILD_MODNAME ".%d.%d.", bus_nr, slot);
if (!drv->name) {
res = -ENOMEM;
goto err_put_driver;
}
drv->major = 0;
drv->minor_start = 0;
drv->type = TTY_DRIVER_TYPE_SERIAL;
drv->subtype = SERIAL_TYPE_NORMAL;
drv->init_termios = tty_std_termios;
drv->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
drv->init_termios.c_ispeed = 9600;
drv->init_termios.c_ospeed = 9600;
tty_set_operations(drv, &ipoctal_fops);
res = tty_register_driver(drv);
if (res) {
dev_err(&ipoctal->dev->dev, "Can't register tty driver.\n");
goto err_free_name;
}
/* Save struct tty_driver for use it when uninstalling the device */
ipoctal->tty_drv = drv;
for (i = 0; i < NR_CHANNELS; i++) {
struct device *tty_dev;
channel = &ipoctal->channel[i];
tty_port_init(&channel->tty_port);
res = tty_port_alloc_xmit_buf(&channel->tty_port);
if (res)
continue;
channel->tty_port.ops = &ipoctal_tty_port_ops;
ipoctal_reset_stats(&channel->stats);
channel->nb_bytes = 0;
spin_lock_init(&channel->lock);
channel->pointer_read = 0;
channel->pointer_write = 0;
tty_dev = tty_port_register_device_attr(&channel->tty_port, drv,
i, NULL, channel, NULL);
if (IS_ERR(tty_dev)) {
dev_err(&ipoctal->dev->dev, "Failed to register tty device.\n");
tty_port_free_xmit_buf(&channel->tty_port);
tty_port_destroy(&channel->tty_port);
continue;
}
channel->tty_registered = true;
}
/*
* IP-OCTAL has different addresses to copy its IRQ vector.
* Depending of the carrier these addresses are accesible or not.
* More info in the datasheet.
*/
ipoctal->dev->bus->ops->request_irq(ipoctal->dev,
ipoctal_irq_handler, ipoctal);
return 0;
err_free_name:
kfree(drv->name);
err_put_driver:
tty_driver_kref_put(drv);
return res;
}