2005-04-17 02:20:36 +04:00
/*
* Comtrol SV11 card driver
*
* This is a slightly odd Z85230 synchronous driver . All you need to
* know basically is
*
* Its a genuine Z85230
*
* It supports DMA using two DMA channels in SYNC mode . The driver doesn ' t
* use these facilities
*
* The control port is at io + 1 , the data at io + 3 and turning off the DMA
* is done by writing 0 to io + 4
*
* The hardware does the bus handling to avoid the need for delays between
* touching control registers .
*
* Port B isnt wired ( why - beats me )
2008-07-02 19:47:52 +04:00
*
* Generic HDLC port Copyright ( C ) 2008 Krzysztof Halasa < khc @ pm . waw . pl >
2005-04-17 02:20:36 +04:00
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/net.h>
# include <linux/skbuff.h>
# include <linux/netdevice.h>
# include <linux/if_arp.h>
# include <linux/delay.h>
2008-07-02 19:47:52 +04:00
# include <linux/hdlc.h>
2005-04-17 02:20:36 +04:00
# include <linux/ioport.h>
# include <net/arp.h>
2005-12-06 13:53:04 +03:00
# include <asm/irq.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
# include <asm/dma.h>
# include <asm/byteorder.h>
# include "z85230.h"
static int dma ;
/*
* Network driver support routines
*/
2008-07-02 19:47:52 +04:00
static inline struct z8530_dev * dev_to_sv ( struct net_device * dev )
{
return ( struct z8530_dev * ) dev_to_hdlc ( dev ) - > priv ;
}
2005-04-17 02:20:36 +04:00
/*
2008-07-02 19:47:52 +04:00
* Frame receive . Simple for our card as we do HDLC and there
2005-04-17 02:20:36 +04:00
* is no funny garbage involved
*/
2008-07-02 19:47:52 +04:00
2005-04-17 02:20:36 +04:00
static void hostess_input ( struct z8530_channel * c , struct sk_buff * skb )
{
/* Drop the CRC - it's not a good idea to try and negotiate it ;) */
2008-07-02 19:47:52 +04:00
skb_trim ( skb , skb - > len - 2 ) ;
skb - > protocol = hdlc_type_trans ( skb , c - > netdevice ) ;
2007-03-20 01:33:04 +03:00
skb_reset_mac_header ( skb ) ;
2008-07-02 19:47:52 +04:00
skb - > dev = c - > netdevice ;
2005-04-17 02:20:36 +04:00
/*
* Send it to the PPP layer . We don ' t have time to process
* it right now .
*/
netif_rx ( skb ) ;
}
2008-07-02 19:47:52 +04:00
2005-04-17 02:20:36 +04:00
/*
* We ' ve been placed in the UP state
2008-07-02 19:47:52 +04:00
*/
2005-04-17 02:20:36 +04:00
static int hostess_open ( struct net_device * d )
{
2008-07-02 19:47:52 +04:00
struct z8530_dev * sv11 = dev_to_sv ( d ) ;
2005-04-17 02:20:36 +04:00
int err = - 1 ;
2008-07-02 19:47:52 +04:00
2005-04-17 02:20:36 +04:00
/*
* Link layer up
*/
2008-07-02 19:47:52 +04:00
switch ( dma ) {
2005-04-17 02:20:36 +04:00
case 0 :
2008-07-02 19:47:52 +04:00
err = z8530_sync_open ( d , & sv11 - > chanA ) ;
2005-04-17 02:20:36 +04:00
break ;
case 1 :
2008-07-02 19:47:52 +04:00
err = z8530_sync_dma_open ( d , & sv11 - > chanA ) ;
2005-04-17 02:20:36 +04:00
break ;
case 2 :
2008-07-02 19:47:52 +04:00
err = z8530_sync_txdma_open ( d , & sv11 - > chanA ) ;
2005-04-17 02:20:36 +04:00
break ;
}
2008-07-02 19:47:52 +04:00
if ( err )
2005-04-17 02:20:36 +04:00
return err ;
2008-07-02 19:47:52 +04:00
err = hdlc_open ( d ) ;
if ( err ) {
switch ( dma ) {
2005-04-17 02:20:36 +04:00
case 0 :
2008-07-02 19:47:52 +04:00
z8530_sync_close ( d , & sv11 - > chanA ) ;
2005-04-17 02:20:36 +04:00
break ;
case 1 :
2008-07-02 19:47:52 +04:00
z8530_sync_dma_close ( d , & sv11 - > chanA ) ;
2005-04-17 02:20:36 +04:00
break ;
case 2 :
2008-07-02 19:47:52 +04:00
z8530_sync_txdma_close ( d , & sv11 - > chanA ) ;
2005-04-17 02:20:36 +04:00
break ;
2008-07-02 19:47:52 +04:00
}
2005-04-17 02:20:36 +04:00
return err ;
}
2008-07-02 19:47:52 +04:00
sv11 - > chanA . rx_function = hostess_input ;
2005-04-17 02:20:36 +04:00
/*
* Go go go
*/
netif_start_queue ( d ) ;
return 0 ;
}
static int hostess_close ( struct net_device * d )
{
2008-07-02 19:47:52 +04:00
struct z8530_dev * sv11 = dev_to_sv ( d ) ;
2005-04-17 02:20:36 +04:00
/*
* Discard new frames
*/
2008-07-02 19:47:52 +04:00
sv11 - > chanA . rx_function = z8530_null_rx ;
hdlc_close ( d ) ;
2005-04-17 02:20:36 +04:00
netif_stop_queue ( d ) ;
2008-07-02 19:47:52 +04:00
switch ( dma ) {
2005-04-17 02:20:36 +04:00
case 0 :
2008-07-02 19:47:52 +04:00
z8530_sync_close ( d , & sv11 - > chanA ) ;
2005-04-17 02:20:36 +04:00
break ;
case 1 :
2008-07-02 19:47:52 +04:00
z8530_sync_dma_close ( d , & sv11 - > chanA ) ;
2005-04-17 02:20:36 +04:00
break ;
case 2 :
2008-07-02 19:47:52 +04:00
z8530_sync_txdma_close ( d , & sv11 - > chanA ) ;
2005-04-17 02:20:36 +04:00
break ;
}
return 0 ;
}
static int hostess_ioctl ( struct net_device * d , struct ifreq * ifr , int cmd )
{
2008-07-02 19:47:52 +04:00
/* struct z8530_dev *sv11=dev_to_sv(d);
z8530_ioctl ( d , & sv11 - > chanA , ifr , cmd ) */
return hdlc_ioctl ( d , ifr , cmd ) ;
2005-04-17 02:20:36 +04:00
}
/*
2008-07-02 19:47:52 +04:00
* Passed network frames , fire them downwind .
2005-04-17 02:20:36 +04:00
*/
2008-07-02 19:47:52 +04:00
2009-08-31 23:50:47 +04:00
static netdev_tx_t hostess_queue_xmit ( struct sk_buff * skb ,
struct net_device * d )
2005-04-17 02:20:36 +04:00
{
2008-07-02 19:47:52 +04:00
return z8530_queue_xmit ( & dev_to_sv ( d ) - > chanA , skb ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 19:47:52 +04:00
static int hostess_attach ( struct net_device * dev , unsigned short encoding ,
unsigned short parity )
2005-04-17 02:20:36 +04:00
{
2008-07-02 19:47:52 +04:00
if ( encoding = = ENCODING_NRZ & & parity = = PARITY_CRC16_PR1_CCITT )
return 0 ;
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
/*
* Description block for a Comtrol Hostess SV11 card
*/
2008-07-02 19:47:52 +04:00
2009-01-09 00:52:11 +03:00
static const struct net_device_ops hostess_ops = {
. ndo_open = hostess_open ,
. ndo_stop = hostess_close ,
. ndo_change_mtu = hdlc_change_mtu ,
. ndo_start_xmit = hdlc_start_xmit ,
. ndo_do_ioctl = hostess_ioctl ,
} ;
2008-07-02 19:47:52 +04:00
static struct z8530_dev * sv11_init ( int iobase , int irq )
2005-04-17 02:20:36 +04:00
{
2008-07-02 19:47:52 +04:00
struct z8530_dev * sv ;
struct net_device * netdev ;
2005-04-17 02:20:36 +04:00
/*
* Get the needed I / O space
*/
2008-07-02 19:47:52 +04:00
if ( ! request_region ( iobase , 8 , " Comtrol SV11 " ) ) {
printk ( KERN_WARNING " hostess: I/O 0x%X already in use. \n " ,
iobase ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
2008-07-02 19:47:52 +04:00
sv = kzalloc ( sizeof ( struct z8530_dev ) , GFP_KERNEL ) ;
if ( ! sv )
goto err_kzalloc ;
2005-04-17 02:20:36 +04:00
/*
* Stuff in the I / O addressing
*/
2008-07-02 19:47:52 +04:00
sv - > active = 0 ;
sv - > chanA . ctrlio = iobase + 1 ;
sv - > chanA . dataio = iobase + 3 ;
sv - > chanB . ctrlio = - 1 ;
sv - > chanB . dataio = - 1 ;
sv - > chanA . irqs = & z8530_nop ;
sv - > chanB . irqs = & z8530_nop ;
outb ( 0 , iobase + 4 ) ; /* DMA off */
2005-04-17 02:20:36 +04:00
/* We want a fast IRQ for this device. Actually we'd like an even faster
IRQ ; ) - This is one driver RtLinux is made for */
2008-07-02 19:47:52 +04:00
2009-11-19 10:29:17 +03:00
if ( request_irq ( irq , z8530_interrupt , IRQF_DISABLED ,
2008-07-02 19:47:52 +04:00
" Hostess SV11 " , sv ) < 0 ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_WARNING " hostess: IRQ %d already in use. \n " , irq ) ;
2008-07-02 19:47:52 +04:00
goto err_irq ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 19:47:52 +04:00
sv - > irq = irq ;
sv - > chanA . private = sv ;
sv - > chanA . dev = sv ;
sv - > chanB . dev = sv ;
if ( dma ) {
2005-04-17 02:20:36 +04:00
/*
* You can have DMA off or 1 and 3 thats the lot
* on the Comtrol .
*/
2008-07-02 19:47:52 +04:00
sv - > chanA . txdma = 3 ;
sv - > chanA . rxdma = 1 ;
outb ( 0x03 | 0x08 , iobase + 4 ) ; /* DMA on */
if ( request_dma ( sv - > chanA . txdma , " Hostess SV/11 (TX) " ) )
goto err_txdma ;
if ( dma = = 1 )
if ( request_dma ( sv - > chanA . rxdma , " Hostess SV/11 (RX) " ) )
goto err_rxdma ;
2005-04-17 02:20:36 +04:00
}
/* Kill our private IRQ line the hostess can end up chattering
until the configuration is set */
disable_irq ( irq ) ;
2008-07-02 19:47:52 +04:00
2005-04-17 02:20:36 +04:00
/*
* Begin normal initialise
*/
2008-07-02 19:47:52 +04:00
if ( z8530_init ( sv ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " Z8530 series device not found. \n " ) ;
enable_irq ( irq ) ;
2008-07-02 19:47:52 +04:00
goto free_dma ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 19:47:52 +04:00
z8530_channel_load ( & sv - > chanB , z8530_dead_port ) ;
if ( sv - > type = = Z85C30 )
z8530_channel_load ( & sv - > chanA , z8530_hdlc_kilostream ) ;
2005-04-17 02:20:36 +04:00
else
2008-07-02 19:47:52 +04:00
z8530_channel_load ( & sv - > chanA , z8530_hdlc_kilostream_85230 ) ;
2005-04-17 02:20:36 +04:00
enable_irq ( irq ) ;
/*
* Now we can take the IRQ
*/
2008-07-02 19:47:52 +04:00
sv - > chanA . netdevice = netdev = alloc_hdlcdev ( sv ) ;
if ( ! netdev )
goto free_dma ;
2005-04-17 02:20:36 +04:00
2008-07-02 19:47:52 +04:00
dev_to_hdlc ( netdev ) - > attach = hostess_attach ;
dev_to_hdlc ( netdev ) - > xmit = hostess_queue_xmit ;
2009-01-09 00:52:11 +03:00
netdev - > netdev_ops = & hostess_ops ;
2008-07-02 19:47:52 +04:00
netdev - > base_addr = iobase ;
netdev - > irq = irq ;
if ( register_hdlc_device ( netdev ) ) {
printk ( KERN_ERR " hostess: unable to register HDLC device. \n " ) ;
free_netdev ( netdev ) ;
goto free_dma ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 19:47:52 +04:00
z8530_describe ( sv , " I/O " , iobase ) ;
sv - > active = 1 ;
return sv ;
free_dma :
if ( dma = = 1 )
free_dma ( sv - > chanA . rxdma ) ;
err_rxdma :
if ( dma )
free_dma ( sv - > chanA . txdma ) ;
err_txdma :
free_irq ( irq , sv ) ;
err_irq :
2005-04-17 02:20:36 +04:00
kfree ( sv ) ;
2008-07-02 19:47:52 +04:00
err_kzalloc :
release_region ( iobase , 8 ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
2008-07-02 19:47:52 +04:00
static void sv11_shutdown ( struct z8530_dev * dev )
2005-04-17 02:20:36 +04:00
{
2008-07-02 19:47:52 +04:00
unregister_hdlc_device ( dev - > chanA . netdevice ) ;
z8530_shutdown ( dev ) ;
free_irq ( dev - > irq , dev ) ;
if ( dma ) {
if ( dma = = 1 )
free_dma ( dev - > chanA . rxdma ) ;
free_dma ( dev - > chanA . txdma ) ;
2005-04-17 02:20:36 +04:00
}
2008-07-02 19:47:52 +04:00
release_region ( dev - > chanA . ctrlio - 1 , 8 ) ;
free_netdev ( dev - > chanA . netdevice ) ;
2005-04-17 02:20:36 +04:00
kfree ( dev ) ;
}
2008-07-02 19:47:52 +04:00
static int io = 0x200 ;
static int irq = 9 ;
2005-04-17 02:20:36 +04:00
module_param ( io , int , 0 ) ;
MODULE_PARM_DESC ( io , " The I/O base of the Comtrol Hostess SV11 card " ) ;
module_param ( dma , int , 0 ) ;
MODULE_PARM_DESC ( dma , " Set this to 1 to use DMA1/DMA3 for TX/RX " ) ;
module_param ( irq , int , 0 ) ;
MODULE_PARM_DESC ( irq , " The interrupt line setting for the Comtrol Hostess SV11 card " ) ;
MODULE_AUTHOR ( " Alan Cox " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Modular driver for the Comtrol Hostess SV11 " ) ;
2008-07-02 19:47:52 +04:00
static struct z8530_dev * sv11_unit ;
2005-04-17 02:20:36 +04:00
int init_module ( void )
{
2008-07-02 19:47:52 +04:00
if ( ( sv11_unit = sv11_init ( io , irq ) ) = = NULL )
2005-04-17 02:20:36 +04:00
return - ENODEV ;
return 0 ;
}
void cleanup_module ( void )
{
2008-07-02 19:47:52 +04:00
if ( sv11_unit )
2005-04-17 02:20:36 +04:00
sv11_shutdown ( sv11_unit ) ;
}