From 2bf49e010b25b8e50e735729b46063c4a9099db1 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 17 Apr 2007 16:00:23 +0000 Subject: brcm63xx cleanups; add a watchdog driver, indent serial console driver, add support for another sst flash SVN-Revision: 6985 --- .../brcm63xx-2.6/files/arch/mips/bcm963xx/Makefile | 2 +- .../brcm63xx-2.6/files/arch/mips/bcm963xx/info.c | 24 +- .../brcm63xx-2.6/files/arch/mips/bcm963xx/irq.c | 10 +- .../brcm63xx-2.6/files/arch/mips/bcm963xx/prom.c | 21 +- .../brcm63xx-2.6/files/arch/mips/bcm963xx/wdt.c | 246 ++++ .../files/drivers/serial/bcm63xx_cons.c | 1325 ++++++++++---------- .../include/asm-mips/mach-bcm963xx/bootloaders.h | 9 +- .../linux/brcm63xx-2.6/patches/150-sst_flash.patch | 36 + 8 files changed, 982 insertions(+), 691 deletions(-) create mode 100644 target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/wdt.c create mode 100644 target/linux/brcm63xx-2.6/patches/150-sst_flash.patch diff --git a/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/Makefile b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/Makefile index aa3654ae50..a9d1e55979 100644 --- a/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/Makefile +++ b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/Makefile @@ -3,7 +3,7 @@ # # Copyright (C) 2004 Broadcom Corporation # -obj-y := irq.o prom.o setup.o time.o ser_init.o int-handler.o info.o +obj-y := irq.o prom.o setup.o time.o ser_init.o int-handler.o info.o wdt.o SRCBASE := $(TOPDIR) EXTRA_CFLAGS += -I$(SRCBASE)/include diff --git a/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/info.c b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/info.c index d492aa3cd6..47a855d78a 100644 --- a/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/info.c +++ b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/info.c @@ -25,7 +25,8 @@ static char *boot_loader_names[BOOT_LOADER_LAST+1] = { [BOOT_LOADER_UNKNOWN] = "Unknown", [BOOT_LOADER_CFE] = "CFE", - [BOOT_LOADER_REDBOOT] = "RedBoot" + [BOOT_LOADER_REDBOOT] = "RedBoot", + [BOOT_LOADER_CFE2] = "CFEv2" }; /* boot loaders specific definitions */ @@ -73,14 +74,29 @@ void __init detect_bootloader(void) { if (detect_cfe()) { boot_loader_type = BOOT_LOADER_CFE; - printk("Boot loader is : %s\n", boot_loader_names[boot_loader_type]); } if (detect_redboot()) { boot_loader_type = BOOT_LOADER_REDBOOT; } - else - boot_loader_type = BOOT_LOADER_UNKNOWN; + else { + /* Some devices are using CFE, but it is not detected as is */ + boot_loader_type = BOOT_LOADER_CFE2; + } + printk("Boot loader is : %s\n", boot_loader_names[boot_loader_type]); +} + +void __init detect_board(void) +{ + switch (boot_loader_type) + { + case BOOT_LOADER_CFE: + break; + case BOOT_LOADER_REDBOOT: + break; + default: + break; + } } EXPORT_SYMBOL(boot_loader_type); diff --git a/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/irq.c b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/irq.c index a606838f33..962cd374dd 100644 --- a/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/irq.c +++ b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/irq.c @@ -237,14 +237,14 @@ unsigned int BcmHalMapInterrupt(FN_HANDLER pfunc, unsigned int param, irq_desc[interruptId].chip = &brcm_irq_no_end_type; if( interruptId >= INTERNAL_ISR_TABLE_OFFSET ) - { - nRet = request_irq( interruptId, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT, - devname, (void *) param ); + { + printk("BcmHalMapInterrupt : internal IRQ\n"); + nRet = request_irq( interruptId, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT, devname, (void *) param ); } else if (interruptId >= INTERRUPT_ID_EXTERNAL_0 && interruptId <= INTERRUPT_ID_EXTERNAL_3) { - nRet = request_external_irq( interruptId, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT, - devname, (void *) param ); + printk("BcmHalMapInterrupt : external IRQ\n"); + nRet = request_external_irq( interruptId, pfunc, SA_SAMPLE_RANDOM | SA_INTERRUPT, devname, (void *) param ); } return( nRet ); diff --git a/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/prom.c b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/prom.c index af278a263a..23e97200b0 100644 --- a/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/prom.c +++ b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/prom.c @@ -1,6 +1,6 @@ /* -<:copyright-gpl Copyright 2004 Broadcom Corp. All Rights Reserved. + Copyright 2007 OpenWrt,org, Florian Fainelli This program is free software; you can distribute it and/or modify it under the terms of the GNU General Public License (Version 2) as @@ -14,7 +14,6 @@ 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. -:> */ /* * prom.c: PROM library initialization code. @@ -50,24 +49,26 @@ void __init prom_init(void) { serial_init(); - printk( "%s prom init\n", get_system_type() ); + printk("%s prom init\n", get_system_type() ); PERF->IrqMask = 0; - + + /* Detect the bootloader */ detect_bootloader(); - if (boot_loader_type == BOOT_LOADER_CFE) { + /* Do further initialisations depending on the bootloader */ + if (boot_loader_type == BOOT_LOADER_CFE || boot_loader_type == BOOT_LOADER_CFE2) { cfe_setup(fw_arg0, fw_arg1, fw_arg2, fw_arg3); - add_memory_region(0, (boot_mem_map.map[0].size - ADSL_SDRAM_IMAGE_SIZE), BOOT_MEM_RAM); } - else - add_memory_region(0, (0x01000000 - ADSL_SDRAM_IMAGE_SIZE), BOOT_MEM_RAM); - + /* Register 16MB RAM minus the ADSL SDRAM by default */ + add_memory_region(0, (0x01000000 - ADSL_SDRAM_IMAGE_SIZE), BOOT_MEM_RAM); + mips_machgroup = MACH_GROUP_BRCM; mips_machtype = MACH_BCM; } -void __init prom_free_prom_memory(void) +unsigned long __init prom_free_prom_memory(void) { /* We do not have any memory to free */ + return 0; } diff --git a/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/wdt.c b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/wdt.c new file mode 100644 index 0000000000..0ea36a67f0 --- /dev/null +++ b/target/linux/brcm63xx-2.6/files/arch/mips/bcm963xx/wdt.c @@ -0,0 +1,246 @@ +/* + * Watchdog driver for the BCM963xx devices + * + * Copyright (C) 2007 OpenWrt.org + * Florian Fainelli + * + * 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 of the License, or (at your + * option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct bcm963xx_timer { + unsigned short unused0; + unsigned char timer_mask; +#define TIMER0EN 0x01 +#define TIMER1EN 0x02 +#define TIMER2EN 0x04 + unsigned char timer_ints; +#define TIMER0 0x01 +#define TIMER1 0x02 +#define TIMER2 0x04 +#define WATCHDOG 0x08 + unsigned long timer_ctl0; + unsigned long timer_ctl1; + unsigned long timer_ctl2; +#define TIMERENABLE 0x80000000 +#define RSTCNTCLR 0x40000000 + unsigned long timer_cnt0; + unsigned long timer_cnt1; + unsigned long timer_cnt2; + unsigned long wdt_def_count; + + /* Write 0xff00 0x00ff to Start timer + * Write 0xee00 0x00ee to Stop and re-load default count + * Read from this register returns current watch dog count + */ + unsigned long wdt_ctl; + + /* Number of 40-MHz ticks for WD Reset pulse to last */ + unsigned long wdt_rst_count; +} bcm963xx_timer; + +static struct bcm963xx_wdt_device { + struct completion stop; + volatile int running; + struct timer_list timer; + volatile int queue; + int default_ticks; + unsigned long inuse; +} bcm963xx_wdt_device; + +static int ticks = 1000; + +#define WDT_BASE 0xfffe0200 +#define WDT ((volatile bcm963xx_timer * const) WDT_BASE) + +#define BCM963XX_INTERVAL (HZ/10+1) + +static void bcm963xx_wdt_trigger(unsigned long unused) +{ + if (bcm963xx_wdt_device.running) + ticks--; + + /* Load the default ticking value into the reset counter register */ + WDT->wdt_rst_count = bcm963xx_wdt_device.default_ticks; + + if (bcm963xx_wdt_device.queue && ticks) { + bcm963xx_wdt_device.timer.expires = jiffies + BCM963XX_INTERVAL; + add_timer(&bcm963xx_wdt_device.timer); + } + else { + complete(&bcm963xx_wdt_device.stop); + } +} + +static void bcm963xx_wdt_reset(void) +{ + ticks = bcm963xx_wdt_device.default_ticks; + /* Also reload default count */ + WDT->wdt_def_count = ticks; + WDT->wdt_ctl = 0xee00; + WDT->wdt_ctl = 0x00ee; +} + +static void bcm963xx_wdt_start(void) +{ + if (!bcm963xx_wdt_device.queue) { + bcm963xx_wdt_device.queue; + /* Enable the watchdog by writing 0xff00 ,then 0x00ff to the control register */ + WDT->wdt_ctl = 0xff00; + WDT->wdt_ctl = 0x00ff; + bcm963xx_wdt_device.timer.expires = jiffies + BCM963XX_INTERVAL; + add_timer(&bcm963xx_wdt_device.timer); + } + bcm963xx_wdt_device.running++; +} + +static int bcm963xx_wdt_stop(void) +{ + if (bcm963xx_wdt_device.running) + bcm963xx_wdt_device.running = 0; + + ticks = bcm963xx_wdt_device.default_ticks; + + /* Stop the watchdog by writing 0xee00 then 0x00ee to the control register */ + WDT->wdt_ctl = 0xee00; + WDT->wdt_ctl = 0x00ee; + + return -EIO; +} + +static int bcm963xx_wdt_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit(0, &bcm963xx_wdt_device.inuse)) + return -EBUSY; + return nonseekable_open(inode, file); +} + +static int bcm963xx_wdt_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &bcm963xx_wdt_device.inuse); + return 0; +} + +static int bcm963xx_wdt_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + void __user *argp = (void __user *)arg; + unsigned int value; + + static struct watchdog_info ident = { + .options = WDIOF_CARDRESET, + .identity = "BCM963xx WDT", + }; + + switch (cmd) { + case WDIOC_KEEPALIVE: + bcm963xx_wdt_reset(); + break; + case WDIOC_GETSTATUS: + /* Reading from the control register will return the current value */ + value = WDT->wdt_ctl; + if ( copy_to_user(argp, &value, sizeof(int)) ) + return -EFAULT; + break; + case WDIOC_GETSUPPORT: + if ( copy_to_user(argp, &ident, sizeof(ident)) ) + return -EFAULT; + break; + case WDIOC_SETOPTIONS: + if ( copy_from_user(&value, argp, sizeof(int)) ) + return -EFAULT; + switch(value) { + case WDIOS_ENABLECARD: + bcm963xx_wdt_start(); + break; + case WDIOS_DISABLECARD: + bcm963xx_wdt_stop(); + break; + default: + return -EINVAL; + } + break; + default: + return -ENOTTY; + } + return 0; +} + +static int bcm963xx_wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +{ + if (!count) + return -EIO; + bcm963xx_wdt_reset(); + return count; +} + +static const struct file_operations bcm963xx_wdt_fops = { + .owner = THIS_MODULE, + .llseek = no_llseek, + .write = bcm963xx_wdt_write, + .ioctl = bcm963xx_wdt_ioctl, + .open = bcm963xx_wdt_open, + .release = bcm963xx_wdt_release, +}; + +static struct miscdevice bcm963xx_wdt_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &bcm963xx_wdt_fops, +}; + +static void __exit bcm963xx_wdt_exit(void) +{ + if (bcm963xx_wdt_device.queue ){ + bcm963xx_wdt_device.queue = 0; + wait_for_completion(&bcm963xx_wdt_device.stop); + } + misc_deregister(&bcm963xx_wdt_miscdev); +} + +static int __init bcm963xx_wdt_init(void) +{ + int ret = 0; + + printk("Broadcom BCM963xx Watchdog timer\n"); + + ret = misc_register(&bcm963xx_wdt_miscdev); + if (ret) { + printk(KERN_CRIT "Cannot register miscdev on minor=%d (err=%d)\n", WATCHDOG_MINOR, ret); + return ret; + } + init_completion(&bcm963xx_wdt_device.stop); + bcm963xx_wdt_device.queue = 0; + + clear_bit(0, &bcm963xx_wdt_device.inuse); + + init_timer(&bcm963xx_wdt_device.timer); + bcm963xx_wdt_device.timer.function = bcm963xx_wdt_trigger; + bcm963xx_wdt_device.timer.data = 0; + + bcm963xx_wdt_device.default_ticks = ticks; + return ret; +} + + +module_init(bcm963xx_wdt_init); +module_exit(bcm963xx_wdt_exit); + +MODULE_AUTHOR("Florian Fainelli "); +MODULE_DESCRIPTION("Broadcom BCM963xx Watchdog driver"); +MODULE_LICENSE("GPL"); diff --git a/target/linux/brcm63xx-2.6/files/drivers/serial/bcm63xx_cons.c b/target/linux/brcm63xx-2.6/files/drivers/serial/bcm63xx_cons.c index f024f23c69..4693779773 100644 --- a/target/linux/brcm63xx-2.6/files/drivers/serial/bcm63xx_cons.c +++ b/target/linux/brcm63xx-2.6/files/drivers/serial/bcm63xx_cons.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -53,37 +53,37 @@ extern void _putc(char); extern void _puts(const char *); typedef struct bcm_serial { - volatile Uart * port; - int type; - int flags; - int irq; - int baud_base; - int blocked_open; - unsigned short close_delay; - unsigned short closing_wait; - unsigned short line; /* port/line number */ - unsigned short cflags; /* line configuration flag */ - unsigned short x_char; /* xon/xoff character */ - unsigned short read_status_mask; /* mask for read condition */ - unsigned short ignore_status_mask; /* mask for ignore condition */ - unsigned long event; /* mask used in BH */ - int xmit_head; /* Position of the head */ - int xmit_tail; /* Position of the tail */ - int xmit_cnt; /* Count of the chars in the buffer */ - int count; /* indicates how many times it has been opened */ - int magic; - - struct async_icount icount; /* keep track of things ... */ - struct tty_struct *tty; /* tty associated */ - struct termios normal_termios; - - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; - - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ - - unsigned char is_initialized; + volatile Uart *port; + int type; + int flags; + int irq; + int baud_base; + int blocked_open; + unsigned short close_delay; + unsigned short closing_wait; + unsigned short line; /* port/line number */ + unsigned short cflags; /* line configuration flag */ + unsigned short x_char; /* xon/xoff character */ + unsigned short read_status_mask; /* mask for read condition */ + unsigned short ignore_status_mask; /* mask for ignore condition */ + unsigned long event; /* mask used in BH */ + int xmit_head; /* Position of the head */ + int xmit_tail; /* Position of the tail */ + int xmit_cnt; /* Count of the chars in the buffer */ + int count; /* indicates how many times it has been opened */ + int magic; + + struct async_icount icount; /* keep track of things ... */ + struct tty_struct *tty; /* tty associated */ + struct termios normal_termios; + + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; + + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + + unsigned char is_initialized; } Context; @@ -94,7 +94,7 @@ typedef struct bcm_serial { #define RXINT (RXFIFONE|RXOVFERR) /* Enable transmit interrupt */ -#define TXINT (TXFIFOEMT|TXUNDERR|TXOVFERR) +#define TXINT (TXFIFOEMT|TXUNDERR|TXOVFERR) /* Enable receiver line status interrupt */ #define LSINT (RXBRK|RXPARERR|RXFRAMERR) @@ -111,32 +111,36 @@ static struct termios *serial_termios[BCM_NUM_UARTS]; static struct termios *serial_termios_locked[BCM_NUM_UARTS]; -static void bcm_stop (struct tty_struct *tty); -static void bcm_start (struct tty_struct *tty); -static inline void receive_chars (struct bcm_serial * info); -static int startup (struct bcm_serial *info); -static void shutdown (struct bcm_serial * info); -static void change_speed( volatile Uart *pUart, tcflag_t cFlag ); -static void bcm63xx_cons_flush_chars (struct tty_struct *tty); -static int bcm63xx_cons_write (struct tty_struct *tty, - const unsigned char *buf, int count); -static int bcm63xx_cons_write_room (struct tty_struct *tty); -static int bcm_chars_in_buffer (struct tty_struct *tty); -static void bcm_flush_buffer (struct tty_struct *tty); -static void bcm_throttle (struct tty_struct *tty); -static void bcm_unthrottle (struct tty_struct *tty); -static void bcm_send_xchar (struct tty_struct *tty, char ch); -static int get_serial_info(struct bcm_serial *info, struct serial_struct *retinfo); -static int set_serial_info (struct bcm_serial *info, struct serial_struct *new_info); -static int get_lsr_info (struct bcm_serial *info, unsigned int *value); -static void send_break (struct bcm_serial *info, int duration); -static int bcm_ioctl (struct tty_struct * tty, struct file * file, - unsigned int cmd, unsigned long arg); -static void bcm_set_termios (struct tty_struct *tty, struct termios *old_termios); -static void bcm63xx_cons_close (struct tty_struct *tty, struct file *filp); -static void bcm_hangup (struct tty_struct *tty); -static int block_til_ready (struct tty_struct *tty, struct file *filp, struct bcm_serial *info); -static int bcm63xx_cons_open (struct tty_struct * tty, struct file * filp); +static void bcm_stop(struct tty_struct *tty); +static void bcm_start(struct tty_struct *tty); +static inline void receive_chars(struct bcm_serial *info); +static int startup(struct bcm_serial *info); +static void shutdown(struct bcm_serial *info); +static void change_speed(volatile Uart * pUart, tcflag_t cFlag); +static void bcm63xx_cons_flush_chars(struct tty_struct *tty); +static int bcm63xx_cons_write(struct tty_struct *tty, + const unsigned char *buf, int count); +static int bcm63xx_cons_write_room(struct tty_struct *tty); +static int bcm_chars_in_buffer(struct tty_struct *tty); +static void bcm_flush_buffer(struct tty_struct *tty); +static void bcm_throttle(struct tty_struct *tty); +static void bcm_unthrottle(struct tty_struct *tty); +static void bcm_send_xchar(struct tty_struct *tty, char ch); +static int get_serial_info(struct bcm_serial *info, + struct serial_struct *retinfo); +static int set_serial_info(struct bcm_serial *info, + struct serial_struct *new_info); +static int get_lsr_info(struct bcm_serial *info, unsigned int *value); +static void send_break(struct bcm_serial *info, int duration); +static int bcm_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg); +static void bcm_set_termios(struct tty_struct *tty, + struct termios *old_termios); +static void bcm63xx_cons_close(struct tty_struct *tty, struct file *filp); +static void bcm_hangup(struct tty_struct *tty); +static int block_til_ready(struct tty_struct *tty, struct file *filp, + struct bcm_serial *info); +static int bcm63xx_cons_open(struct tty_struct *tty, struct file *filp); static int __init bcm63xx_serialinit(void); @@ -149,14 +153,14 @@ static int __init bcm63xx_serialinit(void); * as necessary. * ------------------------------------------------------------ */ -static void bcm_stop (struct tty_struct *tty) +static void bcm_stop(struct tty_struct *tty) { -} +} -static void bcm_start (struct tty_struct *tty) +static void bcm_start(struct tty_struct *tty) { - _puts(CARDNAME " Start\n"); -} + _puts(CARDNAME " Start\n"); +} /* * ------------------------------------------------------------ @@ -165,76 +169,65 @@ static void bcm_start (struct tty_struct *tty) * This routine deals with inputs from any lines. * ------------------------------------------------------------ */ -static inline void receive_chars (struct bcm_serial * info) +static inline void receive_chars(struct bcm_serial *info) { - struct tty_struct *tty = 0; - struct async_icount * icount; - int ignore = 0; - unsigned short status, tmp; - UCHAR ch = 0; - while ((status = info->port->intStatus) & RXINT) - { + struct tty_struct *tty = 0; + struct async_icount *icount; + int ignore = 0; + unsigned short status, tmp; + UCHAR ch = 0; + while ((status = info->port->intStatus) & RXINT) { char flag_char = TTY_NORMAL; - if (status & RXFIFONE) - ch = info->port->Data; // Read the character - tty = info->tty; /* now tty points to the proper dev */ - icount = &info->icount; - if (! tty) - break; - if (!tty_buffer_request_room(tty, 1)) - break; - icount->rx++; - if (status & RXBRK) - { - flag_char = TTY_BREAK; - icount->brk++; - } - // keep track of the statistics - if (status & (RXFRAMERR | RXPARERR | RXOVFERR)) - { - if (status & RXPARERR) /* parity error */ - icount->parity++; - else - if (status & RXFRAMERR) /* frame error */ - icount->frame++; - if (status & RXOVFERR) - { - // Overflow. Reset the RX FIFO - info->port->fifoctl |= RSTRXFIFOS; - icount->overrun++; - } - // check to see if we should ignore the character - // and mask off conditions that should be ignored - if (status & info->ignore_status_mask) - { - if (++ignore > 100 ) - break; - goto ignore_char; - } - // Mask off the error conditions we want to ignore - tmp = status & info->read_status_mask; - if (tmp & RXPARERR) - { - flag_char = TTY_PARITY; - } - else - if (tmp & RXFRAMERR) - { - flag_char = TTY_FRAME; - } - if (tmp & RXOVFERR) - { - tty_insert_flip_char(tty, ch, flag_char); - ch = 0; - flag_char = TTY_OVERRUN; + if (status & RXFIFONE) + ch = info->port->Data; // Read the character + tty = info->tty; /* now tty points to the proper dev */ + icount = &info->icount; + if (!tty) + break; if (!tty_buffer_request_room(tty, 1)) - break; - } - } - tty_insert_flip_char(tty, ch, flag_char); - } -ignore_char:; + break; + icount->rx++; + if (status & RXBRK) { + flag_char = TTY_BREAK; + icount->brk++; + } + // keep track of the statistics + if (status & (RXFRAMERR | RXPARERR | RXOVFERR)) { + if (status & RXPARERR) /* parity error */ + icount->parity++; + else if (status & RXFRAMERR) /* frame error */ + icount->frame++; + if (status & RXOVFERR) { + // Overflow. Reset the RX FIFO + info->port->fifoctl |= RSTRXFIFOS; + icount->overrun++; + } + // check to see if we should ignore the character + // and mask off conditions that should be ignored + if (status & info->ignore_status_mask) { + if (++ignore > 100) + break; + goto ignore_char; + } + // Mask off the error conditions we want to ignore + tmp = status & info->read_status_mask; + if (tmp & RXPARERR) { + flag_char = TTY_PARITY; + } else if (tmp & RXFRAMERR) { + flag_char = TTY_FRAME; + } + if (tmp & RXOVFERR) { + tty_insert_flip_char(tty, ch, flag_char); + ch = 0; + flag_char = TTY_OVERRUN; + if (!tty_buffer_request_room(tty, 1)) + break; + } + } + tty_insert_flip_char(tty, ch, flag_char); + } + ignore_char:; tty_flip_buffer_push(tty); tty_schedule_flip(tty); @@ -250,36 +243,34 @@ ignore_char:; * ------------------------------------------------------------ */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) -static irqreturn_t bcm_interrupt (int irq, void * dev) +static irqreturn_t bcm_interrupt(int irq, void *dev) #else -static void bcm_interrupt (int irq, void * dev, struct pt_regs * regs) +static void bcm_interrupt(int irq, void *dev, struct pt_regs *regs) #endif { - struct bcm_serial * info = lines[0]; - UINT16 intStat; - - /* get pending interrupt flags from UART */ - - /* Mask with only the serial interrupts that are enabled */ - intStat = info->port->intStatus & info->port->intMask; - while (intStat) - { - if (intStat & RXINT) - receive_chars (info); - else - if (intStat & TXINT) - info->port->intStatus = TXINT; - else /* don't know what it was, so let's mask it */ - info->port->intMask &= ~intStat; - - intStat = info->port->intStatus & info->port->intMask; - } - - // Clear the interrupt - BcmHalInterruptEnable (INTERRUPT_ID_UART); + struct bcm_serial *info = lines[0]; + UINT16 intStat; + + /* get pending interrupt flags from UART */ + + /* Mask with only the serial interrupts that are enabled */ + intStat = info->port->intStatus & info->port->intMask; + while (intStat) { + if (intStat & RXINT) + receive_chars(info); + else if (intStat & TXINT) + info->port->intStatus = TXINT; + else /* don't know what it was, so let's mask it */ + info->port->intMask &= ~intStat; + + intStat = info->port->intStatus & info->port->intMask; + } + + // Clear the interrupt + enable_brcm_irq(INTERRUPT_ID_UART); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - return IRQ_HANDLED; -#endif + return IRQ_HANDLED; +#endif } /* @@ -289,10 +280,10 @@ static void bcm_interrupt (int irq, void * dev, struct pt_regs * regs) * various initialization tasks * ------------------------------------------------------------------- */ -static int startup (struct bcm_serial *info) +static int startup(struct bcm_serial *info) { - // Port is already started... - return 0; + // Port is already started... + return 0; } /* @@ -303,21 +294,22 @@ static int startup (struct bcm_serial *info) * DTR is dropped if the hangup on close termio flag is on. * ------------------------------------------------------------------- */ -static void shutdown (struct bcm_serial * info) +static void shutdown(struct bcm_serial *info) { - unsigned long flags; - if (!info->is_initialized) - return; + unsigned long flags; + if (!info->is_initialized) + return; - spin_lock_irqsave(&bcm963xx_serial_lock, flags); + spin_lock_irqsave(&bcm963xx_serial_lock, flags); - info->port->control &= ~(BRGEN|TXEN|RXEN); - if (info->tty) - set_bit (TTY_IO_ERROR, &info->tty->flags); - info->is_initialized = 0; + info->port->control &= ~(BRGEN | TXEN | RXEN); + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + info->is_initialized = 0; - spin_unlock_irqrestore(&bcm963xx_serial_lock, flags); + spin_unlock_irqrestore(&bcm963xx_serial_lock, flags); } + /* * ------------------------------------------------------------------- * change_speed () @@ -325,118 +317,117 @@ static void shutdown (struct bcm_serial * info) * Set the baud rate, character size, parity and stop bits. * ------------------------------------------------------------------- */ -static void change_speed( volatile Uart *pUart, tcflag_t cFlag ) +static void change_speed(volatile Uart * pUart, tcflag_t cFlag) { - unsigned long ulFlags, ulBaud, ulClockFreqHz, ulTmp; - - spin_lock_irqsave(&bcm963xx_serial_lock, ulFlags); - switch( cFlag & (CBAUD | CBAUDEX) ) - { - case B115200: - ulBaud = 115200; - break; - case B57600: - ulBaud = 57600; - break; - case B38400: - ulBaud = 38400; - break; - case B19200: - ulBaud = 19200; - break; - case B9600: - ulBaud = 9600; - break; - case B4800: - ulBaud = 4800; - break; - case B2400: - ulBaud = 2400; - break; - case B1800: - ulBaud = 1800; - break; - case B1200: - ulBaud = 1200; - break; - case B600: - ulBaud = 600; - break; - case B300: - ulBaud = 300; - break; - case B200: - ulBaud = 200; - break; - case B150: - ulBaud = 150; - break; - case B134: - ulBaud = 134; - break; - case B110: - ulBaud = 110; - break; - case B75: - ulBaud = 75; - break; - case B50: - ulBaud = 50; - break; - default: - ulBaud = 115200; - break; - } - - /* Calculate buad rate. */ - ulClockFreqHz = BD_BCM63XX_TIMER_CLOCK_INPUT; - ulTmp = (ulClockFreqHz / ulBaud) / 16; - if( ulTmp & 0x01 ) - ulTmp /= 2; /* Rounding up, so sub is already accounted for */ - else - ulTmp = (ulTmp / 2) - 1; /* Rounding down so we must sub 1 */ - pUart->baudword = ulTmp; - - /* Set character size, stop bits and parity. */ - switch( cFlag & CSIZE ) - { - case CS5: - ulTmp = BITS5SYM; /* select transmit 5 bit data size */ - break; - case CS6: - ulTmp = BITS6SYM; /* select transmit 6 bit data size */ - break; - case CS7: - ulTmp = BITS7SYM; /* select transmit 7 bit data size */ - break; - default: - ulTmp = BITS8SYM; /* select transmit 8 bit data size */ - break; - } - if( cFlag & CSTOPB ) - ulTmp |= TWOSTOP; /* select 2 stop bits */ - else - ulTmp |= ONESTOP; /* select one stop bit */ - - /* Write these values into the config reg. */ - pUart->config = ulTmp; - pUart->control &= ~(RXPARITYEN | TXPARITYEN | RXPARITYEVEN | TXPARITYEVEN); - switch( cFlag & (PARENB | PARODD) ) - { - case PARENB|PARODD: - pUart->control |= RXPARITYEN | TXPARITYEN; - break; - case PARENB: - pUart->control |= RXPARITYEN | TXPARITYEN | RXPARITYEVEN | TXPARITYEVEN; - break; - default: - pUart->control |= 0; - break; - } - - /* Reset and flush uart */ - pUart->fifoctl = RSTTXFIFOS | RSTRXFIFOS; - spin_unlock_irqrestore(&bcm963xx_serial_lock, ulFlags); + unsigned long ulFlags, ulBaud, ulClockFreqHz, ulTmp; + + spin_lock_irqsave(&bcm963xx_serial_lock, ulFlags); + switch (cFlag & (CBAUD | CBAUDEX)) { + case B115200: + ulBaud = 115200; + break; + case B57600: + ulBaud = 57600; + break; + case B38400: + ulBaud = 38400; + break; + case B19200: + ulBaud = 19200; + break; + case B9600: + ulBaud = 9600; + break; + case B4800: + ulBaud = 4800; + break; + case B2400: + ulBaud = 2400; + break; + case B1800: + ulBaud = 1800; + break; + case B1200: + ulBaud = 1200; + break; + case B600: + ulBaud = 600; + break; + case B300: + ulBaud = 300; + break; + case B200: + ulBaud = 200; + break; + case B150: + ulBaud = 150; + break; + case B134: + ulBaud = 134; + break; + case B110: + ulBaud = 110; + break; + case B75: + ulBaud = 75; + break; + case B50: + ulBaud = 50; + break; + default: + ulBaud = 115200; + break; + } + + /* Calculate buad rate. */ + ulClockFreqHz = BD_BCM63XX_TIMER_CLOCK_INPUT; + ulTmp = (ulClockFreqHz / ulBaud) / 16; + if (ulTmp & 0x01) + ulTmp /= 2; /* Rounding up, so sub is already accounted for */ + else + ulTmp = (ulTmp / 2) - 1; /* Rounding down so we must sub 1 */ + pUart->baudword = ulTmp; + + /* Set character size, stop bits and parity. */ + switch (cFlag & CSIZE) { + case CS5: + ulTmp = BITS5SYM; /* select transmit 5 bit data size */ + break; + case CS6: + ulTmp = BITS6SYM; /* select transmit 6 bit data size */ + break; + case CS7: + ulTmp = BITS7SYM; /* select transmit 7 bit data size */ + break; + default: + ulTmp = BITS8SYM; /* select transmit 8 bit data size */ + break; + } + if (cFlag & CSTOPB) + ulTmp |= TWOSTOP; /* select 2 stop bits */ + else + ulTmp |= ONESTOP; /* select one stop bit */ + + /* Write these values into the config reg. */ + pUart->config = ulTmp; + pUart->control &= + ~(RXPARITYEN | TXPARITYEN | RXPARITYEVEN | TXPARITYEVEN); + switch (cFlag & (PARENB | PARODD)) { + case PARENB | PARODD: + pUart->control |= RXPARITYEN | TXPARITYEN; + break; + case PARENB: + pUart->control |= + RXPARITYEN | TXPARITYEN | RXPARITYEVEN | TXPARITYEVEN; + break; + default: + pUart->control |= 0; + break; + } + + /* Reset and flush uart */ + pUart->fifoctl = RSTTXFIFOS | RSTRXFIFOS; + spin_unlock_irqrestore(&bcm963xx_serial_lock, ulFlags); } @@ -447,7 +438,7 @@ static void change_speed( volatile Uart *pUart, tcflag_t cFlag ) * Nothing to flush. Polled I/O is used. * ------------------------------------------------------------------- */ -static void bcm63xx_cons_flush_chars (struct tty_struct *tty) +static void bcm63xx_cons_flush_chars(struct tty_struct *tty) { } @@ -459,14 +450,14 @@ static void bcm63xx_cons_flush_chars (struct tty_struct *tty) * Main output routine using polled I/O. * ------------------------------------------------------------------- */ -static int bcm63xx_cons_write (struct tty_struct *tty, - const unsigned char *buf, int count) +static int bcm63xx_cons_write(struct tty_struct *tty, + const unsigned char *buf, int count) { - int c; + int c; - for (c = 0; c < count; c++) - _putc(buf[c]); - return count; + for (c = 0; c < count; c++) + _putc(buf[c]); + return count; } /* @@ -476,10 +467,10 @@ static int bcm63xx_cons_write (struct tty_struct *tty, * Compute the amount of space available for writing. * ------------------------------------------------------------------- */ -static int bcm63xx_cons_write_room (struct tty_struct *tty) +static int bcm63xx_cons_write_room(struct tty_struct *tty) { - /* Pick a number. Any number. Polled I/O is used. */ - return 1024; + /* Pick a number. Any number. Polled I/O is used. */ + return 1024; } /* @@ -489,9 +480,9 @@ static int bcm63xx_cons_write_room (struct tty_struct *tty) * compute the amount of char left to be transmitted * ------------------------------------------------------------------- */ -static int bcm_chars_in_buffer (struct tty_struct *tty) +static int bcm_chars_in_buffer(struct tty_struct *tty) { - return 0; + return 0; } /* @@ -501,7 +492,7 @@ static int bcm_chars_in_buffer (struct tty_struct *tty) * Empty the output buffer * ------------------------------------------------------------------- */ -static void bcm_flush_buffer (struct tty_struct *tty) +static void bcm_flush_buffer(struct tty_struct *tty) { tty_wakeup(tty); } @@ -514,31 +505,30 @@ static void bcm_flush_buffer (struct tty_struct *tty) * incoming characters should be throttled (or not). * ------------------------------------------------------------ */ -static void bcm_throttle (struct tty_struct *tty) +static void bcm_throttle(struct tty_struct *tty) { - struct bcm_serial *info = (struct bcm_serial *)tty->driver_data; - if (I_IXOFF(tty)) - info->x_char = STOP_CHAR(tty); + struct bcm_serial *info = (struct bcm_serial *) tty->driver_data; + if (I_IXOFF(tty)) + info->x_char = STOP_CHAR(tty); } -static void bcm_unthrottle (struct tty_struct *tty) +static void bcm_unthrottle(struct tty_struct *tty) { - struct bcm_serial *info = (struct bcm_serial *)tty->driver_data; - if (I_IXOFF(tty)) - { - if (info->x_char) - info->x_char = 0; - else - info->x_char = START_CHAR(tty); - } + struct bcm_serial *info = (struct bcm_serial *) tty->driver_data; + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + info->x_char = START_CHAR(tty); + } } -static void bcm_send_xchar (struct tty_struct *tty, char ch) +static void bcm_send_xchar(struct tty_struct *tty, char ch) { - struct bcm_serial *info = (struct bcm_serial *)tty->driver_data; - info->x_char = ch; - if (ch) - bcm_start (info->tty); + struct bcm_serial *info = (struct bcm_serial *) tty->driver_data; + info->x_char = ch; + if (ch) + bcm_start(info->tty); } /* @@ -546,54 +536,56 @@ static void bcm_send_xchar (struct tty_struct *tty, char ch) * rs_ioctl () and friends * ------------------------------------------------------------ */ -static int get_serial_info(struct bcm_serial *info, struct serial_struct *retinfo) +static int get_serial_info(struct bcm_serial *info, + struct serial_struct *retinfo) { - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - - memset (&tmp, 0, sizeof(tmp)); - tmp.type = info->type; - tmp.line = info->line; - tmp.port = (int) info->port; - tmp.irq = info->irq; - tmp.flags = 0; - tmp.baud_base = info->baud_base; - tmp.close_delay = info->close_delay; - tmp.closing_wait = info->closing_wait; - - return copy_to_user (retinfo, &tmp, sizeof(*retinfo)); + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->line; + tmp.port = (int) info->port; + tmp.irq = info->irq; + tmp.flags = 0; + tmp.baud_base = info->baud_base; + tmp.close_delay = info->close_delay; + tmp.closing_wait = info->closing_wait; + + return copy_to_user(retinfo, &tmp, sizeof(*retinfo)); } -static int set_serial_info (struct bcm_serial *info, struct serial_struct *new_info) +static int set_serial_info(struct bcm_serial *info, + struct serial_struct *new_info) { - struct serial_struct new_serial; - struct bcm_serial old_info; - int retval = 0; + struct serial_struct new_serial; + struct bcm_serial old_info; + int retval = 0; - if (!new_info) - return -EFAULT; + if (!new_info) + return -EFAULT; - copy_from_user (&new_serial, new_info, sizeof(new_serial)); - old_info = *info; + copy_from_user(&new_serial, new_info, sizeof(new_serial)); + old_info = *info; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; - if (info->count > 1) - return -EBUSY; + if (info->count > 1) + return -EBUSY; - /* OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - info->baud_base = new_serial.baud_base; - info->type = new_serial.type; - info->close_delay = new_serial.close_delay; - info->closing_wait = new_serial.closing_wait; - retval = startup (info); - return retval; + /* OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + info->baud_base = new_serial.baud_base; + info->type = new_serial.type; + info->close_delay = new_serial.close_delay; + info->closing_wait = new_serial.closing_wait; + retval = startup(info); + return retval; } /* @@ -606,125 +598,135 @@ static int set_serial_info (struct bcm_serial *info, struct serial_struct *new_i * transmit holding register is empty. This functionality * allows an RS485 driver to be written in user space. */ -static int get_lsr_info (struct bcm_serial *info, unsigned int *value) +static int get_lsr_info(struct bcm_serial *info, unsigned int *value) { - return( 0 ); + return (0); } /* * This routine sends a break character out the serial port. */ -static void send_break (struct bcm_serial *info, int duration) +static void send_break(struct bcm_serial *info, int duration) { - unsigned long flags; + unsigned long flags; - if (!info->port) - return; + if (!info->port) + return; - current->state = TASK_INTERRUPTIBLE; + current->state = TASK_INTERRUPTIBLE; - /*save_flags (flags); - cli();*/ - spin_lock_irqsave(&bcm963xx_serial_lock, flags); + /*save_flags (flags); + cli(); */ + spin_lock_irqsave(&bcm963xx_serial_lock, flags); - info->port->control |= XMITBREAK; - schedule_timeout(duration); - info->port->control &= ~XMITBREAK; + info->port->control |= XMITBREAK; + schedule_timeout(duration); + info->port->control &= ~XMITBREAK; - spin_unlock_irqrestore(&bcm963xx_serial_lock, flags); - //restore_flags (flags); + spin_unlock_irqrestore(&bcm963xx_serial_lock, flags); + //restore_flags (flags); } -static int bcm_ioctl (struct tty_struct * tty, struct file * file, - unsigned int cmd, unsigned long arg) +static int bcm_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { - int error; - struct bcm_serial * info = (struct bcm_serial *)tty->driver_data; - int retval; - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && - (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) - { - if (tty->flags & (1 << TTY_IO_ERROR)) - return -EIO; - } - switch (cmd) - { - - case TCSBRK: /* SVID version: non-zero arg --> no break */ - retval = tty_check_change (tty); - if (retval) - return retval; - tty_wait_until_sent (tty, 0); - if (!arg) - send_break (info, HZ/4); /* 1/4 second */ - return 0; - - case TCSBRKP: /* support for POSIX tcsendbreak() */ - retval = tty_check_change (tty); - if (retval) - return retval; - tty_wait_until_sent (tty, 0); - send_break (info, arg ? arg*(HZ/10) : HZ/4); - return 0; - - case TIOCGSOFTCAR: - error = access_ok (VERIFY_WRITE, (void *)arg, sizeof(long)); - if (!error) - return -EFAULT; - else - { - put_user (C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); - return 0; + int error; + struct bcm_serial *info = (struct bcm_serial *) tty->driver_data; + int retval; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; } - - case TIOCSSOFTCAR: - error = get_user (arg, (unsigned long *)arg); - if (error) - return error; - tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); - return 0; - - case TIOCGSERIAL: - error = access_ok (VERIFY_WRITE, (void *)arg, sizeof(struct serial_struct)); - if (!error) - return -EFAULT; - else - return get_serial_info (info, (struct serial_struct *)arg); - - case TIOCSSERIAL: - return set_serial_info (info, (struct serial_struct *) arg); - - case TIOCSERGETLSR: /* Get line status register */ - error = access_ok (VERIFY_WRITE, (void *)arg, sizeof(unsigned int)); - if (!error) - return -EFAULT; - else - return get_lsr_info (info, (unsigned int *)arg); - - case TIOCSERGSTRUCT: - error = access_ok (VERIFY_WRITE, (void *)arg, sizeof(struct bcm_serial)); - if (!error) - return -EFAULT; - else - { - copy_to_user((struct bcm_serial *)arg, info, sizeof(struct bcm_serial)); - return 0; + switch (cmd) { + + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (!arg) + send_break(info, HZ / 4); /* 1/4 second */ + return 0; + + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + send_break(info, arg ? arg * (HZ / 10) : HZ / 4); + return 0; + + case TIOCGSOFTCAR: + error = + access_ok(VERIFY_WRITE, (void *) arg, sizeof(long)); + if (!error) + return -EFAULT; + else { + put_user(C_CLOCAL(tty) ? 1 : 0, + (unsigned long *) arg); + return 0; + } + + case TIOCSSOFTCAR: + error = get_user(arg, (unsigned long *) arg); + if (error) + return error; + tty->termios->c_cflag = + ((tty->termios-> + c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); + return 0; + + case TIOCGSERIAL: + error = + access_ok(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct)); + if (!error) + return -EFAULT; + else + return get_serial_info(info, + (struct serial_struct *) + arg); + + case TIOCSSERIAL: + return set_serial_info(info, (struct serial_struct *) arg); + + case TIOCSERGETLSR: /* Get line status register */ + error = + access_ok(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int)); + if (!error) + return -EFAULT; + else + return get_lsr_info(info, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + error = + access_ok(VERIFY_WRITE, (void *) arg, + sizeof(struct bcm_serial)); + if (!error) + return -EFAULT; + else { + copy_to_user((struct bcm_serial *) arg, info, + sizeof(struct bcm_serial)); + return 0; + } + + default: + return -ENOIOCTLCMD; } - - default: - return -ENOIOCTLCMD; - } - return 0; + return 0; } -static void bcm_set_termios (struct tty_struct *tty, struct termios *old_termios) +static void bcm_set_termios(struct tty_struct *tty, + struct termios *old_termios) { - struct bcm_serial *info = (struct bcm_serial *)tty->driver_data; + struct bcm_serial *info = (struct bcm_serial *) tty->driver_data; - if( tty->termios->c_cflag != old_termios->c_cflag ) - change_speed (info->port, tty->termios->c_cflag); + if (tty->termios->c_cflag != old_termios->c_cflag) + change_speed(info->port, tty->termios->c_cflag); } /* @@ -736,112 +738,106 @@ static void bcm_set_termios (struct tty_struct *tty, struct termios *old_termios * the transmit enable and receive enable flags. * ------------------------------------------------------------ */ -static void bcm63xx_cons_close (struct tty_struct *tty, struct file *filp) +static void bcm63xx_cons_close(struct tty_struct *tty, struct file *filp) { - struct bcm_serial * info = (struct bcm_serial *)tty->driver_data; - unsigned long flags; - - if (!info) - return; - - /*save_flags (flags); - cli();*/ - spin_lock_irqsave(&bcm963xx_serial_lock, flags); - - if (tty_hung_up_p (filp)) - { - spin_unlock_irqrestore(&bcm963xx_serial_lock, flags); - //restore_flags (flags); - return; - } - - if ((tty->count == 1) && (info->count != 1)) - { - - /* Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Info->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * serial port won't be shutdown. - */ - printk("bcm63xx_cons_close: bad serial port count; tty->count is 1, " - "info->count is %d\n", info->count); - info->count = 1; - } - - if (--info->count < 0) - { - printk("ds_close: bad serial port count for ttys%d: %d\n", - info->line, info->count); - info->count = 0; - } - - if (info->count) - { - //restore_flags (flags); - spin_unlock_irqrestore(&bcm963xx_serial_lock, flags); - return; - } - - /* Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - - /* At this point we stop accepting input. To do this, we - * disable the receive line status interrupts. - */ - shutdown (info); + struct bcm_serial *info = (struct bcm_serial *) tty->driver_data; + unsigned long flags; + + if (!info) + return; + + /*save_flags (flags); + cli(); */ + spin_lock_irqsave(&bcm963xx_serial_lock, flags); + + if (tty_hung_up_p(filp)) { + spin_unlock_irqrestore(&bcm963xx_serial_lock, flags); + //restore_flags (flags); + return; + } + + if ((tty->count == 1) && (info->count != 1)) { + + /* Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk + ("bcm63xx_cons_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + + if (--info->count < 0) { + printk("ds_close: bad serial port count for ttys%d: %d\n", + info->line, info->count); + info->count = 0; + } + + if (info->count) { + //restore_flags (flags); + spin_unlock_irqrestore(&bcm963xx_serial_lock, flags); + return; + } + + /* Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + + /* At this point we stop accepting input. To do this, we + * disable the receive line status interrupts. + */ + shutdown(info); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - if (tty->driver->flush_buffer) - tty->driver->flush_buffer (tty); -#else - if (tty->driver.flush_buffer) - tty->driver.flush_buffer (tty); + if (tty->driver->flush_buffer) + tty->driver->flush_buffer(tty); +#else + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); #endif - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer (tty); - - tty->closing = 0; - info->event = 0; - info->tty = 0; - if (tty->ldisc.num != tty_ldisc_get(N_TTY)->num) - { - if (tty->ldisc.close) - (tty->ldisc.close)(tty); - tty->ldisc = *tty_ldisc_get(N_TTY); - tty->termios->c_line = N_TTY; - if (tty->ldisc.open) - (tty->ldisc.open)(tty); - } - if (info->blocked_open) - { - if (info->close_delay) - { - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(info->close_delay); - } - wake_up_interruptible (&info->open_wait); - } - wake_up_interruptible (&info->close_wait); - - //restore_flags (flags); - spin_unlock_irqrestore(&bcm963xx_serial_lock, flags); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (tty->ldisc.num != tty_ldisc_get(N_TTY)->num) { + if (tty->ldisc.close) + (tty->ldisc.close) (tty); + tty->ldisc = *tty_ldisc_get(N_TTY); + tty->termios->c_line = N_TTY; + if (tty->ldisc.open) + (tty->ldisc.open) (tty); + } + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(info->close_delay); + } + wake_up_interruptible(&info->open_wait); + } + wake_up_interruptible(&info->close_wait); + + //restore_flags (flags); + spin_unlock_irqrestore(&bcm963xx_serial_lock, flags); } /* * bcm_hangup () --- called by tty_hangup() when a hangup is signaled. */ -static void bcm_hangup (struct tty_struct *tty) +static void bcm_hangup(struct tty_struct *tty) { - struct bcm_serial *info = (struct bcm_serial *)tty->driver_data; + struct bcm_serial *info = (struct bcm_serial *) tty->driver_data; - shutdown (info); - info->event = 0; - info->count = 0; - info->tty = 0; - wake_up_interruptible (&info->open_wait); + shutdown(info); + info->event = 0; + info->count = 0; + info->tty = 0; + wake_up_interruptible(&info->open_wait); } /* @@ -849,62 +845,62 @@ static void bcm_hangup (struct tty_struct *tty) * rs_open() and friends * ------------------------------------------------------------ */ -static int block_til_ready (struct tty_struct *tty, struct file *filp, - struct bcm_serial *info) +static int block_til_ready(struct tty_struct *tty, struct file *filp, + struct bcm_serial *info) { - return 0; -} + return 0; +} /* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port. It also performs the * serial-specific initialization for the tty structure. */ -static int bcm63xx_cons_open (struct tty_struct * tty, struct file * filp) +static int bcm63xx_cons_open(struct tty_struct *tty, struct file *filp) { - struct bcm_serial *info; - int retval, line; + struct bcm_serial *info; + int retval, line; - // Make sure we're only opening on of the ports we support + // Make sure we're only opening on of the ports we support #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - line = MINOR(tty->driver->cdev.dev) - tty->driver->minor_start; + line = MINOR(tty->driver->cdev.dev) - tty->driver->minor_start; #else - line = MINOR(tty->device) - tty->driver.minor_start; -#endif + line = MINOR(tty->device) - tty->driver.minor_start; +#endif - if ((line < 0) || (line >= BCM_NUM_UARTS)) - return -ENODEV; + if ((line < 0) || (line >= BCM_NUM_UARTS)) + return -ENODEV; - info = lines[line]; + info = lines[line]; - tty->low_latency=1; - info->port->intMask = 0; /* Clear any pending interrupts */ - info->port->intMask = RXINT; /* Enable RX */ + tty->low_latency = 1; + info->port->intMask = 0; /* Clear any pending interrupts */ + info->port->intMask = RXINT; /* Enable RX */ - info->count++; - tty->driver_data = info; - info->tty = tty; - BcmHalInterruptEnable (INTERRUPT_ID_UART); + info->count++; + tty->driver_data = info; + info->tty = tty; + enable_brcm_irq(INTERRUPT_ID_UART); - // Start up serial port - retval = startup (info); - if (retval) - return retval; + // Start up serial port + retval = startup(info); + if (retval) + return retval; - retval = block_til_ready (tty, filp, info); - if (retval) - return retval; + retval = block_til_ready(tty, filp, info); + if (retval) + return retval; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - info->pgrp = process_group(current); - info->session = current->signal->session; + info->pgrp = process_group(current); + info->session = current->signal->session; #else - info->session = current->session; - info->pgrp = current->pgrp; -#endif + info->session = current->session; + info->pgrp = current->pgrp; +#endif - return 0; + return 0; } @@ -932,72 +928,69 @@ static struct tty_operations rs_ops = { -------------------------------------------------------------------------- */ static int __init bcm63xx_serialinit(void) { - int i, flags; - struct bcm_serial * info; - - // Print the driver version information - printk(VER_STR); - serial_driver = alloc_tty_driver(BCM_NUM_UARTS); - if (!serial_driver) - return -ENOMEM; - - serial_driver->owner = THIS_MODULE; -// serial_driver->devfs_name = "tts/"; -// serial_driver.magic = TTY_DRIVER_MAGIC; - serial_driver->name = "ttyS"; - serial_driver->major = TTY_MAJOR; - serial_driver->minor_start = 64; -// serial_driver.num = BCM_NUM_UARTS; - serial_driver->type = TTY_DRIVER_TYPE_SERIAL; - serial_driver->subtype = SERIAL_TYPE_NORMAL; - serial_driver->init_termios = tty_std_termios; - serial_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; - serial_driver->flags = TTY_DRIVER_REAL_RAW; - - serial_driver->termios = serial_termios; - serial_driver->termios_locked = serial_termios_locked; - - tty_set_operations(serial_driver, &rs_ops); - - if (tty_register_driver (serial_driver)) - panic("Couldn't register serial driver\n"); - - //save_flags(flags); cli(); - spin_lock_irqsave(&bcm963xx_serial_lock, flags); - - for (i = 0; i < BCM_NUM_UARTS; i++) - { - info = &multi[i]; - lines[i] = info; - info->magic = SERIAL_MAGIC; - info->port = (Uart *) ((char *)UART_BASE + (i * 0x20)); - info->tty = 0; - info->irq = (2 - i) + 8; - info->line = i; - info->close_delay = 50; - info->closing_wait = 3000; - info->x_char = 0; - info->event = 0; - info->count = 0; - info->blocked_open = 0; - info->normal_termios = serial_driver->init_termios; - init_waitqueue_head(&info->open_wait); - init_waitqueue_head(&info->close_wait); - - /* If we are pointing to address zero then punt - not correctly - * set up in setup.c to handle this. - */ - if (! info->port) - return 0; - BcmHalMapInterrupt(bcm_interrupt, 0, INTERRUPT_ID_UART); - } - - /* order matters here... the trick is that flags - * is updated... in request_irq - to immediatedly obliterate - * it is unwise. - */ - spin_unlock_irqrestore(&bcm963xx_serial_lock, flags); - return 0; + int i, flags; + struct bcm_serial *info; + + // Print the driver version information + printk(VER_STR); + serial_driver = alloc_tty_driver(BCM_NUM_UARTS); + if (!serial_driver) + return -ENOMEM; + + serial_driver->owner = THIS_MODULE; + serial_driver->name = "ttyS"; + serial_driver->major = TTY_MAJOR; + serial_driver->minor_start = 64; + serial_driver->num = 1; + serial_driver->type = TTY_DRIVER_TYPE_SERIAL; + serial_driver->subtype = SERIAL_TYPE_NORMAL; + serial_driver->init_termios = tty_std_termios; + serial_driver->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver->flags = TTY_DRIVER_REAL_RAW; + + serial_driver->termios = serial_termios; + serial_driver->termios_locked = serial_termios_locked; + + tty_set_operations(serial_driver, &rs_ops); + + if (tty_register_driver(serial_driver)) + panic("Couldn't register serial driver\n"); + + //save_flags(flags); cli(); + spin_lock_irqsave(&bcm963xx_serial_lock, flags); + + for (i = 0; i < 1; i++) { + info = &multi[i]; + lines[i] = info; + info->magic = SERIAL_MAGIC; + info->port = (Uart *) ((char *) UART_BASE + (i * 0x20)); + info->tty = 0; + info->irq = (2 - i) + 8; + info->line = i; + info->close_delay = 50; + info->closing_wait = 3000; + info->x_char = 0; + info->event = 0; + info->count = 0; + info->blocked_open = 0; + info->normal_termios = serial_driver->init_termios; + init_waitqueue_head(&info->open_wait); + init_waitqueue_head(&info->close_wait); + + /* If we are pointing to address zero then punt - not correctly + * set up in setup.c to handle this. + */ + if (!info->port) + return 0; + BcmHalMapInterrupt(bcm_interrupt, 0, INTERRUPT_ID_UART); + } + + /* order matters here... the trick is that flags + * is updated... in request_irq - to immediatedly obliterate + * it is unwise. + */ + spin_unlock_irqrestore(&bcm963xx_serial_lock, flags); + return 0; } module_init(bcm63xx_serialinit); @@ -1007,45 +1000,43 @@ module_init(bcm63xx_serialinit); Purpose: bcm_console_print is registered for printk. The console_lock must be held when we get here. -------------------------------------------------------------------------- */ -static void bcm_console_print (struct console * cons, const char * str, - unsigned int count) +static void bcm_console_print(struct console *cons, const char *str, + unsigned int count) { - unsigned int i; - //_puts(str); - for(i=0; iindex; - return serial_driver; + *index = c->index; + return serial_driver; } -static int __init bcm_console_setup(struct console * co, char * options) +static int __init bcm_console_setup(struct console *co, char *options) { - return 0; + return 0; } static struct console bcm_sercons = { - .name = "ttyS", - .write = bcm_console_print, - .device = bcm_console_device, - .setup = bcm_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, + .name = "ttyS", + .write = bcm_console_print, + .device = bcm_console_device, + .setup = bcm_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, }; static int __init bcm63xx_console_init(void) { - register_console(&bcm_sercons); - return 0; + register_console(&bcm_sercons); + return 0; } console_initcall(bcm63xx_console_init); diff --git a/target/linux/brcm63xx-2.6/files/include/asm-mips/mach-bcm963xx/bootloaders.h b/target/linux/brcm63xx-2.6/files/include/asm-mips/mach-bcm963xx/bootloaders.h index 84eeafe856..e169bb00c0 100644 --- a/target/linux/brcm63xx-2.6/files/include/asm-mips/mach-bcm963xx/bootloaders.h +++ b/target/linux/brcm63xx-2.6/files/include/asm-mips/mach-bcm963xx/bootloaders.h @@ -1,6 +1,7 @@ #define ADSL_SDRAM_IMAGE_SIZE (384*1024) -#define BOOT_LOADER_UNKNOWN 0 -#define BOOT_LOADER_CFE 1 -#define BOOT_LOADER_REDBOOT 2 -#define BOOT_LOADER_LAST 2 +#define BOOT_LOADER_UNKNOWN 0 +#define BOOT_LOADER_CFE 1 +#define BOOT_LOADER_REDBOOT 2 +#define BOOT_LOADER_CFE2 3 +#define BOOT_LOADER_LAST 3 diff --git a/target/linux/brcm63xx-2.6/patches/150-sst_flash.patch b/target/linux/brcm63xx-2.6/patches/150-sst_flash.patch new file mode 100644 index 0000000000..ba9fcb9c31 --- /dev/null +++ b/target/linux/brcm63xx-2.6/patches/150-sst_flash.patch @@ -0,0 +1,36 @@ +diff -urN linux-2.6.19.2/drivers/mtd/chips/jedec_probe.c linux-2.6.19.2.new/drivers/mtd/chips/jedec_probe.c +--- linux-2.6.19.2/drivers/mtd/chips/jedec_probe.c 2007-01-10 20:10:37.000000000 +0100 ++++ linux-2.6.19.2.new/drivers/mtd/chips/jedec_probe.c 2007-04-09 22:33:05.000000000 +0200 +@@ -158,6 +158,7 @@ + #define SST49LF030A 0x001C + #define SST49LF040A 0x0051 + #define SST49LF080A 0x005B ++#define SST39VF6402B 0x236C + + /* Toshiba */ + #define TC58FVT160 0x00C2 +@@ -1494,7 +1495,23 @@ + ERASEINFO(0x1000,256), + ERASEINFO(0x1000,256) + } +- ++ }, { ++ .mfr_id = MANUFACTURER_SST, ++ .dev_id = SST39VF6402B, ++ .name = "SST 39VF6402B", ++ .uaddr = { ++ [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ ++ [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ ++ }, ++ .DevSize = SIZE_8MiB, ++ .CmdSet = P_ID_AMD_STD, ++ .NumEraseRegions= 4, ++ .regions = { ++ ERASEINFO(0x2000,256), ++ ERASEINFO(0x2000,256), ++ ERASEINFO(0x2000,256), ++ ERASEINFO(0x2000,256) ++ } + }, { + .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ + .dev_id = M29W800DT, -- cgit v1.2.3