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