11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Moxa C101 synchronous serial card driver for Linux 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2000-2003 Krzysztof Halasa <khc@pm.waw.pl> 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify it 71da177e4SLinus Torvalds * under the terms of version 2 of the GNU General Public License 81da177e4SLinus Torvalds * as published by the Free Software Foundation. 91da177e4SLinus Torvalds * 10467c432aSKrzysztof Halasa * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/> 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * Sources of information: 131da177e4SLinus Torvalds * Hitachi HD64570 SCA User's Manual 141da177e4SLinus Torvalds * Moxa C101 User's Manual 151da177e4SLinus Torvalds */ 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds #include <linux/module.h> 181da177e4SLinus Torvalds #include <linux/kernel.h> 1986ae13b0SIngo Molnar #include <linux/capability.h> 201da177e4SLinus Torvalds #include <linux/slab.h> 211da177e4SLinus Torvalds #include <linux/types.h> 221da177e4SLinus Torvalds #include <linux/string.h> 231da177e4SLinus Torvalds #include <linux/errno.h> 241da177e4SLinus Torvalds #include <linux/init.h> 251da177e4SLinus Torvalds #include <linux/moduleparam.h> 261da177e4SLinus Torvalds #include <linux/netdevice.h> 271da177e4SLinus Torvalds #include <linux/hdlc.h> 281da177e4SLinus Torvalds #include <linux/delay.h> 291da177e4SLinus Torvalds #include <asm/io.h> 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds #include "hd64570.h" 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds static const char* version = "Moxa C101 driver version: 1.15"; 351da177e4SLinus Torvalds static const char* devname = "C101"; 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds #undef DEBUG_PKT 381da177e4SLinus Torvalds #define DEBUG_RINGS 391da177e4SLinus Torvalds 401da177e4SLinus Torvalds #define C101_PAGE 0x1D00 411da177e4SLinus Torvalds #define C101_DTR 0x1E00 421da177e4SLinus Torvalds #define C101_SCA 0x1F00 431da177e4SLinus Torvalds #define C101_WINDOW_SIZE 0x2000 441da177e4SLinus Torvalds #define C101_MAPPED_RAM_SIZE 0x4000 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds #define RAM_SIZE (256 * 1024) 471da177e4SLinus Torvalds #define TX_RING_BUFFERS 10 481da177e4SLinus Torvalds #define RX_RING_BUFFERS ((RAM_SIZE - C101_WINDOW_SIZE) / \ 491da177e4SLinus Torvalds (sizeof(pkt_desc) + HDLC_MAX_MRU) - TX_RING_BUFFERS) 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds #define CLOCK_BASE 9830400 /* 9.8304 MHz */ 521da177e4SLinus Torvalds #define PAGE0_ALWAYS_MAPPED 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds static char *hw; /* pointer to hw=xxx command line string */ 551da177e4SLinus Torvalds 561da177e4SLinus Torvalds 571da177e4SLinus Torvalds typedef struct card_s { 581da177e4SLinus Torvalds struct net_device *dev; 591da177e4SLinus Torvalds spinlock_t lock; /* TX lock */ 601da177e4SLinus Torvalds u8 __iomem *win0base; /* ISA window base address */ 611da177e4SLinus Torvalds u32 phy_winbase; /* ISA physical base address */ 621da177e4SLinus Torvalds sync_serial_settings settings; 631da177e4SLinus Torvalds int rxpart; /* partial frame received, next frame invalid*/ 641da177e4SLinus Torvalds unsigned short encoding; 651da177e4SLinus Torvalds unsigned short parity; 661da177e4SLinus Torvalds u16 rx_ring_buffers; /* number of buffers in a ring */ 671da177e4SLinus Torvalds u16 tx_ring_buffers; 681da177e4SLinus Torvalds u16 buff_offset; /* offset of first buffer of first channel */ 691da177e4SLinus Torvalds u16 rxin; /* rx ring buffer 'in' pointer */ 701da177e4SLinus Torvalds u16 txin; /* tx ring buffer 'in' and 'last' pointers */ 711da177e4SLinus Torvalds u16 txlast; 721da177e4SLinus Torvalds u8 rxs, txs, tmc; /* SCA registers */ 731da177e4SLinus Torvalds u8 irq; /* IRQ (3-15) */ 741da177e4SLinus Torvalds u8 page; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds struct card_s *next_card; 771da177e4SLinus Torvalds }card_t; 781da177e4SLinus Torvalds 791da177e4SLinus Torvalds typedef card_t port_t; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds static card_t *first_card; 821da177e4SLinus Torvalds static card_t **new_card = &first_card; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds #define sca_in(reg, card) readb((card)->win0base + C101_SCA + (reg)) 861da177e4SLinus Torvalds #define sca_out(value, reg, card) writeb(value, (card)->win0base + C101_SCA + (reg)) 871da177e4SLinus Torvalds #define sca_inw(reg, card) readw((card)->win0base + C101_SCA + (reg)) 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds /* EDA address register must be set in EDAL, EDAH order - 8 bit ISA bus */ 901da177e4SLinus Torvalds #define sca_outw(value, reg, card) do { \ 911da177e4SLinus Torvalds writeb(value & 0xFF, (card)->win0base + C101_SCA + (reg)); \ 921da177e4SLinus Torvalds writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg + 1));\ 931da177e4SLinus Torvalds } while(0) 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds #define port_to_card(port) (port) 961da177e4SLinus Torvalds #define log_node(port) (0) 971da177e4SLinus Torvalds #define phy_node(port) (0) 981da177e4SLinus Torvalds #define winsize(card) (C101_WINDOW_SIZE) 991da177e4SLinus Torvalds #define win0base(card) ((card)->win0base) 1001da177e4SLinus Torvalds #define winbase(card) ((card)->win0base + 0x2000) 1011da177e4SLinus Torvalds #define get_port(card, port) (card) 1021da177e4SLinus Torvalds static void sca_msci_intr(port_t *port); 1031da177e4SLinus Torvalds 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds static inline u8 sca_get_page(card_t *card) 1061da177e4SLinus Torvalds { 1071da177e4SLinus Torvalds return card->page; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds static inline void openwin(card_t *card, u8 page) 1111da177e4SLinus Torvalds { 1121da177e4SLinus Torvalds card->page = page; 1131da177e4SLinus Torvalds writeb(page, card->win0base + C101_PAGE); 1141da177e4SLinus Torvalds } 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds 1176b40aba3SKrzysztof Hałasa #include "hd64570.c" 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds 120c2ce9204SKrzysztof Halasa static inline void set_carrier(port_t *port) 121c2ce9204SKrzysztof Halasa { 122a76b044aSKrzysztof Halasa if (!(sca_in(MSCI1_OFFSET + ST3, port) & ST3_DCD)) 123c2ce9204SKrzysztof Halasa netif_carrier_on(port_to_dev(port)); 124c2ce9204SKrzysztof Halasa else 125c2ce9204SKrzysztof Halasa netif_carrier_off(port_to_dev(port)); 126c2ce9204SKrzysztof Halasa } 127c2ce9204SKrzysztof Halasa 128c2ce9204SKrzysztof Halasa 1291da177e4SLinus Torvalds static void sca_msci_intr(port_t *port) 1301da177e4SLinus Torvalds { 131a76b044aSKrzysztof Halasa u8 stat = sca_in(MSCI0_OFFSET + ST1, port); /* read MSCI ST1 status */ 1321da177e4SLinus Torvalds 133a76b044aSKrzysztof Halasa /* Reset MSCI TX underrun and CDCD (ignored) status bit */ 134a76b044aSKrzysztof Halasa sca_out(stat & (ST1_UDRN | ST1_CDCD), MSCI0_OFFSET + ST1, port); 1351da177e4SLinus Torvalds 1361da177e4SLinus Torvalds if (stat & ST1_UDRN) { 137198191c4SKrzysztof Halasa /* TX Underrun error detected */ 138198191c4SKrzysztof Halasa port_to_dev(port)->stats.tx_errors++; 139198191c4SKrzysztof Halasa port_to_dev(port)->stats.tx_fifo_errors++; 1401da177e4SLinus Torvalds } 1411da177e4SLinus Torvalds 142a76b044aSKrzysztof Halasa stat = sca_in(MSCI1_OFFSET + ST1, port); /* read MSCI1 ST1 status */ 1431da177e4SLinus Torvalds /* Reset MSCI CDCD status bit - uses ch#2 DCD input */ 144c2ce9204SKrzysztof Halasa sca_out(stat & ST1_CDCD, MSCI1_OFFSET + ST1, port); 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds if (stat & ST1_CDCD) 147c2ce9204SKrzysztof Halasa set_carrier(port); 1481da177e4SLinus Torvalds } 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds static void c101_set_iface(port_t *port) 1521da177e4SLinus Torvalds { 1531da177e4SLinus Torvalds u8 rxs = port->rxs & CLK_BRG_MASK; 1541da177e4SLinus Torvalds u8 txs = port->txs & CLK_BRG_MASK; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds switch(port->settings.clock_type) { 1571da177e4SLinus Torvalds case CLOCK_INT: 1581da177e4SLinus Torvalds rxs |= CLK_BRG_RX; /* TX clock */ 1591da177e4SLinus Torvalds txs |= CLK_RXCLK_TX; /* BRG output */ 1601da177e4SLinus Torvalds break; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds case CLOCK_TXINT: 1631da177e4SLinus Torvalds rxs |= CLK_LINE_RX; /* RXC input */ 1641da177e4SLinus Torvalds txs |= CLK_BRG_TX; /* BRG output */ 1651da177e4SLinus Torvalds break; 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds case CLOCK_TXFROMRX: 1681da177e4SLinus Torvalds rxs |= CLK_LINE_RX; /* RXC input */ 1691da177e4SLinus Torvalds txs |= CLK_RXCLK_TX; /* RX clock */ 1701da177e4SLinus Torvalds break; 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds default: /* EXTernal clock */ 1731da177e4SLinus Torvalds rxs |= CLK_LINE_RX; /* RXC input */ 1741da177e4SLinus Torvalds txs |= CLK_LINE_TX; /* TXC input */ 1751da177e4SLinus Torvalds } 1761da177e4SLinus Torvalds 1771da177e4SLinus Torvalds port->rxs = rxs; 1781da177e4SLinus Torvalds port->txs = txs; 1791da177e4SLinus Torvalds sca_out(rxs, MSCI1_OFFSET + RXS, port); 1801da177e4SLinus Torvalds sca_out(txs, MSCI1_OFFSET + TXS, port); 1811da177e4SLinus Torvalds sca_set_port(port); 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds static int c101_open(struct net_device *dev) 1861da177e4SLinus Torvalds { 1871da177e4SLinus Torvalds port_t *port = dev_to_port(dev); 1881da177e4SLinus Torvalds int result; 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds result = hdlc_open(dev); 1911da177e4SLinus Torvalds if (result) 1921da177e4SLinus Torvalds return result; 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds writeb(1, port->win0base + C101_DTR); 1951da177e4SLinus Torvalds sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */ 1961da177e4SLinus Torvalds sca_open(dev); 1971da177e4SLinus Torvalds /* DCD is connected to port 2 !@#$%^& - disable MSCI0 CDCD interrupt */ 1981da177e4SLinus Torvalds sca_out(IE1_UDRN, MSCI0_OFFSET + IE1, port); 1991da177e4SLinus Torvalds sca_out(IE0_TXINT, MSCI0_OFFSET + IE0, port); 2001da177e4SLinus Torvalds 201c2ce9204SKrzysztof Halasa set_carrier(port); 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds /* enable MSCI1 CDCD interrupt */ 2041da177e4SLinus Torvalds sca_out(IE1_CDCD, MSCI1_OFFSET + IE1, port); 2051da177e4SLinus Torvalds sca_out(IE0_RXINTA, MSCI1_OFFSET + IE0, port); 2061da177e4SLinus Torvalds sca_out(0x48, IER0, port); /* TXINT #0 and RXINT #1 */ 2071da177e4SLinus Torvalds c101_set_iface(port); 2081da177e4SLinus Torvalds return 0; 2091da177e4SLinus Torvalds } 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds static int c101_close(struct net_device *dev) 2131da177e4SLinus Torvalds { 2141da177e4SLinus Torvalds port_t *port = dev_to_port(dev); 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds sca_close(dev); 2171da177e4SLinus Torvalds writeb(0, port->win0base + C101_DTR); 2181da177e4SLinus Torvalds sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port); 2191da177e4SLinus Torvalds hdlc_close(dev); 2201da177e4SLinus Torvalds return 0; 2211da177e4SLinus Torvalds } 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds static int c101_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 2251da177e4SLinus Torvalds { 2261da177e4SLinus Torvalds const size_t size = sizeof(sync_serial_settings); 2271da177e4SLinus Torvalds sync_serial_settings new_line; 2281da177e4SLinus Torvalds sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; 2291da177e4SLinus Torvalds port_t *port = dev_to_port(dev); 2301da177e4SLinus Torvalds 2311da177e4SLinus Torvalds #ifdef DEBUG_RINGS 2321da177e4SLinus Torvalds if (cmd == SIOCDEVPRIVATE) { 2331da177e4SLinus Torvalds sca_dump_rings(dev); 2341da177e4SLinus Torvalds printk(KERN_DEBUG "MSCI1: ST: %02x %02x %02x %02x\n", 2351da177e4SLinus Torvalds sca_in(MSCI1_OFFSET + ST0, port), 2361da177e4SLinus Torvalds sca_in(MSCI1_OFFSET + ST1, port), 2371da177e4SLinus Torvalds sca_in(MSCI1_OFFSET + ST2, port), 2381da177e4SLinus Torvalds sca_in(MSCI1_OFFSET + ST3, port)); 2391da177e4SLinus Torvalds return 0; 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds #endif 2421da177e4SLinus Torvalds if (cmd != SIOCWANDEV) 2431da177e4SLinus Torvalds return hdlc_ioctl(dev, ifr, cmd); 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds switch(ifr->ifr_settings.type) { 2461da177e4SLinus Torvalds case IF_GET_IFACE: 2471da177e4SLinus Torvalds ifr->ifr_settings.type = IF_IFACE_SYNC_SERIAL; 2481da177e4SLinus Torvalds if (ifr->ifr_settings.size < size) { 2491da177e4SLinus Torvalds ifr->ifr_settings.size = size; /* data size wanted */ 2501da177e4SLinus Torvalds return -ENOBUFS; 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds if (copy_to_user(line, &port->settings, size)) 2531da177e4SLinus Torvalds return -EFAULT; 2541da177e4SLinus Torvalds return 0; 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds case IF_IFACE_SYNC_SERIAL: 2571da177e4SLinus Torvalds if(!capable(CAP_NET_ADMIN)) 2581da177e4SLinus Torvalds return -EPERM; 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds if (copy_from_user(&new_line, line, size)) 2611da177e4SLinus Torvalds return -EFAULT; 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds if (new_line.clock_type != CLOCK_EXT && 2641da177e4SLinus Torvalds new_line.clock_type != CLOCK_TXFROMRX && 2651da177e4SLinus Torvalds new_line.clock_type != CLOCK_INT && 2661da177e4SLinus Torvalds new_line.clock_type != CLOCK_TXINT) 2671da177e4SLinus Torvalds return -EINVAL; /* No such clock setting */ 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds if (new_line.loopback != 0 && new_line.loopback != 1) 2701da177e4SLinus Torvalds return -EINVAL; 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds memcpy(&port->settings, &new_line, size); /* Update settings */ 2731da177e4SLinus Torvalds c101_set_iface(port); 2741da177e4SLinus Torvalds return 0; 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds default: 2771da177e4SLinus Torvalds return hdlc_ioctl(dev, ifr, cmd); 2781da177e4SLinus Torvalds } 2791da177e4SLinus Torvalds } 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds static void c101_destroy_card(card_t *card) 2841da177e4SLinus Torvalds { 2851da177e4SLinus Torvalds readb(card->win0base + C101_PAGE); /* Resets SCA? */ 2861da177e4SLinus Torvalds 2871da177e4SLinus Torvalds if (card->irq) 2881da177e4SLinus Torvalds free_irq(card->irq, card); 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds if (card->win0base) { 2911da177e4SLinus Torvalds iounmap(card->win0base); 2921da177e4SLinus Torvalds release_mem_region(card->phy_winbase, C101_MAPPED_RAM_SIZE); 2931da177e4SLinus Torvalds } 2941da177e4SLinus Torvalds 2951da177e4SLinus Torvalds free_netdev(card->dev); 2961da177e4SLinus Torvalds 2971da177e4SLinus Torvalds kfree(card); 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds 300991990a1SKrzysztof Hałasa static const struct net_device_ops c101_ops = { 301991990a1SKrzysztof Hałasa .ndo_open = c101_open, 302991990a1SKrzysztof Hałasa .ndo_stop = c101_close, 303991990a1SKrzysztof Hałasa .ndo_change_mtu = hdlc_change_mtu, 304991990a1SKrzysztof Hałasa .ndo_start_xmit = hdlc_start_xmit, 305991990a1SKrzysztof Hałasa .ndo_do_ioctl = c101_ioctl, 306991990a1SKrzysztof Hałasa }; 3071da177e4SLinus Torvalds 3081da177e4SLinus Torvalds static int __init c101_run(unsigned long irq, unsigned long winbase) 3091da177e4SLinus Torvalds { 3101da177e4SLinus Torvalds struct net_device *dev; 3111da177e4SLinus Torvalds hdlc_device *hdlc; 3121da177e4SLinus Torvalds card_t *card; 3131da177e4SLinus Torvalds int result; 3141da177e4SLinus Torvalds 3151da177e4SLinus Torvalds if (irq<3 || irq>15 || irq == 6) /* FIXME */ { 3161da177e4SLinus Torvalds printk(KERN_ERR "c101: invalid IRQ value\n"); 3171da177e4SLinus Torvalds return -ENODEV; 3181da177e4SLinus Torvalds } 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds if (winbase < 0xC0000 || winbase > 0xDFFFF || (winbase & 0x3FFF) !=0) { 3211da177e4SLinus Torvalds printk(KERN_ERR "c101: invalid RAM value\n"); 3221da177e4SLinus Torvalds return -ENODEV; 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds 325dd00cc48SYoann Padioleau card = kzalloc(sizeof(card_t), GFP_KERNEL); 3261da177e4SLinus Torvalds if (card == NULL) { 3271da177e4SLinus Torvalds printk(KERN_ERR "c101: unable to allocate memory\n"); 3281da177e4SLinus Torvalds return -ENOBUFS; 3291da177e4SLinus Torvalds } 3301da177e4SLinus Torvalds 3311da177e4SLinus Torvalds card->dev = alloc_hdlcdev(card); 3321da177e4SLinus Torvalds if (!card->dev) { 3331da177e4SLinus Torvalds printk(KERN_ERR "c101: unable to allocate memory\n"); 3341da177e4SLinus Torvalds kfree(card); 3351da177e4SLinus Torvalds return -ENOBUFS; 3361da177e4SLinus Torvalds } 3371da177e4SLinus Torvalds 3381da177e4SLinus Torvalds if (request_irq(irq, sca_intr, 0, devname, card)) { 3391da177e4SLinus Torvalds printk(KERN_ERR "c101: could not allocate IRQ\n"); 3401da177e4SLinus Torvalds c101_destroy_card(card); 3414446065aSKrzysztof Halasa return -EBUSY; 3421da177e4SLinus Torvalds } 3431da177e4SLinus Torvalds card->irq = irq; 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds if (!request_mem_region(winbase, C101_MAPPED_RAM_SIZE, devname)) { 3461da177e4SLinus Torvalds printk(KERN_ERR "c101: could not request RAM window\n"); 3471da177e4SLinus Torvalds c101_destroy_card(card); 3484446065aSKrzysztof Halasa return -EBUSY; 3491da177e4SLinus Torvalds } 3501da177e4SLinus Torvalds card->phy_winbase = winbase; 3511da177e4SLinus Torvalds card->win0base = ioremap(winbase, C101_MAPPED_RAM_SIZE); 3521da177e4SLinus Torvalds if (!card->win0base) { 3531da177e4SLinus Torvalds printk(KERN_ERR "c101: could not map I/O address\n"); 3541da177e4SLinus Torvalds c101_destroy_card(card); 3554446065aSKrzysztof Halasa return -EFAULT; 3561da177e4SLinus Torvalds } 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds card->tx_ring_buffers = TX_RING_BUFFERS; 3591da177e4SLinus Torvalds card->rx_ring_buffers = RX_RING_BUFFERS; 3601da177e4SLinus Torvalds card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */ 3611da177e4SLinus Torvalds 3621da177e4SLinus Torvalds readb(card->win0base + C101_PAGE); /* Resets SCA? */ 3631da177e4SLinus Torvalds udelay(100); 3641da177e4SLinus Torvalds writeb(0, card->win0base + C101_PAGE); 3651da177e4SLinus Torvalds writeb(0, card->win0base + C101_DTR); /* Power-up for RAM? */ 3661da177e4SLinus Torvalds 3671da177e4SLinus Torvalds sca_init(card, 0); 3681da177e4SLinus Torvalds 3691da177e4SLinus Torvalds dev = port_to_dev(card); 3701da177e4SLinus Torvalds hdlc = dev_to_hdlc(dev); 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds spin_lock_init(&card->lock); 3731da177e4SLinus Torvalds dev->irq = irq; 3741da177e4SLinus Torvalds dev->mem_start = winbase; 3751da177e4SLinus Torvalds dev->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1; 3761da177e4SLinus Torvalds dev->tx_queue_len = 50; 377991990a1SKrzysztof Hałasa dev->netdev_ops = &c101_ops; 3781da177e4SLinus Torvalds hdlc->attach = sca_attach; 3791da177e4SLinus Torvalds hdlc->xmit = sca_xmit; 3801da177e4SLinus Torvalds card->settings.clock_type = CLOCK_EXT; 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds result = register_hdlc_device(dev); 3831da177e4SLinus Torvalds if (result) { 3841da177e4SLinus Torvalds printk(KERN_WARNING "c101: unable to register hdlc device\n"); 3851da177e4SLinus Torvalds c101_destroy_card(card); 3861da177e4SLinus Torvalds return result; 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds 38988597364SKrzysztof Hałasa sca_init_port(card); /* Set up C101 memory */ 390c2ce9204SKrzysztof Halasa set_carrier(card); 3911da177e4SLinus Torvalds 3921da177e4SLinus Torvalds printk(KERN_INFO "%s: Moxa C101 on IRQ%u," 3931da177e4SLinus Torvalds " using %u TX + %u RX packets rings\n", 3941da177e4SLinus Torvalds dev->name, card->irq, 3951da177e4SLinus Torvalds card->tx_ring_buffers, card->rx_ring_buffers); 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds *new_card = card; 3981da177e4SLinus Torvalds new_card = &card->next_card; 3991da177e4SLinus Torvalds return 0; 4001da177e4SLinus Torvalds } 4011da177e4SLinus Torvalds 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds 4041da177e4SLinus Torvalds static int __init c101_init(void) 4051da177e4SLinus Torvalds { 4061da177e4SLinus Torvalds if (hw == NULL) { 4071da177e4SLinus Torvalds #ifdef MODULE 4081da177e4SLinus Torvalds printk(KERN_INFO "c101: no card initialized\n"); 4091da177e4SLinus Torvalds #endif 410d753d824SKrzysztof Halasa return -EINVAL; /* no parameters specified, abort */ 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds printk(KERN_INFO "%s\n", version); 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds do { 4161da177e4SLinus Torvalds unsigned long irq, ram; 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds irq = simple_strtoul(hw, &hw, 0); 4191da177e4SLinus Torvalds 4201da177e4SLinus Torvalds if (*hw++ != ',') 4211da177e4SLinus Torvalds break; 4221da177e4SLinus Torvalds ram = simple_strtoul(hw, &hw, 0); 4231da177e4SLinus Torvalds 4241da177e4SLinus Torvalds if (*hw == ':' || *hw == '\x0') 4251da177e4SLinus Torvalds c101_run(irq, ram); 4261da177e4SLinus Torvalds 4271da177e4SLinus Torvalds if (*hw == '\x0') 428d753d824SKrzysztof Halasa return first_card ? 0 : -EINVAL; 4291da177e4SLinus Torvalds }while(*hw++ == ':'); 4301da177e4SLinus Torvalds 4311da177e4SLinus Torvalds printk(KERN_ERR "c101: invalid hardware parameters\n"); 432d753d824SKrzysztof Halasa return first_card ? 0 : -EINVAL; 4331da177e4SLinus Torvalds } 4341da177e4SLinus Torvalds 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds static void __exit c101_cleanup(void) 4371da177e4SLinus Torvalds { 4381da177e4SLinus Torvalds card_t *card = first_card; 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds while (card) { 4411da177e4SLinus Torvalds card_t *ptr = card; 4421da177e4SLinus Torvalds card = card->next_card; 4431da177e4SLinus Torvalds unregister_hdlc_device(port_to_dev(ptr)); 4441da177e4SLinus Torvalds c101_destroy_card(ptr); 4451da177e4SLinus Torvalds } 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds module_init(c101_init); 4501da177e4SLinus Torvalds module_exit(c101_cleanup); 4511da177e4SLinus Torvalds 4521da177e4SLinus Torvalds MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); 4531da177e4SLinus Torvalds MODULE_DESCRIPTION("Moxa C101 serial port driver"); 4541da177e4SLinus Torvalds MODULE_LICENSE("GPL v2"); 45541b1d174SKrzysztof Halasa module_param(hw, charp, 0444); 45641b1d174SKrzysztof Halasa MODULE_PARM_DESC(hw, "irq,ram:irq,..."); 457