1/* 2 * Moxa C101 synchronous serial card driver for Linux 3 * 4 * Copyright (C) 2000 Krzysztof Halasa <khc@pm.waw.pl> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * For information see http://hq.pm.waw.pl/hdlc/ 12 * 13 * Sources of information: 14 * Hitachi HD64570 SCA User's Manual 15 * Moxa C101 User's Manual 16 */ 17 18#include <linux/module.h> 19#include <linux/kernel.h> 20#include <linux/slab.h> 21#include <linux/types.h> 22#include <linux/string.h> 23#include <linux/errno.h> 24#include <linux/init.h> 25#include <linux/netdevice.h> 26#include <linux/hdlc.h> 27#include <linux/delay.h> 28#include <asm/io.h> 29 30#include "hd64570.h" 31 32#define DEBUG_RINGS 33/* #define DEBUG_PKT */ 34 35static const char* version = "Moxa C101 driver revision: 1.02 for Linux 2.4"; 36static const char* devname = "C101"; 37 38#define C101_PAGE 0x1D00 39#define C101_DTR 0x1E00 40#define C101_SCA 0x1F00 41#define C101_WINDOW_SIZE 0x2000 42#define C101_MAPPED_RAM_SIZE 0x4000 43 44#define RAM_SIZE (256 * 1024) 45#define CLOCK_BASE 9830400 /* 9.8304 MHz */ 46#define PAGE0_ALWAYS_MAPPED 47 48static char *hw; 49 50 51typedef struct card_s { 52 hdlc_device hdlc; /* HDLC device struct - must be first */ 53 spinlock_t lock; /* TX lock */ 54 int clkmode; /* clock mode */ 55 int clkrate; /* clock speed */ 56 int line; /* loopback only */ 57 u8 *win0base; /* ISA window base address */ 58 u32 phy_winbase; /* ISA physical base address */ 59 u16 buff_offset; /* offset of first buffer of first channel */ 60 u8 rxs, txs, tmc; /* SCA registers */ 61 u8 irq; /* IRQ (3-15) */ 62 u8 ring_buffers; /* number of buffers in a ring */ 63 u8 page; 64 65 u8 rxin; /* rx ring buffer 'in' pointer */ 66 u8 txin; /* tx ring buffer 'in' and 'last' pointers */ 67 u8 txlast; 68 u8 rxpart; /* partial frame received, next frame invalid*/ 69 70 struct card_s *next_card; 71}card_t; 72 73typedef card_t port_t; 74 75 76#define sca_in(reg, card) readb((card)->win0base + C101_SCA + (reg)) 77#define sca_out(value, reg, card) writeb(value, (card)->win0base + C101_SCA + (reg)) 78#define sca_inw(reg, card) readw((card)->win0base + C101_SCA + (reg)) 79#define sca_outw(value, reg, card) writew(value, (card)->win0base + C101_SCA + (reg)) 80 81#define port_to_card(port) (port) 82#define log_node(port) (0) 83#define phy_node(port) (0) 84#define winsize(card) (C101_WINDOW_SIZE) 85#define win0base(card) ((card)->win0base) 86#define winbase(card) ((card)->win0base + 0x2000) 87#define get_port(card, port) ((port) == 0 ? (card) : NULL) 88 89 90static inline u8 sca_get_page(card_t *card) 91{ 92 return card->page; 93} 94 95static inline void openwin(card_t *card, u8 page) 96{ 97 card->page = page; 98 writeb(page, card->win0base + C101_PAGE); 99} 100 101 102#define close_windows(card) {} /* no hardware support */ 103 104 105#include "hd6457x.c" 106 107 108static int c101_set_clock(port_t *port, int value) 109{ 110 u8 msci = get_msci(port); 111 u8 rxs = port->rxs & CLK_BRG_MASK; 112 u8 txs = port->txs & CLK_BRG_MASK; 113 114 switch(value) { 115 case CLOCK_EXT: 116 rxs |= CLK_LINE_RX; /* RXC input */ 117 txs |= CLK_LINE_TX; /* TXC input */ 118 break; 119 120 case CLOCK_INT: 121 rxs |= CLK_BRG_RX; /* TX clock */ 122 txs |= CLK_RXCLK_TX; /* BRG output */ 123 break; 124 125 case CLOCK_TXINT: 126 rxs |= CLK_LINE_RX; /* RXC input */ 127 txs |= CLK_BRG_TX; /* BRG output */ 128 break; 129 130 case CLOCK_TXFROMRX: 131 rxs |= CLK_LINE_RX; /* RXC input */ 132 txs |= CLK_RXCLK_TX; /* RX clock */ 133 break; 134 135 default: 136 return -EINVAL; 137 } 138 139 port->rxs = rxs; 140 port->txs = txs; 141 sca_out(rxs, msci + RXS, port); 142 sca_out(txs, msci + TXS, port); 143 port->clkmode = value; 144 return 0; 145} 146 147 148static int c101_open(hdlc_device *hdlc) 149{ 150 port_t *port = hdlc_to_port(hdlc); 151 152 MOD_INC_USE_COUNT; 153 writeb(1, port->win0base + C101_DTR); 154 sca_out(0, MSCI1_OFFSET + CTL, port); /* RTS uses ch#2 output */ 155 sca_open(hdlc); 156 c101_set_clock(port, port->clkmode); 157 return 0; 158} 159 160 161static void c101_close(hdlc_device *hdlc) 162{ 163 port_t *port = hdlc_to_port(hdlc); 164 165 sca_close(hdlc); 166 writeb(0, port->win0base + C101_DTR); 167 sca_out(CTL_NORTS, MSCI1_OFFSET + CTL, port); 168 MOD_DEC_USE_COUNT; 169} 170 171 172static int c101_ioctl(hdlc_device *hdlc, struct ifreq *ifr, int cmd) 173{ 174 int value = ifr->ifr_ifru.ifru_ivalue; 175 int result = 0; 176 port_t *port = hdlc_to_port(hdlc); 177 178 if(!capable(CAP_NET_ADMIN)) 179 return -EPERM; 180 181 switch(cmd) { 182 case HDLCSCLOCK: 183 result = c101_set_clock(port, value); 184 case HDLCGCLOCK: 185 value = port->clkmode; 186 break; 187 188 case HDLCSCLOCKRATE: 189 port->clkrate = value; 190 sca_set_clock(port); 191 case HDLCGCLOCKRATE: 192 value = port->clkrate; 193 break; 194 195 case HDLCSLINE: 196 result = sca_set_loopback(port, value); 197 case HDLCGLINE: 198 value = port->line; 199 break; 200 201#ifdef DEBUG_RINGS 202 case HDLCRUN: 203 sca_dump_rings(hdlc); 204 return 0; 205#endif /* DEBUG_RINGS */ 206 207 default: 208 return -EINVAL; 209 } 210 211 ifr->ifr_ifru.ifru_ivalue = value; 212 return result; 213} 214 215 216 217static void c101_destroy_card(card_t *card) 218{ 219 if (card->irq) 220 free_irq(card->irq, card); 221 222 if (card->win0base) { 223 iounmap(card->win0base); 224 release_mem_region(card->phy_winbase, C101_MAPPED_RAM_SIZE); 225 } 226 227 kfree(card); 228} 229 230 231 232static int c101_run(unsigned long irq, unsigned long winbase) 233{ 234 card_t *card; 235 int result; 236 237 if (irq<3 || irq>15 || irq == 6) { 238 printk(KERN_ERR "c101: invalid IRQ value\n"); 239 return -ENODEV; 240 } 241 242 if (winbase < 0xC0000 || winbase > 0xDFFFF || (winbase & 0x3FFF) !=0) { 243 printk(KERN_ERR "c101: invalid RAM value\n"); 244 return -ENODEV; 245 } 246 247 card = kmalloc(sizeof(card_t), GFP_KERNEL); 248 if (card == NULL) { 249 printk(KERN_ERR "c101: unable to allocate memory\n"); 250 return -ENOBUFS; 251 } 252 memset(card, 0, sizeof(card_t)); 253 254 if (request_irq(irq, sca_intr, 0, devname, card)) { 255 printk(KERN_ERR "c101: could not allocate IRQ\n"); 256 c101_destroy_card(card); 257 return(-EBUSY); 258 } 259 card->irq = irq; 260 261 if (!request_mem_region(winbase, C101_MAPPED_RAM_SIZE, devname)) { 262 printk(KERN_ERR "c101: could not request RAM window\n"); 263 c101_destroy_card(card); 264 return(-EBUSY); 265 } 266 card->phy_winbase = winbase; 267 card->win0base = ioremap(winbase, C101_MAPPED_RAM_SIZE); 268 if (!card->win0base) { 269 printk(KERN_ERR "c101: could not map I/O address\n"); 270 c101_destroy_card(card); 271 return -EBUSY; 272 } 273 274 /* 2 rings required for 1 port */ 275 card->ring_buffers = (RAM_SIZE -C101_WINDOW_SIZE) / (2 * HDLC_MAX_MRU); 276 printk(KERN_DEBUG "c101: using %u packets rings\n",card->ring_buffers); 277 278 card->buff_offset = C101_WINDOW_SIZE; /* Bytes 1D00-1FFF reserved */ 279 280 readb(card->win0base + C101_PAGE); /* Resets SCA? */ 281 udelay(100); 282 writeb(0, card->win0base + C101_PAGE); 283 writeb(0, card->win0base + C101_DTR); /* Power-up for RAM? */ 284 285 sca_init(card, 0); 286 287 spin_lock_init(&card->lock); 288 hdlc_to_dev(&card->hdlc)->irq = irq; 289 hdlc_to_dev(&card->hdlc)->mem_start = winbase; 290 hdlc_to_dev(&card->hdlc)->mem_end = winbase + C101_MAPPED_RAM_SIZE - 1; 291 hdlc_to_dev(&card->hdlc)->tx_queue_len = 50; 292 card->hdlc.ioctl = c101_ioctl; 293 card->hdlc.open = c101_open; 294 card->hdlc.close = c101_close; 295 card->hdlc.xmit = sca_xmit; 296 297 result = register_hdlc_device(&card->hdlc); 298 if (result) { 299 printk(KERN_WARNING "c101: unable to register hdlc device\n"); 300 c101_destroy_card(card); 301 return result; 302 } 303 304 sca_init_sync_port(card); /* Set up C101 memory */ 305 306 *new_card = card; 307 new_card = &card->next_card; 308 return 0; 309} 310 311 312 313static int __init c101_init(void) 314{ 315 if (hw == NULL) { 316#ifdef MODULE 317 printk(KERN_INFO "c101: no card initialized\n"); 318#endif 319 return -ENOSYS; /* no parameters specified, abort */ 320 } 321 322 printk(KERN_INFO "%s\n", version); 323 324 do { 325 unsigned long irq, ram; 326 327 irq = simple_strtoul(hw, &hw, 0); 328 329 if (*hw++ != ',') 330 break; 331 ram = simple_strtoul(hw, &hw, 0); 332 333 if (*hw == ':' || *hw == '\x0') 334 c101_run(irq, ram); 335 336 if (*hw == '\x0') 337 return 0; 338 }while(*hw++ == ':'); 339 340 printk(KERN_ERR "c101: invalid hardware parameters\n"); 341 return first_card ? 0 : -ENOSYS; 342} 343 344 345#ifndef MODULE 346static int __init c101_setup(char *str) 347{ 348 hw = str; 349 return 1; 350} 351 352__setup("c101=", c101_setup); 353#endif 354 355 356static void __exit c101_cleanup(void) 357{ 358 card_t *card = first_card; 359 360 while (card) { 361 card_t *ptr = card; 362 card = card->next_card; 363 unregister_hdlc_device(&ptr->hdlc); 364 c101_destroy_card(ptr); 365 } 366} 367 368 369module_init(c101_init); 370module_exit(c101_cleanup); 371 372MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>"); 373MODULE_DESCRIPTION("Moxa C101 serial port driver"); 374MODULE_LICENSE("GPL"); 375MODULE_PARM(hw, "s"); /* hw=irq,ram:irq,... */ 376EXPORT_NO_SYMBOLS; 377