From dd025c0c7a047b1be7dfaa4061368b4783d89ebb Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 8 May 2007 00:37:02 -0700 Subject: [PATCH] Char: cyclades, dynamic ports and save thus approx. 160k of .bss Signed-off-by: Jiri Slaby Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/cyclades.c | 138 +++++++++++++++++++-------------------- include/linux/cyclades.h | 1 + 2 files changed, 68 insertions(+), 71 deletions(-) diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index c6a12bad70f5..7fe4bb60f690 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -722,11 +722,6 @@ module_param_array(irq, int, NULL, 0); */ static struct cyclades_card cy_card[NR_CARDS]; -/* This is the per-channel data structure containing pointers, flags - and variables for the port. This driver supports a maximum of NR_PORTS. -*/ -static struct cyclades_port cy_port[NR_PORTS]; - static int cy_next_channel; /* next minor available */ /* @@ -855,13 +850,6 @@ static inline int serial_paranoia_check(struct cyclades_port *info, return 1; } - if ((long)info < (long)(&cy_port[0]) || - (long)(&cy_port[NR_PORTS]) < (long)info) { - printk(KERN_WARNING "cyc Warning: cyclades_port out of range " - "for (%s) in %s\n", name, routine); - return 1; - } - if (info->magic != CYCLADES_MAGIC) { printk(KERN_WARNING "cyc Warning: bad magic number for serial " "struct (%s) in %s\n", name, routine); @@ -1025,7 +1013,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, struct cyclades_port *info; struct tty_struct *tty; int char_count; - int i, j, len, mdm_change, mdm_status, outch; + int j, len, mdm_change, mdm_status, outch; int save_xir, channel, save_car; char data; @@ -1037,8 +1025,7 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, spin_lock(&cinfo->card_lock); save_xir = (u_char) readb(base_addr + (CyRIR << index)); channel = (u_short) (save_xir & CyIRChannel); - i = channel + chip * 4 + cinfo->first_line; - info = &cy_port[i]; + info = &cinfo->ports[channel + chip * 4]; save_car = readb(base_addr + (CyCAR << index)); cy_writeb(base_addr + (CyCAR << index), save_xir); @@ -1202,18 +1189,17 @@ static void cyy_intr_chip(struct cyclades_card *cinfo, int chip, spin_lock(&cinfo->card_lock); save_xir = (u_char) readb(base_addr + (CyTIR << index)); channel = (u_short) (save_xir & CyIRChannel); - i = channel + chip * 4 + cinfo->first_line; save_car = readb(base_addr + (CyCAR << index)); cy_writeb(base_addr + (CyCAR << index), save_xir); /* validate the port# (as configured and open) */ - if ((i < 0) || (NR_PORTS <= i)) { + if (channel + chip * 4 >= cinfo->nports) { cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) & ~CyTxRdy); goto txend; } - info = &cy_port[i]; + info = &cinfo->ports[channel + chip * 4]; if (info->tty == NULL) { cy_writeb(base_addr + (CySRER << index), readb(base_addr + (CySRER << index)) & @@ -1325,7 +1311,7 @@ txend: spin_lock(&cinfo->card_lock); save_xir = (u_char) readb(base_addr + (CyMIR << index)); channel = (u_short) (save_xir & CyIRChannel); - info = &cy_port[channel + chip * 4 + cinfo->first_line]; + info = &cinfo->ports[channel + chip * 4]; save_car = readb(base_addr + (CyCAR << index)); cy_writeb(base_addr + (CyCAR << index), save_xir); @@ -1726,7 +1712,7 @@ static void cyz_handle_cmd(struct cyclades_card *cinfo) while (cyz_fetch_msg(cinfo, &channel, &cmd, ¶m) == 1) { special_count = 0; delta_count = 0; - info = &cy_port[channel + cinfo->first_line]; + info = &cinfo->ports[channel]; if ((tty = info->tty) == NULL) continue; @@ -1896,7 +1882,7 @@ static void cyz_poll(unsigned long arg) cyz_handle_cmd(cinfo); for (port = 0; port < cinfo->nports; port++) { - info = &cy_port[port + cinfo->first_line]; + info = &cinfo->ports[port]; tty = info->tty; ch_ctrl = &(zfw_ctrl->ch_ctrl[port]); buf_ctrl = &(zfw_ctrl->buf_ctrl[port]); @@ -2468,13 +2454,20 @@ block_til_ready(struct tty_struct *tty, struct file *filp, static int cy_open(struct tty_struct *tty, struct file *filp) { struct cyclades_port *info; + unsigned int i; int retval, line; line = tty->index; if ((line < 0) || (NR_PORTS <= line)) { return -ENODEV; } - info = &cy_port[line]; + for (i = 0; i < NR_CARDS; i++) + if (line < cy_card[i].first_line + cy_card[i].nports && + line >= cy_card[i].first_line) + break; + if (i >= NR_CARDS) + return -ENODEV; + info = &cy_card[i].ports[line - cy_card[i].first_line]; if (info->line < 0) { return -ENODEV; } @@ -4437,7 +4430,7 @@ static void cy_hangup(struct tty_struct *tty) * --------------------------------------------------------------------- */ -static void __devinit cy_init_card(struct cyclades_card *cinfo) +static int __devinit cy_init_card(struct cyclades_card *cinfo) { struct cyclades_port *info; u32 mailbox; @@ -4459,10 +4452,15 @@ static void __devinit cy_init_card(struct cyclades_card *cinfo) nports = cinfo->nports = CyPORTS_PER_CHIP * cinfo->num_chips; } + cinfo->ports = kzalloc(sizeof(*cinfo->ports) * nports, GFP_KERNEL); + if (cinfo->ports == NULL) { + printk(KERN_ERR "Cyclades: cannot allocate ports\n"); + return -ENOMEM; + } + for (port = cinfo->first_line; port < cinfo->first_line + nports; port++) { - info = &cy_port[port]; - memset(info, 0, sizeof(*info)); + info = &cinfo->ports[port - cinfo->first_line]; info->magic = CYCLADES_MAGIC; info->card = cinfo; info->line = port; @@ -4525,6 +4523,7 @@ static void __devinit cy_init_card(struct cyclades_card *cinfo) #endif } #endif + return 0; } /* initialize chips on Cyclom-Y card -- return number of valid @@ -5094,13 +5093,11 @@ static void __devexit cy_pci_remove(struct pci_dev *pdev) pci_release_regions(pdev); cinfo->base_addr = NULL; - for (i = cinfo->first_line; i < cinfo->first_line + cinfo->nports; i++){ - cy_port[i].line = -1; - cy_port[i].magic = -1; - } for (i = cinfo->first_line; i < cinfo->first_line + cinfo->nports; i++) tty_unregister_device(cy_serial_driver, i); + cinfo->nports = 0; + kfree(cinfo->ports); } static struct pci_driver cy_pci_driver = { @@ -5116,7 +5113,7 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, int *eof, void *data) { struct cyclades_port *info; - int i; + unsigned int i, j; int len = 0; off_t begin = 0; off_t pos = 0; @@ -5130,33 +5127,34 @@ cyclades_get_proc_info(char *buf, char **start, off_t offset, int length, len += size; /* Output one line for each known port */ - for (i = 0; i < NR_PORTS && cy_port[i].line >= 0; i++) { - info = &cy_port[i]; + for (i = 0; i < NR_CARDS; i++) + for (j = 0; j < cy_card[i].nports; j++) { + info = &cy_card[i].ports[j]; - if (info->count) - size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu " - "%8lu %9lu %6ld\n", info->line, - (cur_jifs - info->idle_stats.in_use) / HZ, - info->idle_stats.xmit_bytes, - (cur_jifs - info->idle_stats.xmit_idle) / HZ, - info->idle_stats.recv_bytes, - (cur_jifs - info->idle_stats.recv_idle) / HZ, - info->idle_stats.overruns, - (long)info->tty->ldisc.num); - else - size = sprintf(buf + len, "%3d %8lu %10lu %8lu %10lu " - "%8lu %9lu %6ld\n", - info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); - len += size; - pos = begin + len; + if (info->count) + size = sprintf(buf + len, "%3d %8lu %10lu %8lu " + "%10lu %8lu %9lu %6ld\n", info->line, + (cur_jifs - info->idle_stats.in_use) / + HZ, info->idle_stats.xmit_bytes, + (cur_jifs - info->idle_stats.xmit_idle)/ + HZ, info->idle_stats.recv_bytes, + (cur_jifs - info->idle_stats.recv_idle)/ + HZ, info->idle_stats.overruns, + (long)info->tty->ldisc.num); + else + size = sprintf(buf + len, "%3d %8lu %10lu %8lu " + "%10lu %8lu %9lu %6ld\n", + info->line, 0L, 0L, 0L, 0L, 0L, 0L, 0L); + len += size; + pos = begin + len; - if (pos < offset) { - len = 0; - begin = pos; + if (pos < offset) { + len = 0; + begin = pos; + } + if (pos > offset + length) + goto done; } - if (pos > offset + length) - goto done; - } *eof = 1; done: *start = buf + (offset - begin); /* Start of wanted data */ @@ -5211,7 +5209,7 @@ static const struct tty_operations cy_ops = { static int __init cy_init(void) { - unsigned int i, nboards; + unsigned int nboards; int retval = -ENOMEM; cy_serial_driver = alloc_tty_driver(NR_PORTS); @@ -5242,11 +5240,6 @@ static int __init cy_init(void) goto err_frtty; } - for (i = 0; i < NR_PORTS; i++) { - cy_port[i].line = -1; - cy_port[i].magic = -1; - } - /* the code below is responsible to find the boards. Each different type of board has its own detection routine. If a board is found, the next cy_card structure available is set by the detection @@ -5275,6 +5268,7 @@ err: static void __exit cy_cleanup_module(void) { + struct cyclades_card *card; int i, e1; #ifndef CONFIG_CYZ_INTR @@ -5290,22 +5284,24 @@ static void __exit cy_cleanup_module(void) #endif for (i = 0; i < NR_CARDS; i++) { - if (cy_card[i].base_addr) { + card = &cy_card[i]; + if (card->base_addr) { /* clear interrupt */ - cy_writeb(cy_card[i].base_addr + Cy_ClrIntr, 0); - iounmap(cy_card[i].base_addr); - if (cy_card[i].ctl_addr) - iounmap(cy_card[i].ctl_addr); - if (cy_card[i].irq + cy_writeb(card->base_addr + Cy_ClrIntr, 0); + iounmap(card->base_addr); + if (card->ctl_addr) + iounmap(card->ctl_addr); + if (card->irq #ifndef CONFIG_CYZ_INTR - && !IS_CYC_Z(cy_card[i]) + && !IS_CYC_Z(*card) #endif /* CONFIG_CYZ_INTR */ ) - free_irq(cy_card[i].irq, &cy_card[i]); - for (e1 = cy_card[i].first_line; - e1 < cy_card[i].first_line + - cy_card[i].nports; e1++) + free_irq(card->irq, card); + for (e1 = card->first_line; + e1 < card->first_line + + card->nports; e1++) tty_unregister_device(cy_serial_driver, e1); + kfree(card->ports); } } diff --git a/include/linux/cyclades.h b/include/linux/cyclades.h index 07791f026766..72aa00cc4b2d 100644 --- a/include/linux/cyclades.h +++ b/include/linux/cyclades.h @@ -518,6 +518,7 @@ struct cyclades_card { int bus_index; /* address shift - 0 for ISA, 1 for PCI */ int intr_enabled; /* FW Interrupt flag - 0 disabled, 1 enabled */ spinlock_t card_lock; + struct cyclades_port *ports; }; /***************************************