2005-04-17 02:20:36 +04:00
/************************************************************************
* Copyright 2003 Digi International ( www . digi . com )
*
* Copyright ( C ) 2004 IBM Corporation . All rights reserved .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 , or ( at your option )
* any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY , EXPRESS OR IMPLIED ; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE . See the GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 * Temple Place - Suite 330 , Boston ,
* MA 02111 - 1307 , USA .
*
* Contact Information :
* Scott H Kilau < Scott_Kilau @ digi . com >
* Wendy Xiong < wendyx @ us . ltcfwd . linux . ibm . com >
*
2005-07-27 22:43:49 +04:00
*
2005-04-17 02:20:36 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/moduleparam.h>
# include <linux/pci.h>
# include "jsm.h"
MODULE_AUTHOR ( " Digi International, http://www.digi.com " ) ;
2005-04-17 02:25:44 +04:00
MODULE_DESCRIPTION ( " Driver for the Digi International "
" Neo PCI based product line " ) ;
MODULE_LICENSE ( " GPL " ) ;
2005-04-17 02:20:36 +04:00
MODULE_SUPPORTED_DEVICE ( " jsm " ) ;
# define JSM_DRIVER_NAME "jsm"
# define NR_PORTS 32
# define JSM_MINOR_START 0
struct uart_driver jsm_uart_driver = {
. owner = THIS_MODULE ,
. driver_name = JSM_DRIVER_NAME ,
. dev_name = " ttyn " ,
2005-07-27 22:43:48 +04:00
. major = 0 ,
2005-04-17 02:20:36 +04:00
. minor = JSM_MINOR_START ,
. nr = NR_PORTS ,
} ;
int jsm_debug ;
module_param ( jsm_debug , int , 0 ) ;
MODULE_PARM_DESC ( jsm_debug , " Driver debugging level " ) ;
2005-04-17 02:25:44 +04:00
static int jsm_probe_one ( struct pci_dev * pdev , const struct pci_device_id * ent )
2005-04-17 02:20:36 +04:00
{
int rc = 0 ;
2005-04-17 02:25:44 +04:00
struct jsm_board * brd ;
static int adapter_count = 0 ;
int retval ;
2005-04-17 02:20:36 +04:00
2005-04-17 02:25:44 +04:00
rc = pci_enable_device ( pdev ) ;
if ( rc ) {
dev_err ( & pdev - > dev , " Device enable FAILED \n " ) ;
goto out ;
2005-04-17 02:20:36 +04:00
}
2005-04-17 02:25:44 +04:00
rc = pci_request_regions ( pdev , " jsm " ) ;
if ( rc ) {
dev_err ( & pdev - > dev , " pci_request_region FAILED \n " ) ;
goto out_disable_device ;
}
2005-04-17 02:20:36 +04:00
brd = kmalloc ( sizeof ( struct jsm_board ) , GFP_KERNEL ) ;
if ( ! brd ) {
2005-04-17 02:25:44 +04:00
dev_err ( & pdev - > dev ,
" memory allocation for board structure failed \n " ) ;
rc = - ENOMEM ;
goto out_release_regions ;
2005-04-17 02:20:36 +04:00
}
memset ( brd , 0 , sizeof ( struct jsm_board ) ) ;
/* store the info for the board we've found */
2005-04-17 02:25:44 +04:00
brd - > boardnum = adapter_count + + ;
2005-04-17 02:20:36 +04:00
brd - > pci_dev = pdev ;
2005-04-17 02:25:44 +04:00
brd - > maxports = 2 ;
2005-04-17 02:20:36 +04:00
spin_lock_init ( & brd - > bd_lock ) ;
spin_lock_init ( & brd - > bd_intr_lock ) ;
/* store which revision we have */
pci_read_config_byte ( pdev , PCI_REVISION_ID , & brd - > rev ) ;
brd - > irq = pdev - > irq ;
2005-04-17 02:25:44 +04:00
jsm_printk ( INIT , INFO , & brd - > pci_dev ,
" jsm_found_board - NEO adapter \n " ) ;
2005-04-17 02:20:36 +04:00
2005-04-17 02:25:44 +04:00
/* get the PCI Base Address Registers */
brd - > membase = pci_resource_start ( pdev , 0 ) ;
brd - > membase_end = pci_resource_end ( pdev , 0 ) ;
2005-04-17 02:20:36 +04:00
2005-04-17 02:25:44 +04:00
if ( brd - > membase & 1 )
brd - > membase & = ~ 3 ;
else
brd - > membase & = ~ 15 ;
2005-04-17 02:20:36 +04:00
2005-04-17 02:25:44 +04:00
/* Assign the board_ops struct */
brd - > bd_ops = & jsm_neo_ops ;
2005-04-17 02:20:36 +04:00
2005-04-17 02:25:44 +04:00
brd - > bd_uart_offset = 0x200 ;
brd - > bd_dividend = 921600 ;
2005-04-17 02:20:36 +04:00
2005-04-17 02:25:44 +04:00
brd - > re_map_membase = ioremap ( brd - > membase , 0x1000 ) ;
if ( ! brd - > re_map_membase ) {
dev_err ( & pdev - > dev ,
" card has no PCI Memory resources, "
" failing board. \n " ) ;
rc = - ENOMEM ;
goto out_kfree_brd ;
2005-04-17 02:20:36 +04:00
}
2005-04-17 02:25:44 +04:00
rc = request_irq ( brd - > irq , brd - > bd_ops - > intr ,
SA_INTERRUPT | SA_SHIRQ , " JSM " , brd ) ;
if ( rc ) {
printk ( KERN_WARNING " Failed to hook IRQ %d \n " , brd - > irq ) ;
goto out_iounmap ;
2005-04-17 02:20:36 +04:00
}
rc = jsm_tty_init ( brd ) ;
if ( rc < 0 ) {
dev_err ( & pdev - > dev , " Can't init tty devices (%d) \n " , rc ) ;
retval = - ENXIO ;
2005-04-17 02:25:44 +04:00
goto out_free_irq ;
2005-04-17 02:20:36 +04:00
}
rc = jsm_uart_port_init ( brd ) ;
if ( rc < 0 ) {
2005-04-17 02:25:44 +04:00
/* XXX: leaking all resources from jsm_tty_init here! */
2005-04-17 02:20:36 +04:00
dev_err ( & pdev - > dev , " Can't init uart port (%d) \n " , rc ) ;
retval = - ENXIO ;
2005-04-17 02:25:44 +04:00
goto out_free_irq ;
2005-04-17 02:20:36 +04:00
}
/* Log the information about the board */
2005-04-17 02:25:44 +04:00
dev_info ( & pdev - > dev , " board %d: Digi Neo (rev %d), irq %d \n " ,
adapter_count , brd - > rev , brd - > irq ) ;
2005-04-17 02:20:36 +04:00
/*
* allocate flip buffer for board .
*
* Okay to malloc with GFP_KERNEL , we are not at interrupt
* context , and there are no locks held .
*/
brd - > flipbuf = kmalloc ( MYFLIPLEN , GFP_KERNEL ) ;
if ( ! brd - > flipbuf ) {
2005-04-17 02:25:44 +04:00
/* XXX: leaking all resources from jsm_tty_init and
jsm_uart_port_init here ! */
2005-04-17 02:20:36 +04:00
dev_err ( & pdev - > dev , " memory allocation for flipbuf failed \n " ) ;
retval = - ENOMEM ;
2005-04-17 02:25:44 +04:00
goto out_free_irq ;
2005-04-17 02:20:36 +04:00
}
memset ( brd - > flipbuf , 0 , MYFLIPLEN ) ;
2005-04-17 02:25:44 +04:00
pci_set_drvdata ( pdev , brd ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2005-04-17 02:25:44 +04:00
out_free_irq :
2005-04-17 02:20:36 +04:00
free_irq ( brd - > irq , brd ) ;
2005-04-17 02:25:44 +04:00
out_iounmap :
2005-04-17 02:20:36 +04:00
iounmap ( brd - > re_map_membase ) ;
2005-04-17 02:25:44 +04:00
out_kfree_brd :
kfree ( brd ) ;
out_release_regions :
pci_release_regions ( pdev ) ;
out_disable_device :
pci_disable_device ( pdev ) ;
out :
2005-04-17 02:20:36 +04:00
return rc ;
}
2005-04-17 02:25:44 +04:00
static void jsm_remove_one ( struct pci_dev * pdev )
2005-04-17 02:20:36 +04:00
{
2005-04-17 02:25:44 +04:00
struct jsm_board * brd = pci_get_drvdata ( pdev ) ;
2005-04-17 02:20:36 +04:00
int i = 0 ;
2005-04-17 02:25:44 +04:00
jsm_remove_uart_port ( brd ) ;
2005-04-17 02:20:36 +04:00
free_irq ( brd - > irq , brd ) ;
iounmap ( brd - > re_map_membase ) ;
/* Free all allocated channels structs */
for ( i = 0 ; i < brd - > maxports ; i + + ) {
if ( brd - > channels [ i ] ) {
2005-04-17 02:25:44 +04:00
kfree ( brd - > channels [ i ] - > ch_rqueue ) ;
kfree ( brd - > channels [ i ] - > ch_equeue ) ;
kfree ( brd - > channels [ i ] - > ch_wqueue ) ;
2005-04-17 02:20:36 +04:00
kfree ( brd - > channels [ i ] ) ;
}
}
2005-04-17 02:25:44 +04:00
pci_release_regions ( pdev ) ;
pci_disable_device ( pdev ) ;
2005-04-17 02:20:36 +04:00
kfree ( brd - > flipbuf ) ;
kfree ( brd ) ;
}
2005-04-17 02:25:44 +04:00
static struct pci_device_id jsm_pci_tbl [ ] = {
{ PCI_DEVICE ( PCI_VENDOR_ID_DIGI , PCI_DEVICE_ID_NEO_2DB9 ) , 0 , 0 , 0 } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_DIGI , PCI_DEVICE_ID_NEO_2DB9PRI ) , 0 , 0 , 1 } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_DIGI , PCI_DEVICE_ID_NEO_2RJ45 ) , 0 , 0 , 2 } ,
{ PCI_DEVICE ( PCI_VENDOR_ID_DIGI , PCI_DEVICE_ID_NEO_2RJ45PRI ) , 0 , 0 , 3 } ,
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , jsm_pci_tbl ) ;
2005-04-17 02:20:36 +04:00
2005-04-17 02:25:44 +04:00
static struct pci_driver jsm_driver = {
2005-04-17 02:20:36 +04:00
. name = " jsm " ,
. id_table = jsm_pci_tbl ,
2005-04-17 02:25:44 +04:00
. probe = jsm_probe_one ,
2005-04-17 02:20:36 +04:00
. remove = __devexit_p ( jsm_remove_one ) ,
} ;
static int __init jsm_init_module ( void )
{
2005-04-17 02:25:44 +04:00
int rc ;
2005-04-17 02:20:36 +04:00
rc = uart_register_driver ( & jsm_uart_driver ) ;
2005-04-17 02:25:44 +04:00
if ( ! rc ) {
rc = pci_register_driver ( & jsm_driver ) ;
if ( rc )
uart_unregister_driver ( & jsm_uart_driver ) ;
2005-04-17 02:20:36 +04:00
}
return rc ;
}
static void __exit jsm_exit_module ( void )
{
pci_unregister_driver ( & jsm_driver ) ;
uart_unregister_driver ( & jsm_uart_driver ) ;
}
2005-04-17 02:25:44 +04:00
module_init ( jsm_init_module ) ;
2005-04-17 02:20:36 +04:00
module_exit ( jsm_exit_module ) ;