441 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Moxa C101 synchronous serial card driver for Linux4 *5 * Copyright (C) 2000-2003 Krzysztof Halasa <khc@pm.waw.pl>6 *7 * For information see <https://www.kernel.org/pub/linux/utils/net/hdlc/>8 *9 * Sources of information:10 * Hitachi HD64570 SCA User's Manual11 * Moxa C101 User's Manual12 */13 14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt15 16#include <linux/module.h>17#include <linux/kernel.h>18#include <linux/capability.h>19#include <linux/slab.h>20#include <linux/types.h>21#include <linux/string.h>22#include <linux/errno.h>23#include <linux/init.h>24#include <linux/netdevice.h>25#include <linux/hdlc.h>26#include <linux/delay.h>27#include <asm/io.h>28 29#include "hd64570.h"30 31static const char *version = "Moxa C101 driver version: 1.15";32static const char *devname = "C101";33 34#undef DEBUG_PKT35#define DEBUG_RINGS36 37#define C101_PAGE 0x1D0038#define C101_DTR 0x1E0039#define C101_SCA 0x1F0040#define C101_WINDOW_SIZE 0x200041#define C101_MAPPED_RAM_SIZE 0x400042 43#define RAM_SIZE (256 * 1024)44#define TX_RING_BUFFERS 1045#define RX_RING_BUFFERS ((RAM_SIZE - C101_WINDOW_SIZE) / \46 (sizeof(pkt_desc) + HDLC_MAX_MRU) - TX_RING_BUFFERS)47 48#define CLOCK_BASE 9830400 /* 9.8304 MHz */49#define PAGE0_ALWAYS_MAPPED50 51static char *hw; /* pointer to hw=xxx command line string */52 53typedef struct card_s {54 struct net_device *dev;55 spinlock_t lock; /* TX lock */56 u8 __iomem *win0base; /* ISA window base address */57 u32 phy_winbase; /* ISA physical base address */58 sync_serial_settings settings;59 int rxpart; /* partial frame received, next frame invalid*/60 unsigned short encoding;61 unsigned short parity;62 u16 rx_ring_buffers; /* number of buffers in a ring */63 u16 tx_ring_buffers;64 u16 buff_offset; /* offset of first buffer of first channel */65 u16 rxin; /* rx ring buffer 'in' pointer */66 u16 txin; /* tx ring buffer 'in' and 'last' pointers */67 u16 txlast;68 u8 rxs, txs, tmc; /* SCA registers */69 u8 irq; /* IRQ (3-15) */70 u8 page;71 72 struct card_s *next_card;73} card_t;74 75typedef card_t port_t;76 77static card_t *first_card;78static card_t **new_card = &first_card;79 80#define sca_in(reg, card) readb((card)->win0base + C101_SCA + (reg))81#define sca_out(value, reg, card) writeb(value, (card)->win0base + C101_SCA + (reg))82#define sca_inw(reg, card) readw((card)->win0base + C101_SCA + (reg))83 84/* EDA address register must be set in EDAL, EDAH order - 8 bit ISA bus */85#define sca_outw(value, reg, card) do { \86 writeb(value & 0xFF, (card)->win0base + C101_SCA + (reg)); \87 writeb((value >> 8) & 0xFF, (card)->win0base + C101_SCA + (reg + 1));\88} while (0)89 90#define port_to_card(port) (port)91#define log_node(port) (0)92#define phy_node(port) (0)93#define winsize(card) (C101_WINDOW_SIZE)94#define win0base(card) ((card)->win0base)95#define winbase(card) ((card)->win0base + 0x2000)96#define get_port(card, port) (card)97static void sca_msci_intr(port_t *port);98 99static inline u8 sca_get_page(card_t *card)100{101 return card->page;102}103 104static inline void openwin(card_t *card, u8 page)105{106 card->page = page;107 writeb(page, card->win0base + C101_PAGE);108}109 110#include "hd64570.c"111 112static inline void set_carrier(port_t *port)113{114 if (!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD))115 netif_carrier_on(port_to_dev(port));116 else117 netif_carrier_off(port_to_dev(port));118}119 120static void sca_msci_intr(port_t *port)121{122 u8 stat = sca_in(MSCI0_OFFSET + ST1, port); /* read MSCI ST1 status */123 124 /* Reset MSCI TX underrun and CDCD (ignored) status bit */125 sca_out(stat & (ST1_UDRN | ST1_CDCD), MSCI0_OFFSET + ST1, port);126 127 if (stat & ST1_UDRN) {128 /* TX Underrun error detected */129 port_to_dev(port)->stats.tx_errors++;130 port_to_dev(port)->stats.tx_fifo_errors++;131 }132 133 stat = sca_in(MSCI1_OFFSET + ST1, port); /* read MSCI1 ST1 status */134 /* Reset MSCI CDCD status bit - uses ch#2 DCD input */135 sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, port);136 137 if (stat & ST1_CDCD)138 set_carrier(port);139}140 141static void c101_set_iface(port_t *port)142{143 u8 rxs = port->rxs & CLK_BRG_MASK;144 u8 txs = port->txs & CLK_BRG_MASK;145 146 switch (port->settings.clock_type) {147 case CLOCK_INT:148 rxs |= CLK_BRG_RX; /* TX clock */149 txs |= CLK_RXCLK_TX; /* BRG output */150 break;151 152 case CLOCK_TXINT:153 rxs |= CLK_LINE_RX; /* RXC input */154 txs |= CLK_BRG_TX; /* BRG output */155 break;156 157 case CLOCK_TXFROMRX:158 rxs |= CLK_LINE_RX; /* RXC input */159 txs |= CLK_RXCLK_TX; /* RX clock */160 break;161 162 default: /* EXTernal clock */163 rxs |= CLK_LINE_RX; /* RXC input */164 txs |= CLK_LINE_TX; /* TXC input */165 }166 167 port->rxs = rxs;168 port->txs = txs;169 sca_out(rxs, MSCI1_OFFSET + RXS, port);170 sca_out(txs, MSCI1_OFFSET + TXS, port);171 sca_set_port(port);172}173 174static int c101_open(struct net_device *dev)175{176 port_t *port = dev_to_port(dev);177 int result;178 179 result = hdlc_open(dev);180 if (result)181 return result;182 183 writeb(1, port->win0base + C101_DTR);184 sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */185 sca_open(dev);186 /* DCD is connected to port 2 !@#$%^& - disable MSCI0 CDCD interrupt */187 sca_out(IE1_UDRN, MSCI0_OFFSET + IE1, port);188 sca_out(IE0_TXINT, MSCI0_OFFSET + IE0, port);189 190 set_carrier(port);191 192 /* enable MSCI1 CDCD interrupt */193 sca_out(IE1_CDCD, MSCI1_OFFSET + IE1, port);194 sca_out(IE0_RXINTA, MSCI1_OFFSET + IE0, port);195 sca_out(0x48, IER0, port); /* TXINT #0 and RXINT #1 */196 c101_set_iface(port);197 return 0;198}199 200static int c101_close(struct net_device *dev)201{202 port_t *port = dev_to_port(dev);203 204 sca_close(dev);205 writeb(0, port->win0base + C101_DTR);206 sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port);207 hdlc_close(dev);208 return 0;209}210 211static int c101_siocdevprivate(struct net_device *dev, struct ifreq *ifr,212 void __user *data, int cmd)213{214#ifdef DEBUG_RINGS215 port_t *port = dev_to_port(dev);216 217 if (cmd == SIOCDEVPRIVATE) {218 sca_dump_rings(dev);219 printk(KERN_DEBUG "MSCI1: ST: %02x %02x %02x %02x\n",220 sca_in(MSCI1_OFFSET + ST0, port),221 sca_in(MSCI1_OFFSET + ST1, port),222 sca_in(MSCI1_OFFSET + ST2, port),223 sca_in(MSCI1_OFFSET + ST3, port));224 return 0;225 }226#endif227 228 return -EOPNOTSUPP;229}230 231static int c101_ioctl(struct net_device *dev, struct if_settings *ifs)232{233 const size_t size = sizeof(sync_serial_settings);234 sync_serial_settings new_line;235 sync_serial_settings __user *line = ifs->ifs_ifsu.sync;236 port_t *port = dev_to_port(dev);237 238 switch (ifs->type) {239 case IF_GET_IFACE:240 ifs->type = IF_IFACE_SYNC_SERIAL;241 if (ifs->size < size) {242 ifs->size = size; /* data size wanted */243 return -ENOBUFS;244 }245 if (copy_to_user(line, &port->settings, size))246 return -EFAULT;247 return 0;248 249 case IF_IFACE_SYNC_SERIAL:250 if (!capable(CAP_NET_ADMIN))251 return -EPERM;252 253 if (copy_from_user(&new_line, line, size))254 return -EFAULT;255 256 if (new_line.clock_type != CLOCK_EXT &&257 new_line.clock_type != CLOCK_TXFROMRX &&258 new_line.clock_type != CLOCK_INT &&259 new_line.clock_type != CLOCK_TXINT)260 return -EINVAL; /* No such clock setting */261 262 if (new_line.loopback != 0 && new_line.loopback != 1)263 return -EINVAL;264 265 memcpy(&port->settings, &new_line, size); /* Update settings */266 c101_set_iface(port);267 return 0;268 269 default:270 return hdlc_ioctl(dev, ifs);271 }272}273 274static void c101_destroy_card(card_t *card)275{276 readb(card->win0base + C101_PAGE); /* Resets SCA? */277 278 if (card->irq)279 free_irq(card->irq, card);280 281 if (card->win0base) {282 iounmap(card->win0base);283 release_mem_region(card->phy_winbase, C101_MAPPED_RAM_SIZE);284 }285 286 free_netdev(card->dev);287 288 kfree(card);289}290 291static const struct net_device_ops c101_ops = {292 .ndo_open = c101_open,293 .ndo_stop = c101_close,294 .ndo_start_xmit = hdlc_start_xmit,295 .ndo_siocwandev = c101_ioctl,296 .ndo_siocdevprivate = c101_siocdevprivate,297};298 299static int __init c101_run(unsigned long irq, unsigned long winbase)300{301 struct net_device *dev;302 hdlc_device *hdlc;303 card_t *card;304 int result;305 306 if (irq < 3 || irq > 15 || irq == 6) /* FIXME */ {307 pr_err("invalid IRQ value\n");308 return -ENODEV;309 }310 311 if (winbase < 0xC0000 || winbase > 0xDFFFF || (winbase & 0x3FFF) != 0) {312 pr_err("invalid RAM value\n");313 return -ENODEV;314 }315 316 card = kzalloc(sizeof(card_t), GFP_KERNEL);317 if (!card)318 return -ENOBUFS;319 320 card->dev = alloc_hdlcdev(card);321 if (!card->dev) {322 pr_err("unable to allocate memory\n");323 kfree(card);324 return -ENOBUFS;325 }326 327 if (request_irq(irq, sca_intr, 0, devname, card)) {328 pr_err("could not allocate IRQ\n");329 c101_destroy_card(card);330 return -EBUSY;331 }332 card->irq = irq;333 334 if (!request_mem_region(winbase, C101_MAPPED_RAM_SIZE, devname)) {335 pr_err("could not request RAM window\n");336 c101_destroy_card(card);337 return -EBUSY;338 }339 card->phy_winbase = winbase;340 card->win0base = ioremap(winbase, C101_MAPPED_RAM_SIZE);341 if (!card->win0base) {342 pr_err("could not map I/O address\n");343 c101_destroy_card(card);344 return -EFAULT;345 }346 347 card->tx_ring_buffers = TX_RING_BUFFERS;348 card->rx_ring_buffers = RX_RING_BUFFERS;349 card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */350 351 readb(card->win0base + C101_PAGE); /* Resets SCA? */352 udelay(100);353 writeb(0, card->win0base + C101_PAGE);354 writeb(0, card->win0base + C101_DTR); /* Power-up for RAM? */355 356 sca_init(card, 0);357 358 dev = port_to_dev(card);359 hdlc = dev_to_hdlc(dev);360 361 spin_lock_init(&card->lock);362 dev->irq = irq;363 dev->mem_start = winbase;364 dev->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1;365 dev->tx_queue_len = 50;366 dev->netdev_ops = &c101_ops;367 hdlc->attach = sca_attach;368 hdlc->xmit = sca_xmit;369 card->settings.clock_type = CLOCK_EXT;370 371 result = register_hdlc_device(dev);372 if (result) {373 pr_warn("unable to register hdlc device\n");374 c101_destroy_card(card);375 return result;376 }377 378 sca_init_port(card); /* Set up C101 memory */379 set_carrier(card);380 381 netdev_info(dev, "Moxa C101 on IRQ%u, using %u TX + %u RX packets rings\n",382 card->irq, card->tx_ring_buffers, card->rx_ring_buffers);383 384 *new_card = card;385 new_card = &card->next_card;386 return 0;387}388 389static int __init c101_init(void)390{391 if (!hw) {392#ifdef MODULE393 pr_info("no card initialized\n");394#endif395 return -EINVAL; /* no parameters specified, abort */396 }397 398 pr_info("%s\n", version);399 400 do {401 unsigned long irq, ram;402 403 irq = simple_strtoul(hw, &hw, 0);404 405 if (*hw++ != ',')406 break;407 ram = simple_strtoul(hw, &hw, 0);408 409 if (*hw == ':' || *hw == '\x0')410 c101_run(irq, ram);411 412 if (*hw == '\x0')413 return first_card ? 0 : -EINVAL;414 } while (*hw++ == ':');415 416 pr_err("invalid hardware parameters\n");417 return first_card ? 0 : -EINVAL;418}419 420static void __exit c101_cleanup(void)421{422 card_t *card = first_card;423 424 while (card) {425 card_t *ptr = card;426 427 card = card->next_card;428 unregister_hdlc_device(port_to_dev(ptr));429 c101_destroy_card(ptr);430 }431}432 433module_init(c101_init);434module_exit(c101_cleanup);435 436MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");437MODULE_DESCRIPTION("Moxa C101 serial port driver");438MODULE_LICENSE("GPL v2");439module_param(hw, charp, 0444);440MODULE_PARM_DESC(hw, "irq,ram:irq,...");441