staging: dgap: re-arrange functions for removing forward declarations
PATCH RESEND 1/1 staging: dgap: re-arrange functions for removing forward declarations
Re-arrange the functions for removing forward declarations.
---
RESEND: This patch is tested all by Mark.
It is good to merge. Greg, check please.
drivers/staging/dgap/dgap.c | 7462 +++++++++++++++++++++---------------------- 1 files changed, 3669 insertions(+), 3793 deletions(-)
drivers/staging/dgap/dgap.c +3669 -3793
@@ -65,145 +65,6 @@#include "dgap.h" -MODULE_LICENSE ("GPL" ); -MODULE_AUTHOR ("Digi International, http://www.digi.com" ); -MODULE_DESCRIPTION ("Driver for the Digi International EPCA PCI based product line" ); -MODULE_SUPPORTED_DEVICE ("dgap" ); - -static int dgap_start (void ); -static void dgap_stop (void ); -static void dgap_init_globals (void ); -static struct board_t *dgap_found_board (struct pci_dev *pdev,int id, -int boardnum); -static void dgap_cleanup_board (struct board_t *brd); -static void dgap_poll_handler (ulong dummy); -static int dgap_init_one (struct pci_dev *pdev,const struct pci_device_id *ent); -static void dgap_remove_one (struct pci_dev *dev); -static int dgap_remap (struct board_t *brd); -static void dgap_unmap (struct board_t *brd); -static irqreturn_t dgap_intr (int irq,void *voidbrd); - -static int dgap_tty_open (struct tty_struct *tty,struct file *file); -static void dgap_tty_close (struct tty_struct *tty,struct file *file); -static int dgap_block_til_ready (struct tty_struct *tty,struct file *file, -struct channel_t *ch); -static int dgap_tty_ioctl (struct tty_struct *tty,unsigned int cmd, -unsigned long arg); -static int dgap_tty_digigeta (struct channel_t *ch, -struct digi_t __user *retinfo); -static int dgap_tty_digiseta (struct channel_t *ch,struct board_t *bd, -struct un_t *un,struct digi_t __user *new_info); -static int dgap_tty_digigetedelay (struct tty_struct *tty,int __user *retinfo); -static int dgap_tty_digisetedelay (struct channel_t *ch,struct board_t *bd, -struct un_t *un,int __user *new_info); -static int dgap_tty_write_room (struct tty_struct *tty); -static int dgap_tty_chars_in_buffer (struct tty_struct *tty); -static void dgap_tty_start (struct tty_struct *tty); -static void dgap_tty_stop (struct tty_struct *tty); -static void dgap_tty_throttle (struct tty_struct *tty); -static void dgap_tty_unthrottle (struct tty_struct *tty); -static void dgap_tty_flush_chars (struct tty_struct *tty); -static void dgap_tty_flush_buffer (struct tty_struct *tty); -static void dgap_tty_hangup (struct tty_struct *tty); -static int dgap_wait_for_drain (struct tty_struct *tty); -static int dgap_set_modem_info (struct channel_t *ch,struct board_t *bd, -struct un_t *un,unsigned int command, -unsigned int __user *value); -static int dgap_get_modem_info (struct channel_t *ch, -unsigned int __user *value); -static int dgap_tty_digisetcustombaud (struct channel_t *ch,struct board_t *bd, -struct un_t *un,int __user *new_info); -static int dgap_tty_digigetcustombaud (struct channel_t *ch,struct un_t *un, -int __user *retinfo); -static int dgap_tty_tiocmget (struct tty_struct *tty); -static int dgap_tty_tiocmset (struct tty_struct *tty,unsigned int set, -unsigned int clear); -static int dgap_tty_send_break (struct tty_struct *tty,int msec); -static void dgap_tty_wait_until_sent (struct tty_struct *tty,int timeout); -static int dgap_tty_write (struct tty_struct *tty,const unsigned char *buf, -int count); -static void dgap_tty_set_termios (struct tty_struct *tty, -struct ktermios *old_termios); -static int dgap_tty_put_char (struct tty_struct *tty,unsigned char c); -static void dgap_tty_send_xchar (struct tty_struct *tty,char ch); - -static int dgap_tty_register (struct board_t *brd); -static void dgap_tty_unregister (struct board_t *brd); -static int dgap_tty_init (struct board_t *); -static void dgap_tty_free (struct board_t *); -static void dgap_cleanup_tty (struct board_t *); -static void dgap_carrier (struct channel_t *ch); -static void dgap_input (struct channel_t *ch); - -/* -* Our function prototypes from dgap_fep5 -*/ -static void dgap_cmdw_ext (struct channel_t *ch,u16 cmd,u16 word,uint ncmds); -static int dgap_event (struct board_t *bd); - -static void dgap_poll_tasklet (unsigned long data); -static void dgap_cmdb (struct channel_t *ch,u8 cmd,u8 byte1, -u8 byte2,uint ncmds); -static void dgap_cmdw (struct channel_t *ch,u8 cmd,u16 word,uint ncmds); -static void dgap_wmove (struct channel_t *ch,char *buf,uint cnt); -static int dgap_param (struct channel_t *ch,struct board_t *bd,u32 un_type); -static void dgap_parity_scan (struct channel_t *ch,unsigned char *cbuf, -unsigned char *fbuf,int *len); -static uint dgap_get_custom_baud (struct channel_t *ch); -static void dgap_firmware_reset_port (struct channel_t *ch); - -/* -* Function prototypes from dgap_parse.c. -*/ -static int dgap_gettok (char **in); -static char *dgap_getword (char **in); -static int dgap_checknode (struct cnode *p); - -/* -* Function prototypes from dgap_sysfs.h -*/ -static void dgap_create_ports_sysfiles (struct board_t *bd); -static void dgap_remove_ports_sysfiles (struct board_t *bd); - -static int dgap_create_driver_sysfiles (struct pci_driver *); -static void dgap_remove_driver_sysfiles (struct pci_driver *); - -static void dgap_create_tty_sysfs (struct un_t *un,struct device *c); -static void dgap_remove_tty_sysfs (struct device *c); - -/* -* Function prototypes from dgap_parse.h -*/ -static int dgap_parsefile (char **in); -static struct cnode *dgap_find_config (int type,int bus,int slot); -static uint dgap_config_get_num_prts (struct board_t *bd); -static char *dgap_create_config_string (struct board_t *bd,char *string); -static uint dgap_config_get_useintr (struct board_t *bd); -static uint dgap_config_get_altpin (struct board_t *bd); - -static void dgap_do_bios_load (struct board_t *brd,const u8 *ubios,int len); -static void dgap_do_fep_load (struct board_t *brd,const u8 *ufep,int len); -#ifdef DIGI_CONCENTRATORS_SUPPORTED -static void dgap_do_conc_load (struct board_t *brd,u8 *uaddr,int len); -#endif -static int dgap_alloc_flipbuf (struct board_t *brd); -static void dgap_free_flipbuf (struct board_t *brd); -static int dgap_request_irq (struct board_t *brd); -static void dgap_free_irq (struct board_t *brd); - -static void dgap_get_vpd (struct board_t *brd); -static void dgap_do_reset_board (struct board_t *brd); -static int dgap_test_bios (struct board_t *brd); -static int dgap_test_fep (struct board_t *brd); -static int dgap_tty_register_ports (struct board_t *brd); -static int dgap_firmware_load (struct pci_dev *pdev,int card_type, -struct board_t *brd); -static void dgap_cleanup_nodes (void ); - -static void dgap_cleanup_module (void ); - -module_exit (dgap_cleanup_module); -/* * File operations permitted on Control/Management major. */
@@ -298,13 +159,6 @@ static struct board_id dgap_ids[] = { {0,} /* 0 terminated list. */ }; -static struct pci_driver dgap_driver = { - .name ="dgap" , - .probe = dgap_init_one, - .id_table = dgap_pci_tbl, - .remove = dgap_remove_one, -}; -struct firmware_info {u8 *conf_name;/* dgap.conf */ u8 *bios_name;/* BIOS filename */
@@ -367,29 +221,6 @@ static struct ktermios dgap_default_termios = { .c_line = 0, }; -static const struct tty_operations dgap_tty_ops = { - .open = dgap_tty_open, - .close = dgap_tty_close, - .write = dgap_tty_write, - .write_room = dgap_tty_write_room, - .flush_buffer = dgap_tty_flush_buffer, - .chars_in_buffer = dgap_tty_chars_in_buffer, - .flush_chars = dgap_tty_flush_chars, - .ioctl = dgap_tty_ioctl, - .set_termios = dgap_tty_set_termios, - .stop = dgap_tty_stop, - .start = dgap_tty_start, - .throttle = dgap_tty_throttle, - .unthrottle = dgap_tty_unthrottle, - .hangup = dgap_tty_hangup, - .put_char = dgap_tty_put_char, - .tiocmget = dgap_tty_tiocmget, - .tiocmset = dgap_tty_tiocmset, - .break_ctl = dgap_tty_send_break, - .wait_until_sent = dgap_tty_wait_until_sent, - .send_xchar = dgap_tty_send_xchar -}; -/* * Our needed internal static variables from dgap_parse.c */
@@ -457,1089 +288,1226 @@ static struct toklist dgap_tlist[] = { { 0, NULL } }; -/************************************************************************ -* -* Driver load/unload functions -* -************************************************************************/ /* -* init_module() -* -* Module load. This is where it all starts. +* dgap_sindex: much like index(), but it looks for a match of any character in +* the group, and returns that position. If the first character is a ^, then +* this will match the first occurrence not in that group. */ -static int dgap_init_module (void ) +static char *dgap_sindex (char *string,char *group) { -int rc; - -pr_info ("%s, Digi International Part Number %s\n" ,DG_NAME ,DG_PART ); - - rc =dgap_start (); -if (rc) -return rc; - - rc =pci_register_driver (&dgap_driver); -if (rc) - goto err_stop; - - rc =dgap_create_driver_sysfiles (&dgap_driver); -if (rc) - goto err_unregister; - - dgap_driver_state =DRIVER_READY ; +char *ptr; -return 0 ; +if (!string || !group) +return (char *)NULL ; -err_unregister: -pci_unregister_driver (&dgap_driver); -err_stop: -dgap_stop (); +if (*group =='^' ) { + group++; +for (; *string; string++) { +for (ptr = group; *ptr; ptr++) { +if (*ptr == *string) +break ; + } +if (*ptr =='\0' ) +return string; + } + }else { +for (; *string; string++) { +for (ptr = group; *ptr; ptr++) { +if (*ptr == *string) +return string; + } + } + } -return rc; +return (char *)NULL ; } -module_init (dgap_init_module);/* -* Start of driver. +* get a word from the input stream, also keep track of current line number. +* words are separated by whitespace. */ -static int dgap_start (void ) +static char *dgap_getword (char **in) { -int rc; -unsigned long flags; -struct device *device; - -/* -* make sure that the globals are -* init'd before we do anything else -*/ -dgap_init_globals (); - - dgap_numboards =0 ; +char *ret_ptr = *in; -pr_info ("For the tools package please visit http://www.digi.com\n" ); +char *ptr =dgap_sindex (*in," \t\n" ); -/* -* Register our base character device into the kernel. -*/ +/* If no word found, return null */ +if (!ptr) +return NULL ; -/* -* Register management/dpa devices -*/ - rc =register_chrdev (DIGI_DGAP_MAJOR ,"dgap" , &dgap_board_fops); -if (rc <0 ) -return rc; +/* Mark new location for our buffer */ + *ptr ='\0' ; + *in = ptr +1 ; - dgap_class =class_create (THIS_MODULE ,"dgap_mgmt" ); -if (IS_ERR (dgap_class)) { - rc =PTR_ERR (dgap_class); - goto failed_class; +/* Eat any extra spaces/tabs/newlines that might be present */ +while (*in && **in && ((**in ==' ' ) || + (**in =='\t' ) || + (**in =='\n' ))) { + **in ='\0' ; + *in = *in +1 ; } - device =device_create (dgap_class,NULL , -MKDEV (DIGI_DGAP_MAJOR ,0 ), -NULL ,"dgap_mgmt" ); -if (IS_ERR (device)) { - rc =PTR_ERR (device); - goto failed_device; - } +return ret_ptr; +} -/* Start the poller */ -spin_lock_irqsave (&dgap_poll_lock, flags); -init_timer (&dgap_poll_timer); - dgap_poll_timer.function = dgap_poll_handler; - dgap_poll_timer.data =0 ; - dgap_poll_time = jiffies +dgap_jiffies_from_ms (dgap_poll_tick); - dgap_poll_timer.expires = dgap_poll_time; -spin_unlock_irqrestore (&dgap_poll_lock, flags); -add_timer (&dgap_poll_timer); +/* +* Get a token from the input file; return 0 if end of file is reached +*/ +static int dgap_gettok (char **in) +{ +char *w; +struct toklist *t; -return rc; +if (strstr (dgap_cword,"board" )) { + w =dgap_getword (in); +snprintf (dgap_cword,MAXCWORD ,"%s" , w); +for (t = dgap_brdtype; t->token !=0 ; t++) { +if (!strcmp (w, t->string)) +return t->token; + } + }else { +while ((w =dgap_getword (in))) { +snprintf (dgap_cword,MAXCWORD ,"%s" , w); +for (t = dgap_tlist; t->token !=0 ; t++) { +if (!strcmp (w, t->string)) +return t->token; + } + } + } -failed_device: -class_destroy (dgap_class); -failed_class: -unregister_chrdev (DIGI_DGAP_MAJOR ,"dgap" ); -return rc; +return 0 ; } -static void dgap_stop (void ) +/* +* dgap_checknode: see if all the necessary info has been supplied for a node +* before creating the next node. +*/ +static int dgap_checknode (struct cnode *p) { -unsigned long lock_flags; - -spin_lock_irqsave (&dgap_poll_lock, lock_flags); - dgap_poll_stop =1 ; -spin_unlock_irqrestore (&dgap_poll_lock, lock_flags); +switch (p->type) { +case LNODE : +if (p->u.line.v_speed ==0 ) { +pr_err ("line speed not specified" ); +return 1 ; + } +return 0 ; -del_timer_sync (&dgap_poll_timer); +case CNODE : +if (p->u.conc.v_speed ==0 ) { +pr_err ("concentrator line speed not specified" ); +return 1 ; + } +if (p->u.conc.v_nport ==0 ) { +pr_err ("number of ports on concentrator not specified" ); +return 1 ; + } +if (p->u.conc.v_id ==0 ) { +pr_err ("concentrator id letter not specified" ); +return 1 ; + } +return 0 ; -device_destroy (dgap_class,MKDEV (DIGI_DGAP_MAJOR ,0 )); -class_destroy (dgap_class); -unregister_chrdev (DIGI_DGAP_MAJOR ,"dgap" ); +case MNODE : +if (p->u.module.v_nport ==0 ) { +pr_err ("number of ports on EBI module not specified" ); +return 1 ; + } +if (p->u.module.v_id ==0 ) { +pr_err ("EBI module id letter not specified" ); +return 1 ; + } +return 0 ; + } +return 0 ; } -static int dgap_init_one (struct pci_dev *pdev,const struct pci_device_id *ent) +/* +* Given a board pointer, returns whether we should use interrupts or not. +*/ +static uint dgap_config_get_useintr (struct board_t *bd) { -int rc; -struct board_t *brd; - -if (dgap_numboards >=MAXBOARDS ) -return -EPERM ; - - rc =pci_enable_device (pdev); -if (rc) -return -EIO ; - - brd =dgap_found_board (pdev, ent->driver_data, dgap_numboards); -if (IS_ERR (brd)) -return PTR_ERR (brd); - - rc =dgap_firmware_load (pdev, ent->driver_data, brd); -if (rc) - goto cleanup_brd; - - rc =dgap_alloc_flipbuf (brd); -if (rc) - goto cleanup_brd; - - rc =dgap_tty_register (brd); -if (rc) - goto free_flipbuf; - - rc =dgap_request_irq (brd); -if (rc) - goto unregister_tty; - -/* -* Do tty device initialization. -*/ - rc =dgap_tty_init (brd); -if (rc <0 ) - goto free_irq; - - rc =dgap_tty_register_ports (brd); -if (rc) - goto tty_free; +struct cnode *p; - brd->state =BOARD_READY ; - brd->dpastatus =BD_RUNNING ; +if (!bd) +return 0 ; - dgap_board[dgap_numboards++] = brd; +for (p = bd->bd_config; p; p = p->next) { +if (p->type ==INTRNODE ) { +/* +* check for pcxr types. +*/ +return p->u.useintr; + } + } +/* If not found, then don't turn on interrupts. */ return 0 ; - -tty_free: -dgap_tty_free (brd); -free_irq: -dgap_free_irq (brd); -unregister_tty: -dgap_tty_unregister (brd); -free_flipbuf: -dgap_free_flipbuf (brd); -cleanup_brd: -dgap_cleanup_nodes (); -dgap_unmap (brd); -kfree (brd); - -return rc; -} - -static void dgap_remove_one (struct pci_dev *dev) -{ -/* Do Nothing */ }/* -* dgap_cleanup_module() -* -* Module unload. This is where it all ends. +* Given a board pointer, returns whether we turn on altpin or not. */ -static void dgap_cleanup_module (void ) +static uint dgap_config_get_altpin (struct board_t *bd) { -int i; -ulong lock_flags; - -spin_lock_irqsave (&dgap_poll_lock, lock_flags); - dgap_poll_stop =1 ; -spin_unlock_irqrestore (&dgap_poll_lock, lock_flags); - -/* Turn off poller right away. */ -del_timer_sync (&dgap_poll_timer); - -dgap_remove_driver_sysfiles (&dgap_driver); +struct cnode *p; -device_destroy (dgap_class,MKDEV (DIGI_DGAP_MAJOR ,0 )); -class_destroy (dgap_class); -unregister_chrdev (DIGI_DGAP_MAJOR ,"dgap" ); +if (!bd) +return 0 ; -for (i =0 ; i < dgap_numboards; ++i) { -dgap_remove_ports_sysfiles (dgap_board[i]); -dgap_cleanup_tty (dgap_board[i]); -dgap_cleanup_board (dgap_board[i]); +for (p = bd->bd_config; p; p = p->next) { +if (p->type ==ANODE ) { +/* +* check for pcxr types. +*/ +return p->u.altpin; + } } -dgap_cleanup_nodes (); - -if (dgap_numboards) -pci_unregister_driver (&dgap_driver); +/* If not found, then don't turn on interrupts. */ +return 0 ; }/* -* dgap_cleanup_board() -* -* Free all the memory associated with a board +* Given a specific type of board, if found, detached link and +* returns the first occurrence in the list. */ -static void dgap_cleanup_board (struct board_t *brd) +static struct cnode *dgap_find_config (int type,int bus,int slot) { -int i; +struct cnode *p, *prev, *prev2, *found; -if (!brd || brd->magic !=DGAP_BOARD_MAGIC ) -return ; + p = &dgap_head; -dgap_free_irq (brd); +while (p->next) { + prev = p; + p = p->next; -tasklet_kill (&brd->helper_tasklet); +if (p->type !=BNODE ) +continue ; -dgap_unmap (brd); +if (p->u.board.type != type) +continue ; -/* Free all allocated channels structs */ -for (i =0 ; i <MAXPORTS ; i++) -kfree (brd->channels[i]); +if (p->u.board.v_pcibus && + p->u.board.pcibus != bus) +continue ; -kfree (brd->flipbuf); -kfree (brd->flipflagbuf); +if (p->u.board.v_pcislot && + p->u.board.pcislot != slot) +continue ; - dgap_board[brd->boardnum] =NULL ; + found = p; +/* +* Keep walking thru the list till we +* find the next board. +*/ +while (p->next) { + prev2 = p; + p = p->next; -kfree (brd); +if (p->type !=BNODE ) +continue ; + +/* +* Mark the end of our 1 board +* chain of configs. +*/ + prev2->next =NULL ; + +/* +* Link the "next" board to the +* previous board, effectively +* "unlinking" our board from +* the main config. +*/ + prev->next = p; + +return found; + } +/* +* It must be the last board in the list. +*/ + prev->next =NULL ; +return found; + } +return NULL ; }/* -* dgap_found_board() -* -* A board has been found, init it. +* Given a board pointer, walks the config link, counting up +* all ports user specified should be on the board. +* (This does NOT mean they are all actually present right now tho) */ -static struct board_t *dgap_found_board (struct pci_dev *pdev,int id, -int boardnum) +static uint dgap_config_get_num_prts (struct board_t *bd) { -struct board_t *brd; -unsigned int pci_irq; -int i; -int ret; - -/* get the board structure and prep it */ - brd =kzalloc (sizeof (struct board_t ),GFP_KERNEL ); -if (!brd) -return ERR_PTR (-ENOMEM ); - -/* store the info for the board we've found */ - brd->magic =DGAP_BOARD_MAGIC ; - brd->boardnum = boardnum; - brd->vendor = dgap_pci_tbl[id].vendor; - brd->device = dgap_pci_tbl[id].device; - brd->pdev = pdev; - brd->pci_bus = pdev->bus->number; - brd->pci_slot =PCI_SLOT (pdev->devfn); - brd->name = dgap_ids[id].name; - brd->maxports = dgap_ids[id].maxports; - brd->type = dgap_ids[id].config_type; - brd->dpatype = dgap_ids[id].dpatype; - brd->dpastatus =BD_NOFEP ; -init_waitqueue_head (&brd->state_wait); +int count =0 ; +struct cnode *p; -spin_lock_init (&brd->bd_lock); +if (!bd) +return 0 ; - brd->inhibit_poller = FALSE; - brd->wait_for_bios =0 ; - brd->wait_for_fep =0 ; +for (p = bd->bd_config; p; p = p->next) { -for (i =0 ; i <MAXPORTS ; i++) - brd->channels[i] =NULL ; +switch (p->type) { +case BNODE : +/* +* check for pcxr types. +*/ +if (p->u.board.type >EPCFE ) + count += p->u.board.nport; +break ; +case CNODE : + count += p->u.conc.nport; +break ; +case MNODE : + count += p->u.module.nport; +break ; + } + } +return count; +} -/* store which card & revision we have */ -pci_read_config_word (pdev,PCI_SUBSYSTEM_VENDOR_ID , &brd->subvendor); -pci_read_config_word (pdev,PCI_SUBSYSTEM_ID , &brd->subdevice); -pci_read_config_byte (pdev,PCI_REVISION_ID , &brd->rev); +static char *dgap_create_config_string (struct board_t *bd,char *string) +{ +char *ptr = string; +struct cnode *p; +struct cnode *q; +int speed; - pci_irq = pdev->irq; - brd->irq = pci_irq; +if (!bd) { + *ptr =0xff ; +return string; + } -/* get the PCI Base Address Registers */ +for (p = bd->bd_config; p; p = p->next) { -/* Xr Jupiter and EPC use BAR 2 */ -if (brd->device ==PCI_DEV_XRJ_DID || brd->device ==PCI_DEV_EPCJ_DID ) { - brd->membase =pci_resource_start (pdev,2 ); - brd->membase_end =pci_resource_end (pdev,2 ); - } -/* Everyone else uses BAR 0 */ -else { - brd->membase =pci_resource_start (pdev,0 ); - brd->membase_end =pci_resource_end (pdev,0 ); - } +switch (p->type) { +case LNODE : + *ptr ='\0' ; + ptr++; + *ptr = p->u.line.speed; + ptr++; +break ; +case CNODE : +/* +* Because the EPC/con concentrators can have EM modules +* hanging off of them, we have to walk ahead in the +* list and keep adding the number of ports on each EM +* to the config. UGH! +*/ + speed = p->u.conc.speed; + q = p->next; +if (q && (q->type ==MNODE )) { + *ptr = (p->u.conc.nport +0x80 ); + ptr++; + p = q; +while (q->next && (q->next->type) ==MNODE ) { + *ptr = (q->u.module.nport +0x80 ); + ptr++; + p = q; + q = q->next; + } + *ptr = q->u.module.nport; + ptr++; + }else { + *ptr = p->u.conc.nport; + ptr++; + } -if (!brd->membase) { - ret = -ENODEV ; - goto free_brd; + *ptr = speed; + ptr++; +break ; + } } -if (brd->membase &1 ) - brd->membase &= ~3 ; -else - brd->membase &= ~15 ; - -/* -* On the PCI boards, there is no IO space allocated -* The I/O registers will be in the first 3 bytes of the -* upper 2MB of the 4MB memory space. The board memory -* will be mapped into the low 2MB of the 4MB memory space -*/ - brd->port = brd->membase +PCI_IO_OFFSET ; - brd->port_end = brd->port +PCI_IO_SIZE ; + *ptr =0xff ; +return string; +} -/* -* Special initialization for non-PLX boards -*/ -if (brd->device !=PCI_DEV_XRJ_DID && brd->device !=PCI_DEV_EPCJ_DID ) { -unsigned short cmd; +/* +* Parse a configuration file read into memory as a string. +*/ +static int dgap_parsefile (char **in) +{ +struct cnode *p, *brd, *line, *conc; +int rc; +char *s; +int linecnt =0 ; -pci_write_config_byte (pdev,0x40 ,0 ); -pci_write_config_byte (pdev,0x46 ,0 ); + p = &dgap_head; + brd = line = conc =NULL ; -/* Limit burst length to 2 doubleword transactions */ -pci_write_config_byte (pdev,0x42 ,1 ); +/* perhaps we are adding to an existing list? */ +while (p->next) + p = p->next; -/* -* Enable IO and mem if not already done. -* This was needed for support on Itanium. -*/ -pci_read_config_word (pdev,PCI_COMMAND , &cmd); - cmd |= (PCI_COMMAND_IO |PCI_COMMAND_MEMORY ); -pci_write_config_word (pdev,PCI_COMMAND , cmd); +/* file must start with a BEGIN */ +while ((rc =dgap_gettok (in)) !=BEGIN ) { +if (rc ==0 ) { +pr_err ("unexpected EOF" ); +return -1 ; + } } -/* init our poll helper tasklet */ -tasklet_init (&brd->helper_tasklet, dgap_poll_tasklet, - (unsigned long ) brd); +for (; ;) { +int board_type =0 ; +int conc_type =0 ; +int module_type =0 ; - ret =dgap_remap (brd); -if (ret) - goto free_brd; + rc =dgap_gettok (in); +if (rc ==0 ) { +pr_err ("unexpected EOF" ); +return -1 ; + } -pr_info ("dgap: board %d: %s (rev %d), irq %ld\n" , - boardnum, brd->name, brd->rev, brd->irq); +switch (rc) { +case BEGIN :/* should only be 1 begin */ +pr_err ("unexpected config_begin\n" ); +return -1 ; -return brd; +case END : +return 0 ; -free_brd: -kfree (brd); +case BOARD :/* board info */ +if (dgap_checknode (p)) +return -1 ; -return ERR_PTR (ret); -} + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; + p = p->next; -static int dgap_request_irq (struct board_t *brd) -{ -int rc; + p->type =BNODE ; + p->u.board.status =kstrdup ("No" ,GFP_KERNEL ); + line = conc =NULL ; + brd = p; + linecnt =-1 ; -if (!brd || brd->magic !=DGAP_BOARD_MAGIC ) -return -ENODEV ; + board_type =dgap_gettok (in); +if (board_type ==0 ) { +pr_err ("board !!type not specified" ); +return -1 ; + } -/* -* Set up our interrupt handler if we are set to do interrupts. -*/ -if (dgap_config_get_useintr (brd) && brd->irq) { + p->u.board.type = board_type; - rc =request_irq (brd->irq, dgap_intr,IRQF_SHARED ,"DGAP" , brd); +break ; -if (!rc) - brd->intr_used =1 ; - } -return 0 ; -} +case IO :/* i/o port */ +if (p->type !=BNODE ) { +pr_err ("IO port only vaild for boards" ); +return -1 ; + } + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } + p->u.board.portstr =kstrdup (s,GFP_KERNEL ); +if (kstrtol (s,0 , &p->u.board.port)) { +pr_err ("bad number for IO port" ); +return -1 ; + } + p->u.board.v_port =1 ; +break ; -static void dgap_free_irq (struct board_t *brd) -{ -if (brd->intr_used && brd->irq) -free_irq (brd->irq, brd); -} +case MEM :/* memory address */ +if (p->type !=BNODE ) { +pr_err ("memory address only vaild for boards" ); +return -1 ; + } + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } + p->u.board.addrstr =kstrdup (s,GFP_KERNEL ); +if (kstrtoul (s,0 , &p->u.board.addr)) { +pr_err ("bad number for memory address" ); +return -1 ; + } + p->u.board.v_addr =1 ; +break ; -static int dgap_firmware_load (struct pci_dev *pdev,int card_type, -struct board_t *brd) -{ -const struct firmware *fw; -char *tmp_ptr; -int ret; -char *dgap_config_buf; +case PCIINFO :/* pci information */ +if (p->type !=BNODE ) { +pr_err ("memory address only vaild for boards" ); +return -1 ; + } + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } + p->u.board.pcibusstr =kstrdup (s,GFP_KERNEL ); +if (kstrtoul (s,0 , &p->u.board.pcibus)) { +pr_err ("bad number for pci bus" ); +return -1 ; + } + p->u.board.v_pcibus =1 ; + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } + p->u.board.pcislotstr =kstrdup (s,GFP_KERNEL ); +if (kstrtoul (s,0 , &p->u.board.pcislot)) { +pr_err ("bad number for pci slot" ); +return -1 ; + } + p->u.board.v_pcislot =1 ; +break ; -dgap_get_vpd (brd); -dgap_do_reset_board (brd); +case METHOD : +if (p->type !=BNODE ) { +pr_err ("install method only vaild for boards" ); +return -1 ; + } + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } + p->u.board.method =kstrdup (s,GFP_KERNEL ); + p->u.board.v_method =1 ; +break ; -if (fw_info[card_type].conf_name) { - ret =request_firmware (&fw, fw_info[card_type].conf_name, - &pdev->dev); -if (ret) { -dev_err (&pdev->dev,"config file %s not found\n" , - fw_info[card_type].conf_name); -return ret; - } +case STATUS : +if (p->type !=BNODE ) { +pr_err ("config status only vaild for boards" ); +return -1 ; + } + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } + p->u.board.status =kstrdup (s,GFP_KERNEL ); +break ; - dgap_config_buf =kzalloc (fw->size +1 ,GFP_KERNEL ); -if (!dgap_config_buf) { -release_firmware (fw); -return -ENOMEM ; - } +case NPORTS :/* number of ports */ +if (p->type ==BNODE ) { + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.board.nport)) { +pr_err ("bad number for number of ports" ); +return -1 ; + } + p->u.board.v_nport =1 ; + }else if (p->type ==CNODE ) { + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.conc.nport)) { +pr_err ("bad number for number of ports" ); +return -1 ; + } + p->u.conc.v_nport =1 ; + }else if (p->type ==MNODE ) { + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.module.nport)) { +pr_err ("bad number for number of ports" ); +return -1 ; + } + p->u.module.v_nport =1 ; + }else { +pr_err ("nports only valid for concentrators or modules" ); +return -1 ; + } +break ; -memcpy (dgap_config_buf, fw->data, fw->size); -release_firmware (fw); +case ID :/* letter ID used in tty name */ + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } -/* -* preserve dgap_config_buf -* as dgap_parsefile would -* otherwise alter it. -*/ - tmp_ptr = dgap_config_buf; + p->u.board.status =kstrdup (s,GFP_KERNEL ); -if (dgap_parsefile (&tmp_ptr) !=0 ) { -kfree (dgap_config_buf); -return -EINVAL ; - } -kfree (dgap_config_buf); - } +if (p->type ==CNODE ) { + p->u.conc.id =kstrdup (s,GFP_KERNEL ); + p->u.conc.v_id =1 ; + }else if (p->type ==MNODE ) { + p->u.module.id =kstrdup (s,GFP_KERNEL ); + p->u.module.v_id =1 ; + }else { +pr_err ("id only valid for concentrators or modules" ); +return -1 ; + } +break ; -/* -* Match this board to a config the user created for us. -*/ - brd->bd_config = -dgap_find_config (brd->type, brd->pci_bus, brd->pci_slot); +case STARTO :/* start offset of ID */ +if (p->type ==BNODE ) { + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.board.start)) { +pr_err ("bad number for start of tty count" ); +return -1 ; + } + p->u.board.v_start =1 ; + }else if (p->type ==CNODE ) { + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.conc.start)) { +pr_err ("bad number for start of tty count" ); +return -1 ; + } + p->u.conc.v_start =1 ; + }else if (p->type ==MNODE ) { + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.module.start)) { +pr_err ("bad number for start of tty count" ); +return -1 ; + } + p->u.module.v_start =1 ; + }else { +pr_err ("start only valid for concentrators or modules" ); +return -1 ; + } +break ; -/* -* Because the 4 port Xr products share the same PCI ID -* as the 8 port Xr products, if we receive a NULL config -* back, and this is a PAPORT8 board, retry with a -* PAPORT4 attempt as well. -*/ -if (brd->type ==PAPORT8 && !brd->bd_config) - brd->bd_config = -dgap_find_config (PAPORT4 , brd->pci_bus, brd->pci_slot); +case TTYN :/* tty name prefix */ +if (dgap_checknode (p)) +return -1 ; -if (!brd->bd_config) { -dev_err (&pdev->dev,"No valid configuration found\n" ); -return -EINVAL ; - } + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -if (fw_info[card_type].bios_name) { - ret =request_firmware (&fw, fw_info[card_type].bios_name, - &pdev->dev); -if (ret) { -dev_err (&pdev->dev,"bios file %s not found\n" , - fw_info[card_type].bios_name); -return ret; - } -dgap_do_bios_load (brd, fw->data, fw->size); -release_firmware (fw); + p = p->next; + p->type =TNODE ; -/* Wait for BIOS to test board... */ - ret =dgap_test_bios (brd); -if (ret) -return ret; - } + s =dgap_getword (in); +if (!s) { +pr_err ("unexpeced end of file" ); +return -1 ; + } + p->u.ttyname =kstrdup (s,GFP_KERNEL ); +if (!p->u.ttyname) +return -1 ; -if (fw_info[card_type].fep_name) { - ret =request_firmware (&fw, fw_info[card_type].fep_name, - &pdev->dev); -if (ret) { -dev_err (&pdev->dev,"dgap: fep file %s not found\n" , - fw_info[card_type].fep_name); -return ret; - } -dgap_do_fep_load (brd, fw->data, fw->size); -release_firmware (fw); +break ; -/* Wait for FEP to load on board... */ - ret =dgap_test_fep (brd); -if (ret) -return ret; - } +case CU :/* cu name prefix */ +if (dgap_checknode (p)) +return -1 ; -#ifdef DIGI_CONCENTRATORS_SUPPORTED -/* -* If this is a CX or EPCX, we need to see if the firmware -* is requesting a concentrator image from us. -*/ -if ((bd->type ==PCX ) || (bd->type ==PEPC )) { - chk_addr = (u16 *) (vaddr +DOWNREQ ); -/* Nonzero if FEP is requesting concentrator image. */ - check =readw (chk_addr); - vaddr = brd->re_map_membase; - } + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -if (fw_info[card_type].con_name && check && vaddr) { - ret =request_firmware (&fw, fw_info[card_type].con_name, - &pdev->dev); -if (ret) { -dev_err (&pdev->dev,"conc file %s not found\n" , - fw_info[card_type].con_name); -return ret; - } -/* Put concentrator firmware loading code here */ - offset =readw ((u16 *) (vaddr +DOWNREQ )); -memcpy_toio (offset, fw->data, fw->size); + p = p->next; + p->type =CUNODE ; - dgap_do_conc_load(brd, (char *)fw->data, fw->size) -release_firmware (fw); - } -#endif + s =dgap_getword (in); +if (!s) { +pr_err ("unexpeced end of file" ); +return -1 ; + } + p->u.cuname =kstrdup (s,GFP_KERNEL ); +if (!p->u.cuname) +return -1 ; -return 0 ; -} +break ; -/* -* Remap PCI memory. -*/ -static int dgap_remap (struct board_t *brd) -{ -if (!brd || brd->magic !=DGAP_BOARD_MAGIC ) -return -EIO ; +case LINE :/* line information */ +if (dgap_checknode (p)) +return -1 ; +if (!brd) { +pr_err ("must specify board before line info" ); +return -1 ; + } +switch (brd->u.board.type) { +case PPCM : +pr_err ("line not vaild for PC/em" ); +return -1 ; + } -if (!request_mem_region (brd->membase,0x200000 ,"dgap" )) -return -ENOMEM ; + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -if (!request_mem_region (brd->membase +PCI_IO_OFFSET ,0x200000 , -"dgap" )) { -release_mem_region (brd->membase,0x200000 ); -return -ENOMEM ; - } + p = p->next; + p->type =LNODE ; + conc =NULL ; + line = p; + linecnt++; +break ; - brd->re_map_membase =ioremap (brd->membase,0x200000 ); -if (!brd->re_map_membase) { -release_mem_region (brd->membase,0x200000 ); -release_mem_region (brd->membase +PCI_IO_OFFSET ,0x200000 ); -return -ENOMEM ; - } +case CONC :/* concentrator information */ +if (dgap_checknode (p)) +return -1 ; +if (!line) { +pr_err ("must specify line info before concentrator" ); +return -1 ; + } - brd->re_map_port =ioremap ((brd->membase +PCI_IO_OFFSET ),0x200000 ); -if (!brd->re_map_port) { -release_mem_region (brd->membase,0x200000 ); -release_mem_region (brd->membase +PCI_IO_OFFSET ,0x200000 ); -iounmap (brd->re_map_membase); -return -ENOMEM ; - } + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -return 0 ; -} + p = p->next; + p->type =CNODE ; + conc = p; -static void dgap_unmap (struct board_t *brd) -{ -iounmap (brd->re_map_port); -iounmap (brd->re_map_membase); -release_mem_region (brd->membase +PCI_IO_OFFSET ,0x200000 ); -release_mem_region (brd->membase,0x200000 ); -} -/***************************************************************************** -* -* Function: -* -* dgap_poll_handler -* -* Author: -* -* Scott H Kilau -* -* Parameters: -* -* dummy -- ignored -* -* Return Values: -* -* none -* -* Description: -* -* As each timer expires, it determines (a) whether the "transmit" -* waiter needs to be woken up, and (b) whether the poller needs to -* be rescheduled. -* -******************************************************************************/ +if (linecnt) + brd->u.board.conc2++; +else + brd->u.board.conc1++; -static void dgap_poll_handler (ulong dummy) -{ -int i; -struct board_t *brd; -unsigned long lock_flags; -ulong new_time; + conc_type =dgap_gettok (in); +if (conc_type ==0 || conc_type !=CX || + conc_type !=EPC ) { +pr_err ("failed to set a type of concentratros" ); +return -1 ; + } - dgap_poll_counter++; + p->u.conc.type = conc_type; -/* -* Do not start the board state machine until -* driver tells us its up and running, and has -* everything it needs. -*/ -if (dgap_driver_state !=DRIVER_READY ) - goto schedule_poller; +break ; -/* -* If we have just 1 board, or the system is not SMP, -* then use the typical old style poller. -* Otherwise, use our new tasklet based poller, which should -* speed things up for multiple boards. -*/ -if ((dgap_numboards ==1 ) || (num_online_cpus () <=1 )) { -for (i =0 ; i < dgap_numboards; i++) { +case MOD :/* EBI module */ +if (dgap_checknode (p)) +return -1 ; +if (!brd) { +pr_err ("must specify board info before EBI modules" ); +return -1 ; + } +switch (brd->u.board.type) { +case PPCM : + linecnt =0 ; +break ; +default : +if (!conc) { +pr_err ("must specify concentrator info before EBI module" ); +return -1 ; + } + } - brd = dgap_board[i]; + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -if (brd->state ==BOARD_FAILED ) -continue ; -if (!brd->intr_running) -/* Call the real board poller directly */ -dgap_poll_tasklet ((unsigned long ) brd); - } - }else { -/* -* Go thru each board, kicking off a -* tasklet for each if needed -*/ -for (i =0 ; i < dgap_numboards; i++) { - brd = dgap_board[i]; + p = p->next; + p->type =MNODE ; -/* -* Attempt to grab the board lock. -* -* If we can't get it, no big deal, the next poll -* will get it. Basically, I just really don't want -* to spin in here, because I want to kick off my -* tasklets as fast as I can, and then get out the -* poller. -*/ -if (!spin_trylock (&brd->bd_lock)) -continue ; +if (linecnt) + brd->u.board.module2++; +else + brd->u.board.module1++; -/* -* If board is in a failed state, don't bother -* scheduling a tasklet -*/ -if (brd->state ==BOARD_FAILED ) { -spin_unlock (&brd->bd_lock); -continue ; + module_type =dgap_gettok (in); +if (module_type ==0 || module_type !=PORTS || + module_type !=MODEM ) { +pr_err ("failed to set a type of module" ); +return -1 ; } -/* Schedule a poll helper task */ -if (!brd->intr_running) -tasklet_schedule (&brd->helper_tasklet); - -/* -* Can't do DGAP_UNLOCK here, as we don't have -* lock_flags because we did a trylock above. -*/ -spin_unlock (&brd->bd_lock); - } - } + p->u.module.type = module_type; -schedule_poller: +break ; -/* -* Schedule ourself back at the nominal wakeup interval. -*/ -spin_lock_irqsave (&dgap_poll_lock, lock_flags); - dgap_poll_time +=dgap_jiffies_from_ms (dgap_poll_tick); +case CABLE : +if (p->type ==LNODE ) { + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } + p->u.line.cable =kstrdup (s,GFP_KERNEL ); + p->u.line.v_cable =1 ; + } +break ; - new_time = dgap_poll_time - jiffies; +case SPEED :/* sync line speed indication */ +if (p->type ==LNODE ) { + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.line.speed)) { +pr_err ("bad number for line speed" ); +return -1 ; + } + p->u.line.v_speed =1 ; + }else if (p->type ==CNODE ) { + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.conc.speed)) { +pr_err ("bad number for line speed" ); +return -1 ; + } + p->u.conc.v_speed =1 ; + }else { +pr_err ("speed valid only for lines or concentrators." ); +return -1 ; + } +break ; -if ((ulong ) new_time >=2 * dgap_poll_tick) { - dgap_poll_time = - jiffies +dgap_jiffies_from_ms (dgap_poll_tick); - } +case CONNECT : +if (p->type ==CNODE ) { + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } + p->u.conc.connect =kstrdup (s,GFP_KERNEL ); + p->u.conc.v_connect =1 ; + } +break ; +case /* transparent print name prefix */ +if (dgap_checknode (p)) +return -1 ; - dgap_poll_timer.function = dgap_poll_handler; - dgap_poll_timer.data =0 ; - dgap_poll_timer.expires = dgap_poll_time; -spin_unlock_irqrestore (&dgap_poll_lock, lock_flags); + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -if (!dgap_poll_stop) -add_timer (&dgap_poll_timer); -} + p = p->next; + p->type =PNODE ; -/* -* dgap_intr() -* -* Driver interrupt handler. -*/ -static irqreturn_t dgap_intr (int irq,void *voidbrd) -{ -struct board_t *brd = (struct board_t *) voidbrd; + s =dgap_getword (in); +if (!s) { +pr_err ("unexpeced end of file" ); +return -1 ; + } + p->u.printname =kstrdup (s,GFP_KERNEL ); +if (!p->u.printname) +return -1 ; -if (!brd) -return IRQ_NONE ; +break ; -/* -* Check to make sure its for us. -*/ -if (brd->magic !=DGAP_BOARD_MAGIC ) -return IRQ_NONE ; +case CMAJOR :/* major number */ +if (dgap_checknode (p)) +return -1 ; - brd->intr_count++; + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -/* -* Schedule tasklet to run at a better time. -*/ -tasklet_schedule (&brd->helper_tasklet); -return IRQ_HANDLED ; -} + p = p->next; + p->type =JNODE ; -/* -* dgap_init_globals() -* -* This is where we initialize the globals from the static insmod -* configuration variables. These are declared near the head of -* this file. -*/ -static void dgap_init_globals (void ) -{ -int i; + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.majornumber)) { +pr_err ("bad number for major number" ); +return -1 ; + } +break ; -for (i =0 ; i <MAXBOARDS ; i++) - dgap_board[i] =NULL ; +case ALTPIN :/* altpin setting */ +if (dgap_checknode (p)) +return -1 ; -init_timer (&dgap_poll_timer); -} + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -/************************************************************************ -* -* TTY Initialization/Cleanup Functions -* -************************************************************************/ + p = p->next; + p->type =ANODE ; -/* -* dgap_tty_register() -* -* Init the tty subsystem for this board. -*/ -static int dgap_tty_register (struct board_t *brd) -{ -int rc; + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.altpin)) { +pr_err ("bad number for altpin" ); +return -1 ; + } +break ; - brd->serial_driver =tty_alloc_driver (MAXPORTS ,0 ); -if (IS_ERR (brd->serial_driver)) -return PTR_ERR (brd->serial_driver); +case USEINTR :/* enable interrupt setting */ +if (dgap_checknode (p)) +return -1 ; -snprintf (brd->serial_name,MAXTTYNAMELEN ,"tty_dgap_%d_" , - brd->boardnum); - brd->serial_driver->name = brd->serial_name; - brd->serial_driver->name_base =0 ; - brd->serial_driver->major =0 ; - brd->serial_driver->minor_start =0 ; - brd->serial_driver->type =TTY_DRIVER_TYPE_SERIAL ; - brd->serial_driver->subtype =SERIAL_TYPE_NORMAL ; - brd->serial_driver->init_termios = dgap_default_termios; - brd->serial_driver->driver_name =DRVSTR ; - brd->serial_driver->flags = (TTY_DRIVER_REAL_RAW | -TTY_DRIVER_DYNAMIC_DEV | -TTY_DRIVER_HARDWARE_BREAK ); + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -/* The kernel wants space to store pointers to tty_structs */ - brd->serial_driver->ttys = -kzalloc (MAXPORTS *sizeof (struct tty_struct *),GFP_KERNEL ); -if (!brd->serial_driver->ttys) { - rc = -ENOMEM ; - goto free_serial_drv; - } + p = p->next; + p->type =INTRNODE ; + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.useintr)) { +pr_err ("bad number for useintr" ); +return -1 ; + } +break ; -/* -* Entry points for driver. Called by the kernel from -* tty_io.c and n_tty.c. -*/ -tty_set_operations (brd->serial_driver, &dgap_tty_ops); +case TTSIZ :/* size of tty structure */ +if (dgap_checknode (p)) +return -1 ; -/* -* If we're doing transparent print, we have to do all of the above -* again, separately so we don't get the LD confused about what major -* we are when we get into the dgap_tty_open() routine. -*/ - brd->print_driver =tty_alloc_driver (MAXPORTS ,0 ); -if (IS_ERR (brd->print_driver)) { - rc =PTR_ERR (brd->print_driver); - goto free_serial_drv; - } + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -snprintf (brd->print_name,MAXTTYNAMELEN ,"pr_dgap_%d_" , - brd->boardnum); - brd->print_driver->name = brd->print_name; - brd->print_driver->name_base =0 ; - brd->print_driver->major =0 ; - brd->print_driver->minor_start =0 ; - brd->print_driver->type =TTY_DRIVER_TYPE_SERIAL ; - brd->print_driver->subtype =SERIAL_TYPE_NORMAL ; - brd->print_driver->init_termios = dgap_default_termios; - brd->print_driver->driver_name =DRVSTR ; - brd->print_driver->flags = (TTY_DRIVER_REAL_RAW | -TTY_DRIVER_DYNAMIC_DEV | -TTY_DRIVER_HARDWARE_BREAK ); + p = p->next; + p->type =TSNODE ; -/* The kernel wants space to store pointers to tty_structs */ - brd->print_driver->ttys = -kzalloc (MAXPORTS *sizeof (struct tty_struct *),GFP_KERNEL ); -if (!brd->print_driver->ttys) { - rc = -ENOMEM ; - goto free_print_drv; - } + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.ttysize)) { +pr_err ("bad number for ttysize" ); +return -1 ; + } +break ; -/* -* Entry points for driver. Called by the kernel from -* tty_io.c and n_tty.c. -*/ -tty_set_operations (brd->print_driver, &dgap_tty_ops); +case CHSIZ :/* channel structure size */ +if (dgap_checknode (p)) +return -1 ; -/* Register tty devices */ - rc =tty_register_driver (brd->serial_driver); -if (rc <0 ) - goto free_print_drv; + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -/* Register Transparent Print devices */ - rc =tty_register_driver (brd->print_driver); -if (rc <0 ) - goto unregister_serial_drv; + p = p->next; + p->type =CSNODE ; - dgap_boards_by_major[brd->serial_driver->major] = brd; - brd->dgap_serial_major = brd->serial_driver->major; + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.chsize)) { +pr_err ("bad number for chsize" ); +return -1 ; + } +break ; - dgap_boards_by_major[brd->print_driver->major] = brd; - brd->dgap_transparent_print_major = brd->print_driver->major; +case BSSIZ :/* board structure size */ +if (dgap_checknode (p)) +return -1 ; -return 0 ; + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -unregister_serial_drv: -tty_unregister_driver (brd->serial_driver); -free_print_drv: -put_tty_driver (brd->print_driver); -free_serial_drv: -put_tty_driver (brd->serial_driver); + p = p->next; + p->type =BSNODE ; -return rc; -} + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.bssize)) { +pr_err ("bad number for bssize" ); +return -1 ; + } +break ; -static void dgap_tty_unregister (struct board_t *brd) -{ -tty_unregister_driver (brd->print_driver); -tty_unregister_driver (brd->serial_driver); -put_tty_driver (brd->print_driver); -put_tty_driver (brd->serial_driver); -} +case UNTSIZ :/* sched structure size */ +if (dgap_checknode (p)) +return -1 ; -/* -* dgap_tty_init() -* -* Init the tty subsystem. Called once per board after board has been -* downloaded and init'ed. -*/ -static int dgap_tty_init (struct board_t *brd) -{ -int i; -int tlw; -uint true_count; -u8 __iomem *vaddr; -u8 modem; -struct channel_t *ch; -struct bs_t __iomem *bs; -struct cm_t __iomem *cm; -int ret; + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -/* -* Initialize board structure elements. -*/ + p = p->next; + p->type =USNODE ; - vaddr = brd->re_map_membase; - true_count =readw ((vaddr +NCHAN )); + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.unsize)) { +pr_err ("bad number for schedsize" ); +return -1 ; + } +break ; - brd->nasync =dgap_config_get_num_prts (brd); +case F2SIZ :/* f2200 structure size */ +if (dgap_checknode (p)) +return -1 ; -if (!brd->nasync) - brd->nasync = brd->maxports; + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -if (brd->nasync > brd->maxports) - brd->nasync = brd->maxports; + p = p->next; + p->type =FSNODE ; -if (true_count != brd->nasync) { -dev_warn (&brd->pdev->dev, -"%s configured for %d ports, has %d ports.\n" , - brd->name, brd->nasync, true_count); + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.f2size)) { +pr_err ("bad number for f2200size" ); +return -1 ; + } +break ; -if ((brd->type ==PPCM ) && - (true_count ==64 || true_count ==0 )) { -dev_warn (&brd->pdev->dev, -"Please make SURE the EBI cable running from the card\n" ); -dev_warn (&brd->pdev->dev, -"to each EM module is plugged into EBI IN!\n" ); - } +case VPSIZ :/* vpix structure size */ +if (dgap_checknode (p)) +return -1 ; - brd->nasync = true_count; + p->next =kzalloc (sizeof (struct cnode ),GFP_KERNEL ); +if (!p->next) +return -1 ; -/* If no ports, don't bother going any further */ -if (!brd->nasync) { - brd->state =BOARD_FAILED ; - brd->dpastatus =BD_NOFEP ; -return -EIO ; - } - } + p = p->next; + p->type =VSNODE ; -/* -* Allocate channel memory that might not have been allocated -* when the driver was first loaded. -*/ -for (i =0 ; i < brd->nasync; i++) { - brd->channels[i] = -kzalloc (sizeof (struct channel_t ),GFP_KERNEL ); -if (!brd->channels[i]) { - ret = -ENOMEM ; - goto free_chan; + s =dgap_getword (in); +if (!s) { +pr_err ("unexpected end of file" ); +return -1 ; + } +if (kstrtol (s,0 , &p->u.vpixsize)) { +pr_err ("bad number for vpixsize" ); +return -1 ; + } +break ; } } +} - ch = brd->channels[0 ]; - vaddr = brd->re_map_membase; +static void dgap_cleanup_nodes (void ) +{ +struct cnode *p; - bs = (struct bs_t __iomem *) ((ulong ) vaddr +CHANBUF ); - cm = (struct cm_t __iomem *) ((ulong ) vaddr +CMDBUF ); + p = &dgap_head; - brd->bd_bs = bs; +while (p) { +struct cnode *tmp = p->next; -/* Set up channel variables */ -for (i =0 ; i < brd->nasync; i++, ch = brd->channels[i], bs++) { +if (p->type ==NULLNODE ) { + p = tmp; +continue ; + } -spin_lock_init (&ch->ch_lock); +switch (p->type) { +case BNODE : +kfree (p->u.board.portstr); +kfree (p->u.board.addrstr); +kfree (p->u.board.pcibusstr); +kfree (p->u.board.pcislotstr); +kfree (p->u.board.method); +break ; +case CNODE : +kfree (p->u.conc.id); +kfree (p->u.conc.connect); +break ; +case MNODE : +kfree (p->u.module.id); +break ; +case TNODE : +kfree (p->u.ttyname); +break ; +case CUNODE : +kfree (p->u.cuname); +break ; +case LNODE : +kfree (p->u.line.cable); +break ; +case PNODE : +kfree (p->u.printname); +break ; + } -/* Store all our magic numbers */ - ch->magic =DGAP_CHANNEL_MAGIC ; - ch->ch_tun.magic =DGAP_UNIT_MAGIC ; - ch->ch_tun.un_type =DGAP_SERIAL ; - ch->ch_tun.un_ch = ch; - ch->ch_tun.un_dev = i; +kfree (p->u.board.status); +kfree (p); + p = tmp; + } +} - ch->ch_pun.magic =DGAP_UNIT_MAGIC ; - ch->ch_pun.un_type =DGAP_PRINT ; - ch->ch_pun.un_ch = ch; - ch->ch_pun.un_dev = i; +/* +* Retrives the current custom baud rate from FEP memory, +* and returns it back to the user. +* Returns 0 on error. +*/ +static uint dgap_get_custom_baud (struct channel_t *ch) +{ +u8 __iomem *vaddr; +ulong offset; +uint value; - ch->ch_vaddr = vaddr; - ch->ch_bs = bs; - ch->ch_cm = cm; - ch->ch_bd = brd; - ch->ch_portnum = i; - ch->ch_digi = dgap_digi_init; +if (!ch || ch->magic !=DGAP_CHANNEL_MAGIC ) +return 0 ; -/* -* Set up digi dsr and dcd bits based on altpin flag. -*/ -if (dgap_config_get_altpin (brd)) { - ch->ch_dsr =DM_CD ; - ch->ch_cd =DM_DSR ; - ch->ch_digi.digi_flags |=DIGI_ALTPIN ; - }else { - ch->ch_cd =DM_CD ; - ch->ch_dsr =DM_DSR ; - } +if (!ch->ch_bd || ch->ch_bd->magic !=DGAP_BOARD_MAGIC ) +return 0 ; - ch->ch_taddr = vaddr + (ioread16 (&(ch->ch_bs->tx_seg)) <<4 ); - ch->ch_raddr = vaddr + (ioread16 (&(ch->ch_bs->rx_seg)) <<4 ); - ch->ch_tx_win =0 ; - ch->ch_rx_win =0 ; - ch->ch_tsize =readw (&(ch->ch_bs->tx_max)) +1 ; - ch->ch_rsize =readw (&(ch->ch_bs->rx_max)) +1 ; - ch->ch_tstart =0 ; - ch->ch_rstart =0 ; +if (!(ch->ch_bd->bd_flags &BD_FEP5PLUS )) +return 0 ; -/* -* Set queue water marks, interrupt mask, -* and general tty parameters. -*/ - tlw = ch->ch_tsize >=2000 ? ((ch->ch_tsize *5 ) /8 ) : - ch->ch_tsize /2 ; - ch->ch_tlw = tlw; + vaddr = ch->ch_bd->re_map_membase; -dgap_cmdw (ch,STLOW , tlw,0 ); +if (!vaddr) +return 0 ; -dgap_cmdw (ch,SRLOW , ch->ch_rsize /2 ,0 ); +/* +* Go get from fep mem, what the fep +* believes the custom baud rate is. +*/ + offset = (ioread16 (vaddr +ECS_SEG ) <<4 ) + (ch->ch_portnum *0x28 ) + +LINE_SPEED ; -dgap_cmdw (ch,SRHIGH ,7 * ch->ch_rsize /8 ,0 ); + value =readw (vaddr + offset); +return value; +} - ch->ch_mistat =readb (&(ch->ch_bs->m_stat)); +/* +* Remap PCI memory. +*/ +static int dgap_remap (struct board_t *brd) +{ +if (!brd || brd->magic !=DGAP_BOARD_MAGIC ) +return -EIO ; -init_waitqueue_head (&ch->ch_flags_wait); -init_waitqueue_head (&ch->ch_tun.un_flags_wait); -init_waitqueue_head (&ch->ch_pun.un_flags_wait); +if (!request_mem_region (brd->membase,0x200000 ,"dgap" )) +return -ENOMEM ; -/* Turn on all modem interrupts for now */ - modem = (DM_CD |DM_DSR |DM_CTS |DM_RI ); -writeb (modem, &(ch->ch_bs->m_int)); +if (!request_mem_region (brd->membase +PCI_IO_OFFSET ,0x200000 , +"dgap" )) { +release_mem_region (brd->membase,0x200000 ); +return -ENOMEM ; + } -/* -* Set edelay to 0 if interrupts are turned on, -* otherwise set edelay to the usual 100. -*/ -if (brd->intr_used) -writew (0 , &(ch->ch_bs->edelay)); -else -writew (100 , &(ch->ch_bs->edelay)); + brd->re_map_membase =ioremap (brd->membase,0x200000 ); +if (!brd->re_map_membase) { +release_mem_region (brd->membase,0x200000 ); +release_mem_region (brd->membase +PCI_IO_OFFSET ,0x200000 ); +return -ENOMEM ; + } -writeb (1 , &(ch->ch_bs->idata)); + brd->re_map_port =ioremap ((brd->membase +PCI_IO_OFFSET ),0x200000 ); +if (!brd->re_map_port) { +release_mem_region (brd->membase,0x200000 ); +release_mem_region (brd->membase +PCI_IO_OFFSET ,0x200000 ); +iounmap (brd->re_map_membase); +return -ENOMEM ; }return 0 ; - -free_chan: -while (--i >=0 ) { -kfree (brd->channels[i]); - brd->channels[i] =NULL ; - } -return ret; } -/* -* dgap_tty_free() -* -* Free the channles which are allocated in dgap_tty_init(). -*/ -static void dgap_tty_free (struct board_t *brd) +static void dgap_unmap (struct board_t *brd) { -int i; - -for (i =0 ; i < brd->nasync; i++) -kfree (brd->channels[i]); +iounmap (brd->re_map_port); +iounmap (brd->re_map_membase); +release_mem_region (brd->membase +PCI_IO_OFFSET ,0x200000 ); +release_mem_region (brd->membase,0x200000 ); } +/* -* dgap_cleanup_tty() +* dgap_parity_scan() * -* Uninitialize the TTY portion of this driver. Free all memory and -* resources. +* Convert the FEP5 way of reporting parity errors and breaks into +* the Linux line discipline way. */ -static void dgap_cleanup_tty (struct board_t *brd) +static void dgap_parity_scan (struct channel_t *ch,unsigned char *cbuf, +unsigned char *fbuf,int *len) { -struct device *dev; -int i; +int l = *len; +int count =0 ; +unsigned char *in, *cout, *fout; +unsigned char c; - dgap_boards_by_major[brd->serial_driver->major] =NULL ; - brd->dgap_serial_major =0 ; -for (i =0 ; i < brd->nasync; i++) { -tty_port_destroy (&brd->serial_ports[i]); - dev = brd->channels[i]->ch_tun.un_sysfs; -dgap_remove_tty_sysfs (dev); -tty_unregister_device (brd->serial_driver, i); - } -tty_unregister_driver (brd->serial_driver); -put_tty_driver (brd->serial_driver); -kfree (brd->serial_ports); + in = cbuf; + cout = cbuf; + fout = fbuf; - dgap_boards_by_major[brd->print_driver->major] =NULL ; - brd->dgap_transparent_print_major =0 ; -for (i =0 ; i < brd->nasync; i++) { -tty_port_destroy (&brd->printer_ports[i]); - dev = brd->channels[i]->ch_pun.un_sysfs; -dgap_remove_tty_sysfs (dev); -tty_unregister_device (brd->print_driver, i); +if (!ch || ch->magic !=DGAP_CHANNEL_MAGIC ) +return ; + +while (l--) { + c = *in++; +switch (ch->pscan_state) { +default : +/* reset to sanity and fall through */ + ch->pscan_state =0 ; + +case 0 : +/* No FF seen yet */ +if (c == (unsigned char )'\377' ) +/* delete this character from stream */ + ch->pscan_state =1 ; +else { + *cout++ = c; + *fout++ =TTY_NORMAL ; + count +=1 ; + } +break ; + +case 1 : +/* first FF seen */ +if (c == (unsigned char )'\377' ) { +/* doubled ff, transform to single ff */ + *cout++ = c; + *fout++ =TTY_NORMAL ; + count +=1 ; + ch->pscan_state =0 ; + }else { +/* save value examination in next state */ + ch->pscan_savechar = c; + ch->pscan_state =2 ; + } +break ; + +case 2 : +/* third character of ff sequence */ + + *cout++ = c; + +if (ch->pscan_savechar ==0x0 ) { + +if (c ==0x0 ) { + ch->ch_err_break++; + *fout++ =TTY_BREAK ; + }else { + ch->ch_err_parity++; + *fout++ =TTY_PARITY ; + } + } + + count +=1 ; + ch->pscan_state =0 ; + } } -tty_unregister_driver (brd->print_driver); -put_tty_driver (brd->print_driver); -kfree (brd->printer_ports); + *len = count; }/*=======================================================================
@@ -1750,6 +1718,33 @@ static void dgap_input(struct channel_t *ch) } +static void dgap_write_wakeup (struct board_t *bd,struct channel_t *ch, +struct un_t *un,u32 mask, +unsigned long *irq_flags1, +unsigned long *irq_flags2) +{ +if (!(un->un_flags & mask)) +return ; + + un->un_flags &= ~mask; + +if (!(un->un_flags &UN_ISOPEN )) +return ; + +if ((un->un_tty->flags & (1 <<TTY_DO_WRITE_WAKEUP )) && + un->un_tty->ldisc->ops->write_wakeup) { +spin_unlock_irqrestore (&ch->ch_lock, *irq_flags2); +spin_unlock_irqrestore (&bd->bd_lock, *irq_flags1); + + (un->un_tty->ldisc->ops->write_wakeup)(un->un_tty); + +spin_lock_irqsave (&bd->bd_lock, *irq_flags1); +spin_lock_irqsave (&ch->ch_lock, *irq_flags2); + } +wake_up_interruptible (&un->un_tty->write_wait); +wake_up_interruptible (&un->un_flags_wait); +} +/************************************************************************ * Determines when CARRIER changes state and takes appropriate * action.
@@ -1864,163 +1859,1207 @@ static void dgap_carrier(struct channel_t *ch) ch->ch_flags &= ~CH_CD ; } -/************************************************************************ +/*======================================================================= * -* TTY Entry points and helper functions +* dgap_event - FEP to host event processing routine. * -************************************************************************/ - -/* -* dgap_tty_open() +* bd - Board of current event. * -*/ -static int dgap_tty_open (struct tty_struct *tty,struct file *file) +*=======================================================================*/ +static int dgap_event (struct board_t *bd) { -struct board_t *brd;struct channel_t *ch; -struct un_t *un; -struct bs_t __iomem *bs; -uint major; -uint minor; -int rc;ulong lock_flags;ulong lock_flags2; -u16 head; +struct bs_t __iomem *bs; +u8 __iomem *event; +u8 __iomem *vaddr; +struct ev_t __iomem *eaddr; +uint head; +uint tail; +int port; +int reason; +int modem; +int b1; - major =MAJOR (tty_devnum (tty)); - minor =MINOR (tty_devnum (tty)); +if (!bd || bd->magic !=DGAP_BOARD_MAGIC ) +return -EIO ; -if (major >255 ) +spin_lock_irqsave (&bd->bd_lock, lock_flags); + + vaddr = bd->re_map_membase; + +if (!vaddr) { +spin_unlock_irqrestore (&bd->bd_lock, lock_flags);return -EIO ; + } -/* Get board pointer from our array of majors we have allocated */ - brd = dgap_boards_by_major[major]; -if (!brd) + eaddr = (struct ev_t __iomem *) (vaddr +EVBUF ); + +/* Get our head and tail */ + head =readw (&(eaddr->ev_head)); + tail =readw (&(eaddr->ev_tail)); + +/* +* Forget it if pointers out of range. +*/ + +if (head >=EVMAX -EVSTART || tail >=EVMAX -EVSTART || + (head | tail) &03 ) { +/* Let go of board lock */ +spin_unlock_irqrestore (&bd->bd_lock, lock_flags);return -EIO ; + }/* -* If board is not yet up to a state of READY, go to -* sleep waiting for it to happen or they cancel the open. +* Loop to process all the events in the buffer. */ - rc =wait_event_interruptible (brd->state_wait, - (brd->state &BOARD_READY )); +while (tail != head) { -if (rc) -return rc; +/* +* Get interrupt information. +*/ -spin_lock_irqsave (&brd->bd_lock, lock_flags); + event = bd->re_map_membase + tail +EVSTART ; -/* The wait above should guarantee this cannot happen */ -if (brd->state !=BOARD_READY ) { -spin_unlock_irqrestore (&brd->bd_lock, lock_flags); -return -EIO ; + port =ioread8 (event); + reason =ioread8 (event +1 ); + modem =ioread8 (event +2 ); + b1 =ioread8 (event +3 ); + +/* +* Make sure the interrupt is valid. +*/ +if (port >= bd->nasync) + goto next; + +if (!(reason & (IFMODEM |IFBREAK |IFTLW |IFTEM |IFDATA ))) + goto next; + + ch = bd->channels[port]; + +if (!ch || ch->magic !=DGAP_CHANNEL_MAGIC ) + goto next; + +/* +* If we have made it here, the event was valid. +* Lock down the channel. +*/ +spin_lock_irqsave (&ch->ch_lock, lock_flags2); + + bs = ch->ch_bs; + +if (!bs) { +spin_unlock_irqrestore (&ch->ch_lock, lock_flags2); + goto next; + } + +/* +* Process received data. +*/ +if (reason &IFDATA ) { + +/* +* ALL LOCKS *MUST* BE DROPPED BEFORE CALLING INPUT! +* input could send some data to ld, which in turn +* could do a callback to one of our other functions. +*/ +spin_unlock_irqrestore (&ch->ch_lock, lock_flags2); +spin_unlock_irqrestore (&bd->bd_lock, lock_flags); + +dgap_input (ch); + +spin_lock_irqsave (&bd->bd_lock, lock_flags); +spin_lock_irqsave (&ch->ch_lock, lock_flags2); + +if (ch->ch_flags &CH_RACTIVE ) + ch->ch_flags |=CH_RENABLE ; +else +writeb (1 , &(bs->idata)); + +if (ch->ch_flags &CH_RWAIT ) { + ch->ch_flags &= ~CH_RWAIT ; + +wake_up_interruptible + (&ch->ch_tun.un_flags_wait); + } + } + +/* +* Process Modem change signals. +*/ +if (reason &IFMODEM ) { + ch->ch_mistat = modem; +dgap_carrier (ch); + } + +/* +* Process break. +*/ +if (reason &IFBREAK ) { + +if (ch->ch_tun.un_tty) { +/* A break has been indicated */ + ch->ch_err_break++; +tty_buffer_request_room + (ch->ch_tun.un_tty->port,1 ); +tty_insert_flip_char (ch->ch_tun.un_tty->port, +0 ,TTY_BREAK ); +tty_flip_buffer_push (ch->ch_tun.un_tty->port); + } + } + +/* +* Process Transmit low. +*/ +if (reason &IFTLW ) { +dgap_write_wakeup (bd, ch, &ch->ch_tun,UN_LOW , + &lock_flags, &lock_flags2); +dgap_write_wakeup (bd, ch, &ch->ch_pun,UN_LOW , + &lock_flags, &lock_flags2); +if (ch->ch_flags &CH_WLOW ) { + ch->ch_flags &= ~CH_WLOW ; +wake_up_interruptible (&ch->ch_flags_wait); + } + } + +/* +* Process Transmit empty. +*/ +if (reason &IFTEM ) { +dgap_write_wakeup (bd, ch, &ch->ch_tun,UN_EMPTY , + &lock_flags, &lock_flags2); +dgap_write_wakeup (bd, ch, &ch->ch_pun,UN_EMPTY , + &lock_flags, &lock_flags2); +if (ch->ch_flags &CH_WEMPTY ) { + ch->ch_flags &= ~CH_WEMPTY ; +wake_up_interruptible (&ch->ch_flags_wait); + } + } + +spin_unlock_irqrestore (&ch->ch_lock, lock_flags2); + +next: + tail = (tail +4 ) & (EVMAX -EVSTART -4 ); } -/* If opened device is greater than our number of ports, bail. */ -if (MINOR (tty_devnum (tty)) > brd->nasync) { -spin_unlock_irqrestore (&brd->bd_lock, lock_flags); -return -EIO ; +writew (tail, &(eaddr->ev_tail)); +spin_unlock_irqrestore (&bd->bd_lock, lock_flags); + +return 0 ; +} + +/* +* Our board poller function. +*/ +static void dgap_poll_tasklet (unsigned long data) +{ +struct board_t *bd = (struct board_t *) data; +ulong lock_flags; +char __iomem *vaddr; +u16 head, tail; + +if (!bd || (bd->magic !=DGAP_BOARD_MAGIC )) +return ; + +if (bd->inhibit_poller) +return ; + +spin_lock_irqsave (&bd->bd_lock, lock_flags); + + vaddr = bd->re_map_membase; + +/* +* If board is ready, parse deeper to see if there is anything to do. +*/ +if (bd->state ==BOARD_READY ) { + +struct ev_t __iomem *eaddr; + +if (!bd->re_map_membase) { +spin_unlock_irqrestore (&bd->bd_lock, lock_flags); +return ; + } +if (!bd->re_map_port) { +spin_unlock_irqrestore (&bd->bd_lock, lock_flags); +return ; + } + +if (!bd->nasync) + goto out; + + eaddr = (struct ev_t __iomem *) (vaddr +EVBUF ); + +/* Get our head and tail */ + head =readw (&(eaddr->ev_head)); + tail =readw (&(eaddr->ev_tail)); + +/* +* If there is an event pending. Go service it. +*/ +if (head != tail) { +spin_unlock_irqrestore (&bd->bd_lock, lock_flags); +dgap_event (bd); +spin_lock_irqsave (&bd->bd_lock, lock_flags); + } + +out: +/* +* If board is doing interrupts, ACK the interrupt. +*/ +if (bd && bd->intr_running) +readb (bd->re_map_port +2 ); + +spin_unlock_irqrestore (&bd->bd_lock, lock_flags); +return ; } - ch = brd->channels[minor]; -if (!ch) { -spin_unlock_irqrestore (&brd->bd_lock, lock_flags); -return -EIO ; +spin_unlock_irqrestore (&bd->bd_lock, lock_flags); +} + +/* +* dgap_found_board() +* +* A board has been found, init it. +*/ +static struct board_t *dgap_found_board (struct pci_dev *pdev,int id, +int boardnum) +{ +struct board_t *brd; +unsigned int pci_irq; +int i; +int ret; + +/* get the board structure and prep it */ + brd =kzalloc (sizeof (struct board_t ),GFP_KERNEL ); +if (!brd) +return ERR_PTR (-ENOMEM ); + +/* store the info for the board we've found */ + brd->magic =DGAP_BOARD_MAGIC ; + brd->boardnum = boardnum; + brd->vendor = dgap_pci_tbl[id].vendor; + brd->device = dgap_pci_tbl[id].device; + brd->pdev = pdev; + brd->pci_bus = pdev->bus->number; + brd->pci_slot =PCI_SLOT (pdev->devfn); + brd->name = dgap_ids[id].name; + brd->maxports = dgap_ids[id].maxports; + brd->type = dgap_ids[id].config_type; + brd->dpatype = dgap_ids[id].dpatype; + brd->dpastatus =BD_NOFEP ; +init_waitqueue_head (&brd->state_wait); + +spin_lock_init (&brd->bd_lock); + + brd->inhibit_poller = FALSE; + brd->wait_for_bios =0 ; + brd->wait_for_fep =0 ; + +for (i =0 ; i <MAXPORTS ; i++) + brd->channels[i] =NULL ; + +/* store which card & revision we have */ +pci_read_config_word (pdev,PCI_SUBSYSTEM_VENDOR_ID , &brd->subvendor); +pci_read_config_word (pdev,PCI_SUBSYSTEM_ID , &brd->subdevice); +pci_read_config_byte (pdev,PCI_REVISION_ID , &brd->rev); + + pci_irq = pdev->irq; + brd->irq = pci_irq; + +/* get the PCI Base Address Registers */ + +/* Xr Jupiter and EPC use BAR 2 */ +if (brd->device ==PCI_DEV_XRJ_DID || brd->device ==PCI_DEV_EPCJ_DID ) { + brd->membase =pci_resource_start (pdev,2 ); + brd->membase_end =pci_resource_end (pdev,2 ); + } +/* Everyone else uses BAR 0 */ +else { + brd->membase =pci_resource_start (pdev,0 ); + brd->membase_end =pci_resource_end (pdev,0 ); } -/* Grab channel lock */ -spin_lock_irqsave (&ch->ch_lock, lock_flags2); +if (!brd->membase) { + ret = -ENODEV ; + goto free_brd; + } -/* Figure out our type */ -if (major == brd->dgap_serial_major) { - un = &brd->channels[minor]->ch_tun; - un->un_type =DGAP_SERIAL ; - }else if (major == brd->dgap_transparent_print_major) { - un = &brd->channels[minor]->ch_pun; - un->un_type =DGAP_PRINT ; +if (brd->membase &1 ) + brd->membase &= ~3 ; +else + brd->membase &= ~15 ; + +/* +* On the PCI boards, there is no IO space allocated +* The I/O registers will be in the first 3 bytes of the +* upper 2MB of the 4MB memory space. The board memory +* will be mapped into the low 2MB of the 4MB memory space +*/ + brd->port = brd->membase +PCI_IO_OFFSET ; + brd->port_end = brd->port +PCI_IO_SIZE ; + +/* +* Special initialization for non-PLX boards +*/ +if (brd->device !=PCI_DEV_XRJ_DID && brd->device !=PCI_DEV_EPCJ_DID ) { +unsigned short cmd; + +pci_write_config_byte (pdev,0x40 ,0 ); +pci_write_config_byte (pdev,0x46 ,0 ); + +/* Limit burst length to 2 doubleword transactions */ +pci_write_config_byte (pdev,0x42 ,1 ); + +/* +* Enable IO and mem if not already done. +* This was needed for support on Itanium. +*/ +pci_read_config_word (pdev,PCI_COMMAND , &cmd); + cmd |= (PCI_COMMAND_IO |PCI_COMMAND_MEMORY ); +pci_write_config_word (pdev,PCI_COMMAND , cmd); + } + +/* init our poll helper tasklet */ +tasklet_init (&brd->helper_tasklet, dgap_poll_tasklet, + (unsigned long ) brd); + + ret =dgap_remap (brd); +if (ret) + goto free_brd; + +pr_info ("dgap: board %d: %s (rev %d), irq %ld\n" , + boardnum, brd->name, brd->rev, brd->irq); + +return brd; + +free_brd: +kfree (brd); + +return ERR_PTR (ret); +} + +/* +* dgap_intr() +* +* Driver interrupt handler. +*/ +static irqreturn_t dgap_intr (int irq,void *voidbrd) +{ +struct board_t *brd = (struct board_t *) voidbrd; + +if (!brd) +return IRQ_NONE ; + +/* +* Check to make sure its for us. +*/ +if (brd->magic !=DGAP_BOARD_MAGIC ) +return IRQ_NONE ; + + brd->intr_count++; + +/* +* Schedule tasklet to run at a better time. +*/ +tasklet_schedule (&brd->helper_tasklet); +return IRQ_HANDLED ; +} + +/***************************************************************************** +* +* Function: +* +* dgap_poll_handler +* +* Author: +* +* Scott H Kilau +* +* Parameters: +* +* dummy -- ignored +* +* Return Values: +* +* none +* +* Description: +* +* As each timer expires, it determines (a) whether the "transmit" +* waiter needs to be woken up, and (b) whether the poller needs to +* be rescheduled. +* +******************************************************************************/ + +static void dgap_poll_handler (ulong dummy) +{ +int i; +struct board_t *brd; +unsigned long lock_flags; +ulong new_time; + + dgap_poll_counter++; + +/* +* Do not start the board state machine until +* driver tells us its up and running, and has +* everything it needs. +*/ +if (dgap_driver_state !=DRIVER_READY ) + goto schedule_poller; + +/* +* If we have just 1 board, or the system is not SMP, +* then use the typical old style poller. +* Otherwise, use our new tasklet based poller, which should +* speed things up for multiple boards. +*/ +if ((dgap_numboards ==1 ) || (num_online_cpus () <=1 )) { +for (i =0 ; i < dgap_numboards; i++) { + + brd = dgap_board[i]; + +if (brd->state ==BOARD_FAILED ) +continue ; +if (!brd->intr_running) +/* Call the real board poller directly */ +dgap_poll_tasklet ((unsigned long ) brd); + } }else { -spin_unlock_irqrestore (&ch->ch_lock, lock_flags2); -spin_unlock_irqrestore (&brd->bd_lock, lock_flags); -return -EIO ; +/* +* Go thru each board, kicking off a +* tasklet for each if needed +*/ +for (i =0 ; i < dgap_numboards; i++) { + brd = dgap_board[i]; + +/* +* Attempt to grab the board lock. +* +* If we can't get it, no big deal, the next poll +* will get it. Basically, I just really don't want +* to spin in here, because I want to kick off my +* tasklets as fast as I can, and then get out the +* poller. +*/ +if (!spin_trylock (&brd->bd_lock)) +continue ; + +/* +* If board is in a failed state, don't bother +* scheduling a tasklet +*/ +if (brd->state ==BOARD_FAILED ) { +spin_unlock (&brd->bd_lock); +continue ; + } + +/* Schedule a poll helper task */ +if (!brd->intr_running) +tasklet_schedule (&brd->helper_tasklet); + +/* +* Can't do DGAP_UNLOCK here, as we don't have +* lock_flags because we did a trylock above. +*/ +spin_unlock (&brd->bd_lock); + } } -/* Store our unit into driver_data, so we always have it available. */ - tty->driver_data = un; +schedule_poller:/* -* Error if channel info pointer is NULL. +* Schedule ourself back at the nominal wakeup interval. */ - bs = ch->ch_bs; -if (!bs) { -spin_unlock_irqrestore (&ch->ch_lock, lock_flags2); -spin_unlock_irqrestore (&brd->bd_lock, lock_flags); -return -EIO ; +spin_lock_irqsave (&dgap_poll_lock, lock_flags); + dgap_poll_time +=dgap_jiffies_from_ms (dgap_poll_tick); + + new_time = dgap_poll_time - jiffies; + +if ((ulong ) new_time >=2 * dgap_poll_tick) { + dgap_poll_time = + jiffies +dgap_jiffies_from_ms (dgap_poll_tick); } + dgap_poll_timer.function = dgap_poll_handler; + dgap_poll_timer.data =0 ; + dgap_poll_timer.expires = dgap_poll_time; +spin_unlock_irqrestore (&dgap_poll_lock, lock_flags); + +if (!dgap_poll_stop) +add_timer (&dgap_poll_timer); +} + +/*======================================================================= +* +* dgap_cmdb - Sends a 2 byte command to the FEP. +* +* ch - Pointer to channel structure. +* cmd - Command to be sent. +* byte1 - Integer containing first byte to be sent. +* byte2 - Integer containing second byte to be sent. +* ncmds - Wait until ncmds or fewer cmds are left +* in the cmd buffer before returning. +* +*=======================================================================*/ +static void dgap_cmdb (struct channel_t *ch,u8 cmd,u8 byte1, +u8 byte2,uint ncmds) +{ +char __iomem *vaddr; +struct __iomem cm_t *cm_addr; +uint count; +uint n; +u16 head; +u16 tail; + +if (!ch || ch->magic !=DGAP_CHANNEL_MAGIC ) +return ; +/* -* Initialize tty's +* Check if board is still alive. */ -if (!(un->un_flags &UN_ISOPEN )) { -/* Store important variables. */ - un->un_tty = tty; +if (ch->ch_bd->state ==BOARD_FAILED ) +return ; -/* Maybe do something here to the TTY struct as well? */ +/* +* Make sure the pointers are in range before +* writing to the FEP memory. +*/ + vaddr = ch->ch_bd->re_map_membase; + +if (!vaddr) +return ; + + cm_addr = (struct cm_t __iomem *) (vaddr +CMDBUF ); + head =readw (&(cm_addr->cm_head)); + +/* +* Forget it if pointers out of range. +*/ +if (head >= (CMDMAX -CMDSTART ) || (head &03 )) { + ch->ch_bd->state =BOARD_FAILED ; +return ; }/* -* Initialize if neither terminal or printer is open. +* Put the data in the circular command buffer. */ -if (!((ch->ch_tun.un_flags | ch->ch_pun.un_flags) &UN_ISOPEN )) { +writeb (cmd, (vaddr + head +CMDSTART +0 )); +writeb ((u8 ) ch->ch_portnum, (vaddr + head +CMDSTART +1 )); +writeb (byte1, (vaddr + head +CMDSTART +2 )); +writeb (byte2, (vaddr + head +CMDSTART +3 )); - ch->ch_mforce =0 ; - ch->ch_mval =0 ; + head = (head +4 ) & (CMDMAX -CMDSTART -4 ); + +writew (head, &(cm_addr->cm_head)); + +/* +* Wait if necessary before updating the head +* pointer to limit the number of outstanding +* commands to the FEP. If the time spent waiting +* is outlandish, declare the FEP dead. +*/
Lines of this file are not shown. View the raw message.
The rest of this diff is not shown. View the raw message.
Signature · 1 line
1.7.1
Part of the diff is not shown here. View the raw message.
Greg KH
maintainerQuoted 7 lines · Daeseok Youn
Re-arrange the functions for removing forward declarations.
Tested-by Mark Hounschell <[email protected]>Signed-off-by Daeseok Youn <[email protected]>---
RESEND: This patch is tested all by Mark.
It is good to merge. Greg, check please.
It doesn't apply to my tree :(
Hi,
2014-10-29 18:22 GMT+09:00 Greg KH <[email protected]>:
Quoted 10 lines · Daeseok Youn
Quoted 7 lines
Re-arrange the functions for removing forward declarations.
Tested-by Mark Hounschell <[email protected]>Signed-off-by Daeseok Youn <[email protected]>---
RESEND: This patch is tested all by Mark.
It is good to merge. Greg, check please.It doesn't apply to my tree :(
Yes, it need to rebase as Mark's comment.
I will send this again after rebase.
Thanks.
Daeseok Youn.
A message that is not in the archive (sent off-list or not yet received): [email protected]
Quoted 12 lines · Greg KH
Quoted 7 lines · Daeseok Youn
Re-arrange the functions for removing forward declarations.
Tested-by Mark Hounschell <[email protected]>Signed-off-by Daeseok Youn <[email protected]>---
RESEND: This patch is tested all by Mark.
It is good to merge. Greg, check please.It doesn't apply to my tree :(
Daeseok,
I will be happy to test the new patch. Somehow another patch got in there without us seeing it "commit: ac2f46c365e655dd2c366f69c609febc4ac310fd" on the list. That's why it doesn't apply for Greg.
Regards
Mark