11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sealevel Systems 4021 driver. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * modify it under the terms of the GNU General Public License 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as published by the Free Software Foundation; either version 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2 of the License, or (at your option) any later version. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (c) Copyright 1999, 2001 Alan Cox 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (c) Copyright 2001 Red Hat Inc. 1152e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa * Generic HDLC port Copyright (C) 2008 Krzysztof Halasa <khc@pm.waw.pl> 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1523efcb738ea51befe0674e0685fc6cfe353aa553Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 1623efcb738ea51befe0674e0685fc6cfe353aa553Joe Perches 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/mm.h> 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/net.h> 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/if_arp.h> 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 2552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa#include <linux/hdlc.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 285a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <net/arp.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3182729971e0f8ccf1f15567cc4f2c5389e0659eb2Al Viro#include <asm/irq.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/io.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/dma.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/byteorder.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "z85230.h" 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct slvl_device 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct z8530_channel *chan; 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int channel; 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct slvl_board 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa struct slvl_device dev[2]; 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct z8530_dev board; 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int iobase; 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Network driver support routines 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5652e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasastatic inline struct slvl_device* dev_to_chan(struct net_device *dev) 5752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa{ 5852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa return (struct slvl_device *)dev_to_hdlc(dev)->priv; 5952e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa} 6052e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6252e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa * Frame receive. Simple for our card as we do HDLC and there 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is no funny garbage involved 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Drop the CRC - it's not a good idea to try and negotiate it ;) */ 6952e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa skb_trim(skb, skb->len - 2); 7052e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa skb->protocol = hdlc_type_trans(skb, c->netdevice); 7198e399f82ab3a6d863d1d4a7ea48925cc91c830eArnaldo Carvalho de Melo skb_reset_mac_header(skb); 7252e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa skb->dev = c->netdevice; 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_rx(skb); 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We've been placed in the UP state 7852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa */ 7952e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sealevel_open(struct net_device *d) 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 8252e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa struct slvl_device *slvl = dev_to_chan(d); 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err = -1; 841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int unit = slvl->channel; 8552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa * Link layer up. 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 90614c12a1581687501f1b0fc721feff69b47abd92Rudy Matela switch (unit) { 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 9252e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa err = z8530_sync_dma_open(d, slvl->chan); 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 9552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa err = z8530_sync_open(d, slvl->chan); 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 9952e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (err) 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 10152e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 10252e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa err = hdlc_open(d); 10352e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (err) { 10452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa switch (unit) { 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z8530_sync_dma_close(d, slvl->chan); 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z8530_sync_close(d, slvl->chan); 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 11152e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa } 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 11552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa slvl->chan->rx_function = sealevel_input; 11652e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Go go go 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_start_queue(d); 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sealevel_close(struct net_device *d) 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12652e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa struct slvl_device *slvl = dev_to_chan(d); 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int unit = slvl->channel; 12852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Discard new frames 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13352e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa slvl->chan->rx_function = z8530_null_rx; 13452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 13552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa hdlc_close(d); 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds netif_stop_queue(d); 13752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 138614c12a1581687501f1b0fc721feff69b47abd92Rudy Matela switch (unit) { 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z8530_sync_dma_close(d, slvl->chan); 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z8530_sync_close(d, slvl->chan); 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sealevel_ioctl(struct net_device *d, struct ifreq *ifr, int cmd) 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15152e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa /* struct slvl_device *slvl=dev_to_chan(d); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z8530_ioctl(d,&slvl->sync.chanA,ifr,cmd) */ 15352e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa return hdlc_ioctl(d, ifr, cmd); 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 15752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa * Passed network frames, fire them downwind. 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15952e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 160d71a674922e7519edb477ecb585e7d29d69c7aa7Stephen Hemmingerstatic netdev_tx_t sealevel_queue_xmit(struct sk_buff *skb, 161d71a674922e7519edb477ecb585e7d29d69c7aa7Stephen Hemminger struct net_device *d) 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16352e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa return z8530_queue_xmit(dev_to_chan(d)->chan, skb); 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16652e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasastatic int sealevel_attach(struct net_device *dev, unsigned short encoding, 16752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa unsigned short parity) 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16952e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (encoding == ENCODING_NRZ && parity == PARITY_CRC16_PR1_CCITT) 17052e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa return 0; 17152e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa return -EINVAL; 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 174991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasastatic const struct net_device_ops sealevel_ops = { 175991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_open = sealevel_open, 176991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_stop = sealevel_close, 177991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_change_mtu = hdlc_change_mtu, 178991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_start_xmit = hdlc_start_xmit, 179991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa .ndo_do_ioctl = sealevel_ioctl, 180991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa}; 181991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa 18252e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasastatic int slvl_setup(struct slvl_device *sv, int iobase, int irq) 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 18452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa struct net_device *dev = alloc_hdlcdev(sv); 18552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (!dev) 18652e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa return -1; 18752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 18852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev_to_hdlc(dev)->attach = sealevel_attach; 18952e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev_to_hdlc(dev)->xmit = sealevel_queue_xmit; 190991990a12de42281f81b4e3a6471586d2d0caf6aKrzysztof Hałasa dev->netdev_ops = &sealevel_ops; 19152e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->base_addr = iobase; 19252e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->irq = irq; 19352e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 19452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (register_hdlc_device(dev)) { 19523efcb738ea51befe0674e0685fc6cfe353aa553Joe Perches pr_err("unable to register HDLC device\n"); 19652e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa free_netdev(dev); 19752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa return -1; 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20052e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa sv->chan->netdevice = dev; 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate and setup Sealevel board. 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 20952e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasastatic __init struct slvl_board *slvl_init(int iobase, int irq, 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int txdma, int rxdma, int slow) 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct z8530_dev *dev; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct slvl_board *b; 21452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get the needed I/O space 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21952e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (!request_region(iobase, 8, "Sealevel 4021")) { 22023efcb738ea51befe0674e0685fc6cfe353aa553Joe Perches pr_warn("I/O 0x%X already in use\n", iobase); 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa b = kzalloc(sizeof(struct slvl_board), GFP_KERNEL); 22552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (!b) 22652e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa goto err_kzalloc; 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa b->dev[0].chan = &b->board.chanA; 22952e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa b->dev[0].channel = 0; 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23152e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa b->dev[1].chan = &b->board.chanB; 23252e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa b->dev[1].channel = 1; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev = &b->board; 23552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Stuff in the I/O addressing 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23952e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->active = 0; 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds b->iobase = iobase; 24352e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Select 8530 delays for the old board 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 24852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (slow) 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds iobase |= Z8530_PORT_SLEEP; 25052e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 25152e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->chanA.ctrlio = iobase + 1; 25252e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->chanA.dataio = iobase; 25352e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->chanB.ctrlio = iobase + 3; 25452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->chanB.dataio = iobase + 2; 25552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 25652e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->chanA.irqs = &z8530_nop; 25752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->chanB.irqs = &z8530_nop; 25852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Assert DTR enable DMA 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26252e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 26352e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa outb(3 | (1 << 7), b->iobase + 4); 26452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* We want a fast IRQ for this device. Actually we'd like an even faster 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds IRQ ;) - This is one driver RtLinux is made for */ 26852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 2690ca45208b0400812965d810b1917839dc8844bbeMichael Opdenacker if (request_irq(irq, z8530_interrupt, 0, 27052e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa "SeaLevel", dev) < 0) { 27123efcb738ea51befe0674e0685fc6cfe353aa553Joe Perches pr_warn("IRQ %d already in use\n", irq); 27252e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa goto err_request_irq; 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 27552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->irq = irq; 27652e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->chanA.private = &b->dev[0]; 27752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->chanB.private = &b->dev[1]; 27852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->chanA.dev = dev; 27952e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->chanB.dev = dev; 28052e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 28152e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->chanA.txdma = 3; 28252e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->chanA.rxdma = 1; 28352e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (request_dma(dev->chanA.txdma, "SeaLevel (TX)")) 28452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa goto err_dma_tx; 28552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 28652e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (request_dma(dev->chanA.rxdma, "SeaLevel (RX)")) 28752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa goto err_dma_rx; 28852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds disable_irq(irq); 29052e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Begin normal initialise 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 29552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (z8530_init(dev) != 0) { 29623efcb738ea51befe0674e0685fc6cfe353aa553Joe Perches pr_err("Z8530 series device not found\n"); 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_irq(irq); 29852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa goto free_hw; 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30052e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (dev->type == Z85C30) { 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream); 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream); 30352e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa } else { 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z8530_channel_load(&dev->chanA, z8530_hdlc_kilostream_85230); 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z8530_channel_load(&dev->chanB, z8530_hdlc_kilostream_85230); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now we can take the IRQ 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 31152e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enable_irq(irq); 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (slvl_setup(&b->dev[0], iobase, irq)) 31552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa goto free_hw; 31652e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa if (slvl_setup(&b->dev[1], iobase, irq)) 31752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa goto free_netdev0; 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z8530_describe(dev, "I/O", iobase); 32052e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa dev->active = 1; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return b; 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32352e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasafree_netdev0: 32452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa unregister_hdlc_device(b->dev[0].chan->netdevice); 32552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa free_netdev(b->dev[0].chan->netdevice); 32652e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasafree_hw: 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_dma(dev->chanA.rxdma); 32852e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasaerr_dma_rx: 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_dma(dev->chanA.txdma); 33052e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasaerr_dma_tx: 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(irq, dev); 33252e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasaerr_request_irq: 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(b); 33452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasaerr_kzalloc: 33552e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa release_region(iobase, 8); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit slvl_shutdown(struct slvl_board *b) 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int u; 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds z8530_shutdown(&b->board); 34452e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 345614c12a1581687501f1b0fc721feff69b47abd92Rudy Matela for (u = 0; u < 2; u++) { 34652e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa struct net_device *d = b->dev[u].chan->netdevice; 34752e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa unregister_hdlc_device(d); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_netdev(d); 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35052e8a6a2d8dc19002d1757870d16051157ce999cKrzysztof Hałasa 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_irq(b->board.irq, &b->board); 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_dma(b->board.chanA.rxdma); 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds free_dma(b->board.chanA.txdma); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* DMA off on the card, drop DTR */ 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds outb(0, b->iobase); 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds release_region(b->iobase, 8); 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(b); 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int io=0x238; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int txdma=1; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int rxdma=3; 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int irq=5; 365eb93992207dadb946a3b5cf4544957dc924a6f58Rusty Russellstatic bool slow=false; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(io, int, 0); 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(io, "The I/O base of the Sealevel card"); 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(txdma, int, 0); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(txdma, "Transmit DMA channel"); 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(rxdma, int, 0); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(rxdma, "Receive DMA channel"); 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(irq, int, 0); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(irq, "The interrupt line setting for the SeaLevel card"); 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(slow, bool, 0); 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(slow, "Set this for an older Sealevel card such as the 4012"); 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Alan Cox"); 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Modular driver for the SeaLevel 4021"); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct slvl_board *slvl_unit; 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init slvl_init_module(void) 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slvl_unit = slvl_init(io, irq, txdma, rxdma, slow); 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return slvl_unit ? 0 : -ENODEV; 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit slvl_cleanup_module(void) 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 393614c12a1581687501f1b0fc721feff69b47abd92Rudy Matela if (slvl_unit) 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds slvl_shutdown(slvl_unit); 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(slvl_init_module); 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(slvl_cleanup_module); 399