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