2005-04-16 15:20:36 -07: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 >
2006-04-01 01:04:20 +02:00
* Wendy Xiong < wendyx @ us . ibm . com >
2005-04-16 15:20:36 -07:00
*
2005-07-27 11:43:49 -07:00
*
2005-04-16 15:20:36 -07:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <linux/moduleparam.h>
# include <linux/pci.h>
# include "jsm.h"
MODULE_AUTHOR ( " Digi International, http://www.digi.com " ) ;
2005-04-16 15:25:44 -07:00
MODULE_DESCRIPTION ( " Driver for the Digi International "
" Neo PCI based product line " ) ;
MODULE_LICENSE ( " GPL " ) ;
2005-04-16 15:20:36 -07: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 11:43:48 -07:00
. major = 0 ,
2005-04-16 15:20:36 -07: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 " ) ;
2009-04-06 17:34:17 +01:00
static int __devinit jsm_probe_one ( struct pci_dev * pdev , const struct pci_device_id * ent )
2005-04-16 15:20:36 -07:00
{
int rc = 0 ;
2005-04-16 15:25:44 -07:00
struct jsm_board * brd ;
static int adapter_count = 0 ;
2005-04-16 15:20:36 -07:00
2005-04-16 15:25:44 -07:00
rc = pci_enable_device ( pdev ) ;
if ( rc ) {
dev_err ( & pdev - > dev , " Device enable FAILED \n " ) ;
goto out ;
2005-04-16 15:20:36 -07:00
}
2005-04-16 15:25:44 -07:00
rc = pci_request_regions ( pdev , " jsm " ) ;
if ( rc ) {
dev_err ( & pdev - > dev , " pci_request_region FAILED \n " ) ;
goto out_disable_device ;
}
2005-04-16 15:20:36 -07:00
2007-02-14 00:33:07 -08:00
brd = kzalloc ( sizeof ( struct jsm_board ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! brd ) {
2005-04-16 15:25:44 -07:00
dev_err ( & pdev - > dev ,
" memory allocation for board structure failed \n " ) ;
rc = - ENOMEM ;
goto out_release_regions ;
2005-04-16 15:20:36 -07:00
}
/* store the info for the board we've found */
2005-04-16 15:25:44 -07:00
brd - > boardnum = adapter_count + + ;
2005-04-16 15:20:36 -07:00
brd - > pci_dev = pdev ;
2008-05-01 04:35:00 -07:00
if ( pdev - > device = = PCIE_DEVICE_ID_NEO_4_IBM )
brd - > maxports = 4 ;
2009-02-18 14:48:34 -08:00
else if ( pdev - > device = = PCI_DEVICE_ID_DIGI_NEO_8 )
brd - > maxports = 8 ;
2008-05-01 04:35:00 -07:00
else
brd - > maxports = 2 ;
2005-04-16 15:20:36 -07:00
spin_lock_init ( & brd - > bd_intr_lock ) ;
/* store which revision we have */
2007-06-08 15:46:36 -07:00
brd - > rev = pdev - > revision ;
2005-04-16 15:20:36 -07:00
brd - > irq = pdev - > irq ;
2005-04-16 15:25:44 -07:00
jsm_printk ( INIT , INFO , & brd - > pci_dev ,
" jsm_found_board - NEO adapter \n " ) ;
2005-04-16 15:20:36 -07:00
2005-04-16 15:25:44 -07:00
/* get the PCI Base Address Registers */
brd - > membase = pci_resource_start ( pdev , 0 ) ;
brd - > membase_end = pci_resource_end ( pdev , 0 ) ;
2005-04-16 15:20:36 -07:00
2005-04-16 15:25:44 -07:00
if ( brd - > membase & 1 )
brd - > membase & = ~ 3 ;
else
brd - > membase & = ~ 15 ;
2005-04-16 15:20:36 -07:00
2005-04-16 15:25:44 -07:00
/* Assign the board_ops struct */
brd - > bd_ops = & jsm_neo_ops ;
2005-04-16 15:20:36 -07:00
2005-04-16 15:25:44 -07:00
brd - > bd_uart_offset = 0x200 ;
brd - > bd_dividend = 921600 ;
2005-04-16 15:20:36 -07:00
2005-04-16 15:25:44 -07: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-16 15:20:36 -07:00
}
2005-04-16 15:25:44 -07:00
rc = request_irq ( brd - > irq , brd - > bd_ops - > intr ,
2006-07-01 19:29:43 -07:00
IRQF_DISABLED | IRQF_SHARED , " JSM " , brd ) ;
2005-04-16 15:25:44 -07:00
if ( rc ) {
printk ( KERN_WARNING " Failed to hook IRQ %d \n " , brd - > irq ) ;
goto out_iounmap ;
2005-04-16 15:20:36 -07:00
}
rc = jsm_tty_init ( brd ) ;
if ( rc < 0 ) {
dev_err ( & pdev - > dev , " Can't init tty devices (%d) \n " , rc ) ;
2009-04-06 17:34:27 +01:00
rc = - ENXIO ;
2005-04-16 15:25:44 -07:00
goto out_free_irq ;
2005-04-16 15:20:36 -07:00
}
rc = jsm_uart_port_init ( brd ) ;
if ( rc < 0 ) {
2005-04-16 15:25:44 -07:00
/* XXX: leaking all resources from jsm_tty_init here! */
2005-04-16 15:20:36 -07:00
dev_err ( & pdev - > dev , " Can't init uart port (%d) \n " , rc ) ;
2009-04-06 17:34:27 +01:00
rc = - ENXIO ;
2005-04-16 15:25:44 -07:00
goto out_free_irq ;
2005-04-16 15:20:36 -07:00
}
/* Log the information about the board */
2005-04-16 15:25:44 -07:00
dev_info ( & pdev - > dev , " board %d: Digi Neo (rev %d), irq %d \n " ,
adapter_count , brd - > rev , brd - > irq ) ;
2005-04-16 15:20:36 -07:00
/*
* allocate flip buffer for board .
*
* Okay to malloc with GFP_KERNEL , we are not at interrupt
* context , and there are no locks held .
*/
2007-02-14 00:33:07 -08:00
brd - > flipbuf = kzalloc ( MYFLIPLEN , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! brd - > flipbuf ) {
2005-04-16 15:25:44 -07:00
/* XXX: leaking all resources from jsm_tty_init and
jsm_uart_port_init here ! */
2005-04-16 15:20:36 -07:00
dev_err ( & pdev - > dev , " memory allocation for flipbuf failed \n " ) ;
2009-04-06 17:34:27 +01:00
rc = - ENOMEM ;
2005-04-16 15:25:44 -07:00
goto out_free_irq ;
2005-04-16 15:20:36 -07:00
}
2005-04-16 15:25:44 -07:00
pci_set_drvdata ( pdev , brd ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
2005-04-16 15:25:44 -07:00
out_free_irq :
2005-04-16 15:20:36 -07:00
free_irq ( brd - > irq , brd ) ;
2005-04-16 15:25:44 -07:00
out_iounmap :
2005-04-16 15:20:36 -07:00
iounmap ( brd - > re_map_membase ) ;
2005-04-16 15:25:44 -07:00
out_kfree_brd :
kfree ( brd ) ;
out_release_regions :
pci_release_regions ( pdev ) ;
out_disable_device :
pci_disable_device ( pdev ) ;
out :
2005-04-16 15:20:36 -07:00
return rc ;
}
2009-01-27 11:51:06 +00:00
static void __devexit jsm_remove_one ( struct pci_dev * pdev )
2005-04-16 15:20:36 -07:00
{
2005-04-16 15:25:44 -07:00
struct jsm_board * brd = pci_get_drvdata ( pdev ) ;
2005-04-16 15:20:36 -07:00
int i = 0 ;
2005-04-16 15:25:44 -07:00
jsm_remove_uart_port ( brd ) ;
2005-04-16 15:20:36 -07: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-16 15:25:44 -07:00
kfree ( brd - > channels [ i ] - > ch_rqueue ) ;
kfree ( brd - > channels [ i ] - > ch_equeue ) ;
kfree ( brd - > channels [ i ] - > ch_wqueue ) ;
2005-04-16 15:20:36 -07:00
kfree ( brd - > channels [ i ] ) ;
}
}
2005-04-16 15:25:44 -07:00
pci_release_regions ( pdev ) ;
pci_disable_device ( pdev ) ;
2005-04-16 15:20:36 -07:00
kfree ( brd - > flipbuf ) ;
kfree ( brd ) ;
}
2005-04-16 15:25:44 -07: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 } ,
2008-05-01 04:35:00 -07:00
{ PCI_DEVICE ( PCI_VENDOR_ID_DIGI , PCIE_DEVICE_ID_NEO_4_IBM ) , 0 , 0 , 4 } ,
2009-02-18 14:48:34 -08:00
{ PCI_DEVICE ( PCI_VENDOR_ID_DIGI , PCI_DEVICE_ID_DIGI_NEO_8 ) , 0 , 0 , 5 } ,
2005-04-16 15:25:44 -07:00
{ 0 , }
} ;
MODULE_DEVICE_TABLE ( pci , jsm_pci_tbl ) ;
2005-04-16 15:20:36 -07:00
2005-04-16 15:25:44 -07:00
static struct pci_driver jsm_driver = {
2005-04-16 15:20:36 -07:00
. name = " jsm " ,
. id_table = jsm_pci_tbl ,
2005-04-16 15:25:44 -07:00
. probe = jsm_probe_one ,
2005-04-16 15:20:36 -07:00
. remove = __devexit_p ( jsm_remove_one ) ,
} ;
static int __init jsm_init_module ( void )
{
2005-04-16 15:25:44 -07:00
int rc ;
2005-04-16 15:20:36 -07:00
rc = uart_register_driver ( & jsm_uart_driver ) ;
2005-04-16 15:25:44 -07:00
if ( ! rc ) {
rc = pci_register_driver ( & jsm_driver ) ;
if ( rc )
uart_unregister_driver ( & jsm_uart_driver ) ;
2005-04-16 15:20:36 -07:00
}
return rc ;
}
static void __exit jsm_exit_module ( void )
{
pci_unregister_driver ( & jsm_driver ) ;
uart_unregister_driver ( & jsm_uart_driver ) ;
}
2005-04-16 15:25:44 -07:00
module_init ( jsm_init_module ) ;
2005-04-16 15:20:36 -07:00
module_exit ( jsm_exit_module ) ;