diff options
Diffstat (limited to 'drivers/serial')
-rw-r--r-- | drivers/serial/8250.c | 20 | ||||
-rw-r--r-- | drivers/serial/8250_early.c | 23 | ||||
-rw-r--r-- | drivers/serial/8250_gsc.c | 17 | ||||
-rw-r--r-- | drivers/serial/8250_hp300.c | 35 | ||||
-rw-r--r-- | drivers/serial/8250_hub6.c | 24 | ||||
-rw-r--r-- | drivers/serial/8250_pci.c | 109 | ||||
-rw-r--r-- | drivers/serial/Kconfig | 15 | ||||
-rw-r--r-- | drivers/serial/atmel_serial.c | 884 | ||||
-rw-r--r-- | drivers/serial/serial_core.c | 59 |
9 files changed, 877 insertions, 309 deletions
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index b8a4bd94f51d..77f7a7f0646e 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -305,7 +305,7 @@ static inline int map_8250_out_reg(struct uart_8250_port *up, int offset) return au_io_out_map[offset]; } -#elif defined (CONFIG_SERIAL_8250_RM9K) +#elif defined(CONFIG_SERIAL_8250_RM9K) static const u8 regmap_in[8] = { @@ -475,7 +475,7 @@ static inline void _serial_dl_write(struct uart_8250_port *up, int value) serial_outp(up, UART_DLM, value >> 8 & 0xff); } -#if defined (CONFIG_SERIAL_8250_AU1X00) +#if defined(CONFIG_SERIAL_8250_AU1X00) /* Au1x00 haven't got a standard divisor latch */ static int serial_dl_read(struct uart_8250_port *up) { @@ -492,7 +492,7 @@ static void serial_dl_write(struct uart_8250_port *up, int value) else _serial_dl_write(up, value); } -#elif defined (CONFIG_SERIAL_8250_RM9K) +#elif defined(CONFIG_SERIAL_8250_RM9K) static int serial_dl_read(struct uart_8250_port *up) { return (up->port.iotype == UPIO_RM9000) ? @@ -1185,8 +1185,8 @@ static void autoconfig_irq(struct uart_8250_port *up) irqs = probe_irq_on(); serial_outp(up, UART_MCR, 0); - udelay (10); - if (up->port.flags & UPF_FOURPORT) { + udelay(10); + if (up->port.flags & UPF_FOURPORT) { serial_outp(up, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); } else { @@ -1199,7 +1199,7 @@ static void autoconfig_irq(struct uart_8250_port *up) (void)serial_inp(up, UART_IIR); (void)serial_inp(up, UART_MSR); serial_outp(up, UART_TX, 0xFF); - udelay (20); + udelay(20); irq = probe_irq_off(irqs); serial_outp(up, UART_MCR, save_mcr); @@ -1343,7 +1343,7 @@ receive_chars(struct uart_8250_port *up, unsigned int *status) uart_insert_char(&up->port, lsr, UART_LSR_OE, ch, flag); - ignore_char: +ignore_char: lsr = serial_inp(up, UART_LSR); } while ((lsr & UART_LSR_DR) && (max_count-- > 0)); spin_unlock(&up->port.lock); @@ -1633,7 +1633,8 @@ static void serial8250_backup_timeout(unsigned long data) serial_out(up, UART_IER, ier); /* Standard timer interval plus 0.2s to keep the port running */ - mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout) + HZ/5); + mod_timer(&up->timer, + jiffies + poll_timeout(up->port.timeout) + HZ / 5); } static unsigned int serial8250_tx_empty(struct uart_port *port) @@ -1844,7 +1845,7 @@ static int serial8250_startup(struct uart_port *port) up->timer.function = serial8250_backup_timeout; up->timer.data = (unsigned long)up; mod_timer(&up->timer, jiffies + - poll_timeout(up->port.timeout) + HZ/5); + poll_timeout(up->port.timeout) + HZ / 5); } } @@ -2173,6 +2174,7 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios, } serial8250_set_mctrl(&up->port, up->port.mctrl); spin_unlock_irqrestore(&up->port.lock, flags); + tty_termios_encode_baud_rate(termios, baud, baud); } static void diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c index 1f16de719962..38776e8b064b 100644 --- a/drivers/serial/8250_early.c +++ b/drivers/serial/8250_early.c @@ -82,7 +82,8 @@ static void __init serial_putc(struct uart_port *port, int c) serial_out(port, UART_TX, c); } -static void __init early_serial8250_write(struct console *console, const char *s, unsigned int count) +static void __init early_serial8250_write(struct console *console, + const char *s, unsigned int count) { struct uart_port *port = &early_device.port; unsigned int ier; @@ -132,7 +133,8 @@ static void __init init_port(struct early_serial8250_device *device) serial_out(port, UART_LCR, c & ~UART_LCR_DLAB); } -static int __init parse_options(struct early_serial8250_device *device, char *options) +static int __init parse_options(struct early_serial8250_device *device, + char *options) { struct uart_port *port = &device->port; int mmio, length; @@ -145,8 +147,10 @@ static int __init parse_options(struct early_serial8250_device *device, char *op port->iotype = UPIO_MEM; port->mapbase = simple_strtoul(options + 5, &options, 0); #ifdef CONFIG_FIX_EARLYCON_MEM - set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, port->mapbase & PAGE_MASK); - port->membase = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); + set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, + port->mapbase & PAGE_MASK); + port->membase = + (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); port->membase += port->mapbase & ~PAGE_MASK; #else port->membase = ioremap(port->mapbase, 64); @@ -165,7 +169,8 @@ static int __init parse_options(struct early_serial8250_device *device, char *op } else return -EINVAL; - if ((options = strchr(options, ','))) { + options = strchr(options, ','); + if (options) { options++; device->baud = simple_strtoul(options, NULL, 0); length = min(strcspn(options, " "), sizeof(device->options)); @@ -179,7 +184,7 @@ static int __init parse_options(struct early_serial8250_device *device, char *op printk(KERN_INFO "Early serial console at %s 0x%llx (options '%s')\n", mmio ? "MMIO" : "I/O port", mmio ? (unsigned long long) port->mapbase - : (unsigned long long) port->iobase, + : (unsigned long long) port->iobase, device->options); return 0; } @@ -199,7 +204,8 @@ static int __init early_serial8250_setup(char *options) if (device->port.membase || device->port.iobase) return 0; - if ((err = parse_options(device, options)) < 0) + err = parse_options(device, options); + if (err < 0) return err; init_port(device); @@ -219,7 +225,8 @@ int __init setup_early_serial8250_console(char *cmdline) } options = strchr(cmdline, ',') + 1; - if ((err = early_serial8250_setup(options)) < 0) + err = early_serial8250_setup(options); + if (err < 0) return err; register_console(&early_serial8250_console); diff --git a/drivers/serial/8250_gsc.c b/drivers/serial/8250_gsc.c index c5d0addfda4f..4eb7437a404a 100644 --- a/drivers/serial/8250_gsc.c +++ b/drivers/serial/8250_gsc.c @@ -25,8 +25,7 @@ #include "8250.h" -static int __init -serial_init_chip(struct parisc_device *dev) +static int __init serial_init_chip(struct parisc_device *dev) { struct uart_port port; unsigned long address; @@ -38,18 +37,17 @@ serial_init_chip(struct parisc_device *dev) * what we have here is a missing parent device, so tell * the user what they're missing. */ - if (parisc_parent(dev)->id.hw_type != HPHW_IOA) { - printk(KERN_INFO "Serial: device 0x%lx not configured.\n" + if (parisc_parent(dev)->id.hw_type != HPHW_IOA) + printk(KERN_INFO + "Serial: device 0x%lx not configured.\n" "Enable support for Wax, Lasi, Asp or Dino.\n", dev->hpa.start); - } return -ENODEV; } address = dev->hpa.start; - if (dev->id.sversion != 0x8d) { + if (dev->id.sversion != 0x8d) address += 0x800; - } memset(&port, 0, sizeof(port)); port.iotype = UPIO_MEM; @@ -63,11 +61,12 @@ serial_init_chip(struct parisc_device *dev) err = serial8250_register_port(&port); if (err < 0) { - printk(KERN_WARNING "serial8250_register_port returned error %d\n", err); + printk(KERN_WARNING + "serial8250_register_port returned error %d\n", err); iounmap(port.membase); return err; } - + return 0; } diff --git a/drivers/serial/8250_hp300.c b/drivers/serial/8250_hp300.c index 2cf0953fe0ec..0e1410f2c033 100644 --- a/drivers/serial/8250_hp300.c +++ b/drivers/serial/8250_hp300.c @@ -36,7 +36,7 @@ static struct hp300_port *hp300_ports; #ifdef CONFIG_HPDCA static int __devinit hpdca_init_one(struct dio_dev *d, - const struct dio_device_id *ent); + const struct dio_device_id *ent); static void __devexit hpdca_remove_one(struct dio_dev *d); static struct dio_device_id hpdca_dio_tbl[] = { @@ -85,7 +85,7 @@ extern int hp300_uart_scode; #ifdef CONFIG_SERIAL_8250_CONSOLE /* - * Parse the bootinfo to find descriptions for headless console and + * Parse the bootinfo to find descriptions for headless console and * debug serial ports and register them with the 8250 driver. * This function should be called before serial_console_init() is called * to make sure the serial console will be available for use. IA-64 kernel @@ -126,13 +126,11 @@ int __init hp300_setup_serial_console(void) printk(KERN_WARNING "Serial console is APCI but support is disabled (CONFIG_HPAPCI)!\n"); return 0; #endif - } - else { + } else { #ifdef CONFIG_HPDCA unsigned long pa = dio_scodetophysaddr(scode); - if (!pa) { + if (!pa) return 0; - } printk(KERN_INFO "Serial console is HP DCA at select code %d\n", scode); @@ -145,26 +143,23 @@ int __init hp300_setup_serial_console(void) /* Enable board-interrupts */ out_8(pa + DIO_VIRADDRBASE + DCA_IC, DCA_IC_IE); - if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80) { + if (DIO_ID(pa + DIO_VIRADDRBASE) & 0x80) add_preferred_console("ttyS", port.line, "9600n8"); - } #else printk(KERN_WARNING "Serial console is DCA but support is disabled (CONFIG_HPDCA)!\n"); return 0; #endif } - if (early_serial_setup(&port) < 0) { + if (early_serial_setup(&port) < 0) printk(KERN_WARNING "hp300_setup_serial_console(): early_serial_setup() failed.\n"); - } - return 0; } #endif /* CONFIG_SERIAL_8250_CONSOLE */ #ifdef CONFIG_HPDCA static int __devinit hpdca_init_one(struct dio_dev *d, - const struct dio_device_id *ent) + const struct dio_device_id *ent) { struct uart_port port; int line; @@ -210,7 +205,7 @@ static int __devinit hpdca_init_one(struct dio_dev *d, static int __init hp300_8250_init(void) { - static int called = 0; + static int called; #ifdef CONFIG_HPAPCI int line; unsigned long base; @@ -239,13 +234,12 @@ static int __init hp300_8250_init(void) * Port 1 is either the console or the DCA. */ for (i = 1; i < 4; i++) { - /* Port 1 is the console on a 425e, on other machines it's mapped to - * DCA. + /* Port 1 is the console on a 425e, on other machines it's + * mapped to DCA. */ #ifdef CONFIG_SERIAL_8250_CONSOLE - if (i == 1) { + if (i == 1) continue; - } #endif /* Create new serial device */ @@ -259,7 +253,8 @@ static int __init hp300_8250_init(void) /* Memory mapped I/O */ uport.iotype = UPIO_MEM; - uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF; + uport.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ \ + | UPF_BOOT_AUTOCONF; /* XXX - no interrupt support yet */ uport.irq = 0; uport.uartclk = HPAPCI_BAUD_BASE * 16; @@ -270,8 +265,8 @@ static int __init hp300_8250_init(void) line = serial8250_register_port(&uport); if (line < 0) { - printk(KERN_NOTICE "8250_hp300: register_serial() APCI %d" - " irq %d failed\n", i, uport.irq); + printk(KERN_NOTICE "8250_hp300: register_serial() APCI" + " %d irq %d failed\n", i, uport.irq); kfree(port); continue; } diff --git a/drivers/serial/8250_hub6.c b/drivers/serial/8250_hub6.c index daf569cd3c8f..7609150e7d5e 100644 --- a/drivers/serial/8250_hub6.c +++ b/drivers/serial/8250_hub6.c @@ -23,18 +23,18 @@ } static struct plat_serial8250_port hub6_data[] = { - HUB6(0,0), - HUB6(0,1), - HUB6(0,2), - HUB6(0,3), - HUB6(0,4), - HUB6(0,5), - HUB6(1,0), - HUB6(1,1), - HUB6(1,2), - HUB6(1,3), - HUB6(1,4), - HUB6(1,5), + HUB6(0, 0), + HUB6(0, 1), + HUB6(0, 2), + HUB6(0, 3), + HUB6(0, 4), + HUB6(0, 5), + HUB6(1, 0), + HUB6(1, 1), + HUB6(1, 2), + HUB6(1, 3), + HUB6(1, 4), + HUB6(1, 5), { }, }; diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c index 0a4ac2b6eb5a..a8bec498cad6 100644 --- a/drivers/serial/8250_pci.c +++ b/drivers/serial/8250_pci.c @@ -140,7 +140,7 @@ afavlab_setup(struct serial_private *priv, struct pciserial_board *board, struct uart_port *port, int idx) { unsigned int bar, offset = board->first_offset; - + bar = FL_GET_BASE(board->flags); if (idx < 4) bar += idx; @@ -227,8 +227,8 @@ static int pci_inteli960ni_init(struct pci_dev *dev) return -ENODEV; /* is firmware started? */ - pci_read_config_dword(dev, 0x44, (void*) &oldval); - if (oldval == 0x00001000L) { /* RESET value */ + pci_read_config_dword(dev, 0x44, (void *)&oldval); + if (oldval == 0x00001000L) { /* RESET value */ printk(KERN_DEBUG "Local i960 firmware missing"); return -ENODEV; } @@ -253,11 +253,11 @@ static int pci_plx9050_init(struct pci_dev *dev) irq_config = 0x41; if (dev->vendor == PCI_VENDOR_ID_PANACOM || - dev->subsystem_vendor == PCI_SUBVENDOR_ID_EXSYS) { + dev->subsystem_vendor == PCI_SUBVENDOR_ID_EXSYS) irq_config = 0x43; - } + if ((dev->vendor == PCI_VENDOR_ID_PLX) && - (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) { + (dev->device == PCI_DEVICE_ID_PLX_ROMULUS)) /* * As the megawolf cards have the int pins active * high, and have 2 UART chips, both ints must be @@ -267,8 +267,6 @@ static int pci_plx9050_init(struct pci_dev *dev) * deep FIFOs */ irq_config = 0x5b; - } - /* * enable/disable interrupts */ @@ -343,14 +341,14 @@ static int sbs_init(struct pci_dev *dev) { u8 __iomem *p; - p = ioremap(pci_resource_start(dev, 0),pci_resource_len(dev,0)); + p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); if (p == NULL) return -ENOMEM; /* Set bit-4 Control Register (UART RESET) in to reset the uarts */ - writeb(0x10,p + OCT_REG_CR_OFF); + writeb(0x10, p + OCT_REG_CR_OFF); udelay(50); - writeb(0x0,p + OCT_REG_CR_OFF); + writeb(0x0, p + OCT_REG_CR_OFF); /* Set bit-2 (INTENABLE) of Control Register */ writeb(0x4, p + OCT_REG_CR_OFF); @@ -367,10 +365,10 @@ static void __devexit sbs_exit(struct pci_dev *dev) { u8 __iomem *p; - p = ioremap(pci_resource_start(dev, 0),pci_resource_len(dev,0)); - if (p != NULL) { + p = ioremap(pci_resource_start(dev, 0), pci_resource_len(dev, 0)); + /* FIXME: What if resource_len < OCT_REG_CR_OFF */ + if (p != NULL) writeb(0, p + OCT_REG_CR_OFF); - } iounmap(p); } @@ -386,7 +384,7 @@ static void __devexit sbs_exit(struct pci_dev *dev) * with other OSes (like M$ DOS). * * SIIG support added by Andrey Panin <pazke@donpac.ru>, 10/1999 - * + * * There is two family of SIIG serial cards with different PCI * interface chip and different configuration methods: * - 10x cards have control registers in IO and/or memory space; @@ -489,21 +487,21 @@ static const unsigned short timedia_single_port[] = { static const unsigned short timedia_dual_port[] = { 0x0002, 0x4036, 0x4037, 0x4038, 0x4078, 0x4079, 0x4085, - 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, - 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, + 0x4088, 0x4089, 0x5037, 0x5078, 0x5079, 0x5085, 0x6079, + 0x7079, 0x8079, 0x8137, 0x8138, 0x8237, 0x8238, 0x9079, 0x9137, 0x9138, 0x9237, 0x9238, 0xA079, 0xB079, 0xC079, 0xD079, 0 }; static const unsigned short timedia_quad_port[] = { - 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, - 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, + 0x4055, 0x4056, 0x4095, 0x4096, 0x5056, 0x8156, 0x8157, + 0x8256, 0x8257, 0x9056, 0x9156, 0x9157, 0x9158, 0x9159, 0x9256, 0x9257, 0xA056, 0xA157, 0xA158, 0xA159, 0xB056, 0xB157, 0 }; static const unsigned short timedia_eight_port[] = { - 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, + 0x4065, 0x4066, 0x5065, 0x5066, 0x8166, 0x9066, 0x9166, 0x9167, 0x9168, 0xA066, 0xA167, 0xA168, 0 }; @@ -656,7 +654,8 @@ static int pci_ite887x_init(struct pci_dev *dev) ITE_887x_POSIO_ENABLE | ITE_887x_POSIO_SPEED | ITE_887x_POSIO_IOSIZE_32 | inta_addr[i]); /* write INTCBAR - ioport */ - pci_write_config_dword(dev, ITE_887x_INTCBAR, inta_addr[i]); + pci_write_config_dword(dev, ITE_887x_INTCBAR, + inta_addr[i]); ret = inb(inta_addr[i]); if (ret != 0xff) { /* ioport connected */ @@ -755,7 +754,7 @@ pci_default_setup(struct serial_private *priv, struct pciserial_board *board, if (board->flags & FL_REGION_SZ_CAP && idx >= maxnr) return 1; - + return setup_port(priv, port, bar, offset, board->reg_shift); } @@ -843,7 +842,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = { .init = pci_plx9050_init, .setup = pci_default_setup, .exit = __devexit_p(pci_plx9050_exit), - }, + }, { .vendor = PCI_VENDOR_ID_PANACOM, .device = PCI_DEVICE_ID_PANACOM_DUALMODEM, @@ -1032,7 +1031,7 @@ static struct pci_serial_quirk *find_quirk(struct pci_dev *dev) quirk_id_matches(quirk->device, dev->device) && quirk_id_matches(quirk->subvendor, dev->subsystem_vendor) && quirk_id_matches(quirk->subdevice, dev->subsystem_device)) - break; + break; return quirk; } @@ -1711,7 +1710,7 @@ static struct pciserial_board pci_boards[] __devinitdata = { }; static const struct pci_device_id softmodem_blacklist[] = { - { PCI_VDEVICE ( AL, 0x5457 ), }, /* ALi Corporation M5457 AC'97 Modem */ + { PCI_VDEVICE(AL, 0x5457), }, /* ALi Corporation M5457 AC'97 Modem */ }; /* @@ -1724,13 +1723,13 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) { const struct pci_device_id *blacklist; int num_iomem, num_port, first_port = -1, i; - + /* * If it is not a communications device or the programming * interface is greater than 6, give up. * * (Should we try to make guesses for multiport serial devices - * later?) + * later?) */ if ((((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL) && ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_MODEM)) || @@ -1863,25 +1862,23 @@ pciserial_init_ports(struct pci_dev *dev, struct pciserial_board *board) break; #ifdef SERIAL_DEBUG_PCI - printk("Setup PCI port: port %x, irq %d, type %d\n", + printk(KERN_DEBUG "Setup PCI port: port %x, irq %d, type %d\n", serial_port.iobase, serial_port.irq, serial_port.iotype); #endif - + priv->line[i] = serial8250_register_port(&serial_port); if (priv->line[i] < 0) { printk(KERN_WARNING "Couldn't register serial port %s: %d\n", pci_name(dev), priv->line[i]); break; } } - priv->nr = i; - return priv; - err_deinit: +err_deinit: if (quirk->exit) quirk->exit(dev); - err_out: +err_out: return priv; } EXPORT_SYMBOL_GPL(pciserial_init_ports); @@ -2171,22 +2168,22 @@ static struct pci_device_id serial_pci_tbl[] = { pbn_b0_8_1843200_200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_1_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_2_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_4_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_2_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_bt_4_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_8_115200 }, { PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, @@ -2201,11 +2198,11 @@ static struct pci_device_id serial_pci_tbl[] = { /* * VScom SPCOM800, from sl@s.pl */ - { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_8_921600 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_1077, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b2_4_921600 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_KEYSPAN, @@ -2223,27 +2220,27 @@ static struct pci_device_id serial_pci_tbl[] = { pbn_b2_4_115200 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, + PCI_SUBDEVICE_ID_CHASE_PCIFAST4, 0, 0, pbn_b2_4_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, + PCI_SUBDEVICE_ID_CHASE_PCIFAST8, 0, 0, pbn_b2_8_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16, 0, 0, pbn_b2_16_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIFAST, - PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, + PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC, 0, 0, pbn_b2_16_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIRAS, - PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, + PCI_SUBDEVICE_ID_CHASE_PCIRAS4, 0, 0, pbn_b2_4_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_CHASE_PCIRAS, - PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, + PCI_SUBDEVICE_ID_CHASE_PCIRAS8, 0, 0, pbn_b2_8_460800 }, { PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050, PCI_SUBVENDOR_ID_EXSYS, @@ -2269,10 +2266,12 @@ static struct pci_device_id serial_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b1_8_115200 }, { PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, 0, 0, + PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4, + 0, 0, pbn_b0_4_921600 }, { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954, - PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL, 0, 0, + PCI_SUBVENDOR_ID_SIIG, PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL, + 0, 0, pbn_b0_4_1152000 }, /* @@ -2312,7 +2311,7 @@ static struct pci_device_id serial_pci_tbl[] = { * Digitan DS560-558, from jimd@esoft.com */ { PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b1_1_115200 }, /* @@ -2320,16 +2319,16 @@ static struct pci_device_id serial_pci_tbl[] = { * The 400L and 800L have a custom setup quirk. */ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_1_921600 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_2_921600 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_4_921600 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_b0_4_921600 }, { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100L, PCI_ANY_ID, PCI_ANY_ID, 0, 0, diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 84a054d7e986..b82595cf13e8 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -380,6 +380,21 @@ config SERIAL_ATMEL_CONSOLE console is the device which receives all kernel messages and warnings and which allows logins in single user mode). +config SERIAL_ATMEL_PDC + bool "Support DMA transfers on AT91 / AT32 serial port" + depends on SERIAL_ATMEL + default y + help + Say Y here if you wish to use the PDC to do DMA transfers to + and from the Atmel AT91 / AT32 serial port. In order to + actually use DMA transfers, make sure that the use_dma_tx + and use_dma_rx members in the atmel_uart_data struct is set + appropriately for each port. + + Note that break and error handling currently doesn't work + properly when DMA is enabled. Make sure that ports where + this matters don't use DMA. + config SERIAL_ATMEL_TTYAT bool "Install as device ttyATn instead of ttySn" depends on SERIAL_ATMEL=y diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 60f52904aad0..fad245b064d6 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -7,6 +7,8 @@ * Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd. * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. * + * DMA support added by Chip Coldwell. + * * 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 @@ -33,6 +35,7 @@ #include <linux/sysrq.h> #include <linux/tty_flip.h> #include <linux/platform_device.h> +#include <linux/dma-mapping.h> #include <linux/atmel_pdc.h> #include <linux/atmel_serial.h> @@ -46,6 +49,10 @@ #include <asm/arch/gpio.h> #endif +#define PDC_BUFFER_SIZE 512 +/* Revisit: We should calculate this based on the actual port settings */ +#define PDC_RX_TIMEOUT (3 * 10) /* 3 bytes */ + #if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif @@ -73,6 +80,7 @@ #define ATMEL_ISR_PASS_LIMIT 256 +/* UART registers. CR is write-only, hence no GET macro */ #define UART_PUT_CR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_CR) #define UART_GET_MR(port) __raw_readl((port)->membase + ATMEL_US_MR) #define UART_PUT_MR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_MR) @@ -86,8 +94,6 @@ #define UART_PUT_BRGR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_BRGR) #define UART_PUT_RTOR(port,v) __raw_writel(v, (port)->membase + ATMEL_US_RTOR) -// #define UART_GET_CR(port) __raw_readl((port)->membase + ATMEL_US_CR) // is write-only - /* PDC registers */ #define UART_PUT_PTCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_PTCR) #define UART_GET_PTSR(port) __raw_readl((port)->membase + ATMEL_PDC_PTSR) @@ -100,12 +106,24 @@ #define UART_PUT_TPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TPR) #define UART_PUT_TCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TCR) -//#define UART_PUT_TNPR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TNPR) -//#define UART_PUT_TNCR(port,v) __raw_writel(v, (port)->membase + ATMEL_PDC_TNCR) static int (*atmel_open_hook)(struct uart_port *); static void (*atmel_close_hook)(struct uart_port *); +struct atmel_dma_buffer { + unsigned char *buf; + dma_addr_t dma_addr; + unsigned int dma_size; + unsigned int ofs; +}; + +struct atmel_uart_char { + u16 status; + u16 ch; +}; + +#define ATMEL_SERIAL_RINGSIZE 1024 + /* * We wrap our port structure around the generic uart_port. */ @@ -114,6 +132,19 @@ struct atmel_uart_port { struct clk *clk; /* uart clock */ unsigned short suspended; /* is port suspended? */ int break_active; /* break being received */ + + short use_dma_rx; /* enable PDC receiver */ + short pdc_rx_idx; /* current PDC RX buffer */ + struct atmel_dma_buffer pdc_rx[2]; /* PDC receier */ + + short use_dma_tx; /* enable PDC transmitter */ + struct atmel_dma_buffer pdc_tx; /* PDC transmitter */ + + struct tasklet_struct tasklet; + unsigned int irq_status; + unsigned int irq_status_prev; + + struct circ_buf rx_ring; }; static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; @@ -122,6 +153,38 @@ static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; static struct console atmel_console; #endif +static inline struct atmel_uart_port * +to_atmel_uart_port(struct uart_port *uart) +{ + return container_of(uart, struct atmel_uart_port, uart); +} + +#ifdef CONFIG_SERIAL_ATMEL_PDC +static bool atmel_use_dma_rx(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + return atmel_port->use_dma_rx; +} + +static bool atmel_use_dma_tx(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + return atmel_port->use_dma_tx; +} +#else +static bool atmel_use_dma_rx(struct uart_port *port) +{ + return false; +} + +static bool atmel_use_dma_tx(struct uart_port *port) +{ + return false; +} +#endif + /* * Return TIOCSER_TEMT when transmitter FIFO and Shift register is empty. */ @@ -141,8 +204,8 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl) #ifdef CONFIG_ARCH_AT91RM9200 if (cpu_is_at91rm9200()) { /* - * AT91RM9200 Errata #39: RTS0 is not internally connected to PA21. - * We need to drive the pin manually. + * AT91RM9200 Errata #39: RTS0 is not internally connected + * to PA21. We need to drive the pin manually. */ if (port->mapbase == AT91RM9200_BASE_US0) { if (mctrl & TIOCM_RTS) @@ -203,7 +266,12 @@ static u_int atmel_get_mctrl(struct uart_port *port) */ static void atmel_stop_tx(struct uart_port *port) { - UART_PUT_IDR(port, ATMEL_US_TXRDY); + if (atmel_use_dma_tx(port)) { + /* disable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); + } else + UART_PUT_IDR(port, ATMEL_US_TXRDY); } /* @@ -211,7 +279,17 @@ static void atmel_stop_tx(struct uart_port *port) */ static void atmel_start_tx(struct uart_port *port) { - UART_PUT_IER(port, ATMEL_US_TXRDY); + if (atmel_use_dma_tx(port)) { + if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN) + /* The transmitter is already running. Yes, we + really need this.*/ + return; + + UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); + /* re-enable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + } else + UART_PUT_IER(port, ATMEL_US_TXRDY); } /* @@ -219,7 +297,12 @@ static void atmel_start_tx(struct uart_port *port) */ static void atmel_stop_rx(struct uart_port *port) { - UART_PUT_IDR(port, ATMEL_US_RXRDY); + if (atmel_use_dma_rx(port)) { + /* disable PDC receive */ + UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS); + UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + } else + UART_PUT_IDR(port, ATMEL_US_RXRDY); } /* @@ -227,7 +310,8 @@ static void atmel_stop_rx(struct uart_port *port) */ static void atmel_enable_ms(struct uart_port *port) { - UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC); + UART_PUT_IER(port, ATMEL_US_RIIC | ATMEL_US_DSRIC + | ATMEL_US_DCDIC | ATMEL_US_CTSIC); } /* @@ -242,22 +326,63 @@ static void atmel_break_ctl(struct uart_port *port, int break_state) } /* + * Stores the incoming character in the ring buffer + */ +static void +atmel_buffer_rx_char(struct uart_port *port, unsigned int status, + unsigned int ch) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct circ_buf *ring = &atmel_port->rx_ring; + struct atmel_uart_char *c; + + if (!CIRC_SPACE(ring->head, ring->tail, ATMEL_SERIAL_RINGSIZE)) + /* Buffer overflow, ignore char */ + return; + + c = &((struct atmel_uart_char *)ring->buf)[ring->head]; + c->status = status; + c->ch = ch; + + /* Make sure the character is stored before we update head. */ + smp_wmb(); + + ring->head = (ring->head + 1) & (ATMEL_SERIAL_RINGSIZE - 1); +} + +/* + * Deal with parity, framing and overrun errors. + */ +static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status) +{ + /* clear error */ + UART_PUT_CR(port, ATMEL_US_RSTSTA); + + if (status & ATMEL_US_RXBRK) { + /* ignore side-effect */ + status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); + port->icount.brk++; + } + if (status & ATMEL_US_PARE) + port->icount.parity++; + if (status & ATMEL_US_FRAME) + port->icount.frame++; + if (status & ATMEL_US_OVRE) + port->icount.overrun++; +} + +/* * Characters received (called from interrupt handler) */ static void atmel_rx_chars(struct uart_port *port) { - struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; - struct tty_struct *tty = port->info->tty; - unsigned int status, ch, flg; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + unsigned int status, ch; status = UART_GET_CSR(port); while (status & ATMEL_US_RXRDY) { ch = UART_GET_CHAR(port); - port->icount.rx++; - - flg = TTY_NORMAL; - /* * note that the error handling code is * out of the main execution path @@ -265,15 +390,14 @@ static void atmel_rx_chars(struct uart_port *port) if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME | ATMEL_US_OVRE | ATMEL_US_RXBRK) || atmel_port->break_active)) { - UART_PUT_CR(port, ATMEL_US_RSTSTA); /* clear error */ + + /* clear error */ + UART_PUT_CR(port, ATMEL_US_RSTSTA); + if (status & ATMEL_US_RXBRK && !atmel_port->break_active) { - status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */ - port->icount.brk++; atmel_port->break_active = 1; UART_PUT_IER(port, ATMEL_US_RXBRK); - if (uart_handle_break(port)) - goto ignore_char; } else { /* * This is either the end-of-break @@ -286,52 +410,30 @@ static void atmel_rx_chars(struct uart_port *port) status &= ~ATMEL_US_RXBRK; atmel_port->break_active = 0; } - if (status & ATMEL_US_PARE) - port->icount.parity++; - if (status & ATMEL_US_FRAME) - port->icount.frame++; - if (status & ATMEL_US_OVRE) - port->icount.overrun++; - - status &= port->read_status_mask; - - if (status & ATMEL_US_RXBRK) - flg = TTY_BREAK; - else if (status & ATMEL_US_PARE) - flg = TTY_PARITY; - else if (status & ATMEL_US_FRAME) - flg = TTY_FRAME; } - if (uart_handle_sysrq_char(port, ch)) - goto ignore_char; - - uart_insert_char(port, status, ATMEL_US_OVRE, ch, flg); - - ignore_char: + atmel_buffer_rx_char(port, status, ch); status = UART_GET_CSR(port); } - tty_flip_buffer_push(tty); + tasklet_schedule(&atmel_port->tasklet); } /* - * Transmit characters (called from interrupt handler) + * Transmit characters (called from tasklet with TXRDY interrupt + * disabled) */ static void atmel_tx_chars(struct uart_port *port) { struct circ_buf *xmit = &port->info->xmit; - if (port->x_char) { + if (port->x_char && UART_GET_CSR(port) & ATMEL_US_TXRDY) { UART_PUT_CHAR(port, port->x_char); port->icount.tx++; port->x_char = 0; - return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { - atmel_stop_tx(port); + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) return; - } while (UART_GET_CSR(port) & ATMEL_US_TXRDY) { UART_PUT_CHAR(port, xmit->buf[xmit->tail]); @@ -344,8 +446,88 @@ static void atmel_tx_chars(struct uart_port *port) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) - atmel_stop_tx(port); + if (!uart_circ_empty(xmit)) + UART_PUT_IER(port, ATMEL_US_TXRDY); +} + +/* + * receive interrupt handler. + */ +static void +atmel_handle_receive(struct uart_port *port, unsigned int pending) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (atmel_use_dma_rx(port)) { + /* + * PDC receive. Just schedule the tasklet and let it + * figure out the details. + * + * TODO: We're not handling error flags correctly at + * the moment. + */ + if (pending & (ATMEL_US_ENDRX | ATMEL_US_TIMEOUT)) { + UART_PUT_IDR(port, (ATMEL_US_ENDRX + | ATMEL_US_TIMEOUT)); + tasklet_schedule(&atmel_port->tasklet); + } + + if (pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | + ATMEL_US_FRAME | ATMEL_US_PARE)) + atmel_pdc_rxerr(port, pending); + } + + /* Interrupt receive */ + if (pending & ATMEL_US_RXRDY) + atmel_rx_chars(port); + else if (pending & ATMEL_US_RXBRK) { + /* + * End of break detected. If it came along with a + * character, atmel_rx_chars will handle it. + */ + UART_PUT_CR(port, ATMEL_US_RSTSTA); + UART_PUT_IDR(port, ATMEL_US_RXBRK); + atmel_port->break_active = 0; + } +} + +/* + * transmit interrupt handler. (Transmit is IRQF_NODELAY safe) + */ +static void +atmel_handle_transmit(struct uart_port *port, unsigned int pending) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (atmel_use_dma_tx(port)) { + /* PDC transmit */ + if (pending & (ATMEL_US_ENDTX | ATMEL_US_TXBUFE)) { + UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); + tasklet_schedule(&atmel_port->tasklet); + } + } else { + /* Interrupt transmit */ + if (pending & ATMEL_US_TXRDY) { + UART_PUT_IDR(port, ATMEL_US_TXRDY); + tasklet_schedule(&atmel_port->tasklet); + } + } +} + +/* + * status flags interrupt handler. + */ +static void +atmel_handle_status(struct uart_port *port, unsigned int pending, + unsigned int status) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + + if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC + | ATMEL_US_CTSIC)) { + atmel_port->irq_status = status; + tasklet_schedule(&atmel_port->tasklet); + } } /* @@ -354,47 +536,255 @@ static void atmel_tx_chars(struct uart_port *port) static irqreturn_t atmel_interrupt(int irq, void *dev_id) { struct uart_port *port = dev_id; - struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; unsigned int status, pending, pass_counter = 0; - status = UART_GET_CSR(port); - pending = status & UART_GET_IMR(port); - while (pending) { - /* Interrupt receive */ - if (pending & ATMEL_US_RXRDY) - atmel_rx_chars(port); - else if (pending & ATMEL_US_RXBRK) { + do { + status = UART_GET_CSR(port); + pending = status & UART_GET_IMR(port); + if (!pending) + break; + + atmel_handle_receive(port, pending); + atmel_handle_status(port, pending, status); + atmel_handle_transmit(port, pending); + } while (pass_counter++ < ATMEL_ISR_PASS_LIMIT); + + return IRQ_HANDLED; +} + +/* + * Called from tasklet with ENDTX and TXBUFE interrupts disabled. + */ +static void atmel_tx_dma(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct circ_buf *xmit = &port->info->xmit; + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; + int count; + + xmit->tail += pdc->ofs; + xmit->tail &= UART_XMIT_SIZE - 1; + + port->icount.tx += pdc->ofs; + pdc->ofs = 0; + + if (!uart_circ_empty(xmit)) { + /* more to transmit - setup next transfer */ + + /* disable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + dma_sync_single_for_device(port->dev, + pdc->dma_addr, + pdc->dma_size, + DMA_TO_DEVICE); + + count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + pdc->ofs = count; + + UART_PUT_TPR(port, pdc->dma_addr + xmit->tail); + UART_PUT_TCR(port, count); + /* re-enable PDC transmit and interrupts */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTEN); + UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE); + } else { + /* nothing left to transmit - disable the transmitter */ + + /* disable PDC transmit */ + UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS); + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static void atmel_rx_from_ring(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct circ_buf *ring = &atmel_port->rx_ring; + unsigned int flg; + unsigned int status; + + while (ring->head != ring->tail) { + struct atmel_uart_char c; + + /* Make sure c is loaded after head. */ + smp_rmb(); + + c = ((struct atmel_uart_char *)ring->buf)[ring->tail]; + + ring->tail = (ring->tail + 1) & (ATMEL_SERIAL_RINGSIZE - 1); + + port->icount.rx++; + status = c.status; + flg = TTY_NORMAL; + + /* + * note that the error handling code is + * out of the main execution path + */ + if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME + | ATMEL_US_OVRE | ATMEL_US_RXBRK))) { + if (status & ATMEL_US_RXBRK) { + /* ignore side-effect */ + status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); + + port->icount.brk++; + if (uart_handle_break(port)) + continue; + } + if (status & ATMEL_US_PARE) + port->icount.parity++; + if (status & ATMEL_US_FRAME) + port->icount.frame++; + if (status & ATMEL_US_OVRE) + port->icount.overrun++; + + status &= port->read_status_mask; + + if (status & ATMEL_US_RXBRK) + flg = TTY_BREAK; + else if (status & ATMEL_US_PARE) + flg = TTY_PARITY; + else if (status & ATMEL_US_FRAME) + flg = TTY_FRAME; + } + + + if (uart_handle_sysrq_char(port, c.ch)) + continue; + + uart_insert_char(port, status, ATMEL_US_OVRE, c.ch, flg); + } + + /* + * Drop the lock here since it might end up calling + * uart_start(), which takes the lock. + */ + spin_unlock(&port->lock); + tty_flip_buffer_push(port->info->tty); + spin_lock(&port->lock); +} + +static void atmel_rx_from_dma(struct uart_port *port) +{ + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct tty_struct *tty = port->info->tty; + struct atmel_dma_buffer *pdc; + int rx_idx = atmel_port->pdc_rx_idx; + unsigned int head; + unsigned int tail; + unsigned int count; + + do { + /* Reset the UART timeout early so that we don't miss one */ + UART_PUT_CR(port, ATMEL_US_STTTO); + + pdc = &atmel_port->pdc_rx[rx_idx]; + head = UART_GET_RPR(port) - pdc->dma_addr; + tail = pdc->ofs; + + /* If the PDC has switched buffers, RPR won't contain + * any address within the current buffer. Since head + * is unsigned, we just need a one-way comparison to + * find out. + * + * In this case, we just need to consume the entire + * buffer and resubmit it for DMA. This will clear the + * ENDRX bit as well, so that we can safely re-enable + * all interrupts below. + */ + head = min(head, pdc->dma_size); + + if (likely(head != tail)) { + dma_sync_single_for_cpu(port->dev, pdc->dma_addr, + pdc->dma_size, DMA_FROM_DEVICE); + /* - * End of break detected. If it came along - * with a character, atmel_rx_chars will - * handle it. + * head will only wrap around when we recycle + * the DMA buffer, and when that happens, we + * explicitly set tail to 0. So head will + * always be greater than tail. */ - UART_PUT_CR(port, ATMEL_US_RSTSTA); - UART_PUT_IDR(port, ATMEL_US_RXBRK); - atmel_port->break_active = 0; + count = head - tail; + + tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count); + + dma_sync_single_for_device(port->dev, pdc->dma_addr, + pdc->dma_size, DMA_FROM_DEVICE); + + port->icount.rx += count; + pdc->ofs = head; } - // TODO: All reads to CSR will clear these interrupts! - if (pending & ATMEL_US_RIIC) port->icount.rng++; - if (pending & ATMEL_US_DSRIC) port->icount.dsr++; - if (pending & ATMEL_US_DCDIC) + /* + * If the current buffer is full, we need to check if + * the next one contains any additional data. + */ + if (head >= pdc->dma_size) { + pdc->ofs = 0; + UART_PUT_RNPR(port, pdc->dma_addr); + UART_PUT_RNCR(port, pdc->dma_size); + + rx_idx = !rx_idx; + atmel_port->pdc_rx_idx = rx_idx; + } + } while (head >= pdc->dma_size); + + /* + * Drop the lock here since it might end up calling + * uart_start(), which takes the lock. + */ + spin_unlock(&port->lock); + tty_flip_buffer_push(tty); + spin_lock(&port->lock); + + UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); +} + +/* + * tasklet handling tty stuff outside the interrupt handler. + */ +static void atmel_tasklet_func(unsigned long data) +{ + struct uart_port *port = (struct uart_port *)data; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + unsigned int status; + unsigned int status_change; + + /* The interrupt handler does not take the lock */ + spin_lock(&port->lock); + + if (atmel_use_dma_tx(port)) + atmel_tx_dma(port); + else + atmel_tx_chars(port); + + status = atmel_port->irq_status; + status_change = status ^ atmel_port->irq_status_prev; + + if (status_change & (ATMEL_US_RI | ATMEL_US_DSR + | ATMEL_US_DCD | ATMEL_US_CTS)) { + /* TODO: All reads to CSR will clear these interrupts! */ + if (status_change & ATMEL_US_RI) + port->icount.rng++; + if (status_change & ATMEL_US_DSR) + port->icount.dsr++; + if (status_change & ATMEL_US_DCD) uart_handle_dcd_change(port, !(status & ATMEL_US_DCD)); - if (pending & ATMEL_US_CTSIC) + if (status_change & ATMEL_US_CTS) uart_handle_cts_change(port, !(status & ATMEL_US_CTS)); - if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC)) - wake_up_interruptible(&port->info->delta_msr_wait); - /* Interrupt transmit */ - if (pending & ATMEL_US_TXRDY) - atmel_tx_chars(port); + wake_up_interruptible(&port->info->delta_msr_wait); - if (pass_counter++ > ATMEL_ISR_PASS_LIMIT) - break; - - status = UART_GET_CSR(port); - pending = status & UART_GET_IMR(port); + atmel_port->irq_status_prev = status; } - return IRQ_HANDLED; + + if (atmel_use_dma_rx(port)) + atmel_rx_from_dma(port); + else + atmel_rx_from_ring(port); + + spin_unlock(&port->lock); } /* @@ -402,6 +792,8 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) */ static int atmel_startup(struct uart_port *port) { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + struct tty_struct *tty = port->info->tty; int retval; /* @@ -414,13 +806,64 @@ static int atmel_startup(struct uart_port *port) /* * Allocate the IRQ */ - retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, "atmel_serial", port); + retval = request_irq(port->irq, atmel_interrupt, IRQF_SHARED, + tty ? tty->name : "atmel_serial", port); if (retval) { printk("atmel_serial: atmel_startup - Can't get irq\n"); return retval; } /* + * Initialize DMA (if necessary) + */ + if (atmel_use_dma_rx(port)) { + int i; + + for (i = 0; i < 2; i++) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; + + pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL); + if (pdc->buf == NULL) { + if (i != 0) { + dma_unmap_single(port->dev, + atmel_port->pdc_rx[0].dma_addr, + PDC_BUFFER_SIZE, + DMA_FROM_DEVICE); + kfree(atmel_port->pdc_rx[0].buf); + } + free_irq(port->irq, port); + return -ENOMEM; + } + pdc->dma_addr = dma_map_single(port->dev, + pdc->buf, + PDC_BUFFER_SIZE, + DMA_FROM_DEVICE); + pdc->dma_size = PDC_BUFFER_SIZE; + pdc->ofs = 0; + } + + atmel_port->pdc_rx_idx = 0; + + UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr); + UART_PUT_RCR(port, PDC_BUFFER_SIZE); + + UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr); + UART_PUT_RNCR(port, PDC_BUFFER_SIZE); + } + if (atmel_use_dma_tx(port)) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; + struct circ_buf *xmit = &port->info->xmit; + + pdc->buf = xmit->buf; + pdc->dma_addr = dma_map_single(port->dev, + pdc->buf, + UART_XMIT_SIZE, + DMA_TO_DEVICE); + pdc->dma_size = UART_XMIT_SIZE; + pdc->ofs = 0; + } + + /* * If there is a specific "open" function (to register * control line interrupts) */ @@ -436,9 +879,21 @@ static int atmel_startup(struct uart_port *port) * Finally, enable the serial port */ UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); - UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); /* enable xmit & rcvr */ + /* enable xmit & rcvr */ + UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); - UART_PUT_IER(port, ATMEL_US_RXRDY); /* enable receive only */ + if (atmel_use_dma_rx(port)) { + /* set UART timeout */ + UART_PUT_RTOR(port, PDC_RX_TIMEOUT); + UART_PUT_CR(port, ATMEL_US_STTTO); + + UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT); + /* enable PDC controller */ + UART_PUT_PTCR(port, ATMEL_PDC_RXTEN); + } else { + /* enable receive only */ + UART_PUT_IER(port, ATMEL_US_RXRDY); + } return 0; } @@ -448,6 +903,38 @@ static int atmel_startup(struct uart_port *port) */ static void atmel_shutdown(struct uart_port *port) { + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); + /* + * Ensure everything is stopped. + */ + atmel_stop_rx(port); + atmel_stop_tx(port); + + /* + * Shut-down the DMA. + */ + if (atmel_use_dma_rx(port)) { + int i; + + for (i = 0; i < 2; i++) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i]; + + dma_unmap_single(port->dev, + pdc->dma_addr, + pdc->dma_size, + DMA_FROM_DEVICE); + kfree(pdc->buf); + } + } + if (atmel_use_dma_tx(port)) { + struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx; + + dma_unmap_single(port->dev, + pdc->dma_addr, + pdc->dma_size, + DMA_TO_DEVICE); + } + /* * Disable all interrupts, port and break condition. */ @@ -470,45 +957,48 @@ static void atmel_shutdown(struct uart_port *port) /* * Power / Clock management. */ -static void atmel_serial_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) +static void atmel_serial_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) { - struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); switch (state) { - case 0: - /* - * Enable the peripheral clock for this serial port. - * This is called on uart_open() or a resume event. - */ - clk_enable(atmel_port->clk); - break; - case 3: - /* - * Disable the peripheral clock for this serial port. - * This is called on uart_close() or a suspend event. - */ - clk_disable(atmel_port->clk); - break; - default: - printk(KERN_ERR "atmel_serial: unknown pm %d\n", state); + case 0: + /* + * Enable the peripheral clock for this serial port. + * This is called on uart_open() or a resume event. + */ + clk_enable(atmel_port->clk); + break; + case 3: + /* + * Disable the peripheral clock for this serial port. + * This is called on uart_close() or a suspend event. + */ + clk_disable(atmel_port->clk); + break; + default: + printk(KERN_ERR "atmel_serial: unknown pm %d\n", state); } } /* * Change the port parameters */ -static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, struct ktermios * old) +static void atmel_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { unsigned long flags; unsigned int mode, imr, quot, baud; /* Get current mode register */ - mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP | ATMEL_US_PAR); + mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL + | ATMEL_US_NBSTOP | ATMEL_US_PAR); - baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk/16); + baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); quot = uart_get_divisor(port, baud); - if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */ + if (quot > 65535) { /* BRGR is 16-bit, so switch to slower clock */ quot /= 8; mode |= ATMEL_US_USCLKS_MCK_DIV8; } @@ -535,18 +1025,17 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, /* parity */ if (termios->c_cflag & PARENB) { - if (termios->c_cflag & CMSPAR) { /* Mark or Space parity */ + /* Mark or Space parity */ + if (termios->c_cflag & CMSPAR) { if (termios->c_cflag & PARODD) mode |= ATMEL_US_PAR_MARK; else mode |= ATMEL_US_PAR_SPACE; - } - else if (termios->c_cflag & PARODD) + } else if (termios->c_cflag & PARODD) mode |= ATMEL_US_PAR_ODD; else mode |= ATMEL_US_PAR_EVEN; - } - else + } else mode |= ATMEL_US_PAR_NONE; spin_lock_irqsave(&port->lock, flags); @@ -557,6 +1046,10 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, if (termios->c_iflag & (BRKINT | PARMRK)) port->read_status_mask |= ATMEL_US_RXBRK; + if (atmel_use_dma_rx(port)) + /* need to enable error interrupts */ + UART_PUT_IER(port, port->read_status_mask); + /* * Characters to ignore */ @@ -572,16 +1065,16 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, if (termios->c_iflag & IGNPAR) port->ignore_status_mask |= ATMEL_US_OVRE; } - - // TODO: Ignore all characters if CREAD is set. + /* TODO: Ignore all characters if CREAD is set.*/ /* update the per-port timeout */ uart_update_timeout(port, termios->c_cflag, baud); - /* disable interrupts and drain transmitter */ - imr = UART_GET_IMR(port); /* get interrupt mask */ - UART_PUT_IDR(port, -1); /* disable all interrupts */ - while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) { barrier(); } + /* save/disable interrupts and drain transmitter */ + imr = UART_GET_IMR(port); + UART_PUT_IDR(port, -1); + while (!(UART_GET_CSR(port) & ATMEL_US_TXEMPTY)) + cpu_relax(); /* disable receiver and transmitter */ UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS); @@ -707,7 +1200,8 @@ static struct uart_ops atmel_pops = { /* * Configure the port from the platform device resource info. */ -static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct platform_device *pdev) +static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, + struct platform_device *pdev) { struct uart_port *port = &atmel_port->uart; struct atmel_uart_data *data = pdev->dev.platform_data; @@ -722,6 +1216,11 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct port->mapbase = pdev->resource[0].start; port->irq = pdev->resource[1].start; + tasklet_init(&atmel_port->tasklet, atmel_tasklet_func, + (unsigned long)port); + + memset(&atmel_port->rx_ring, 0, sizeof(atmel_port->rx_ring)); + if (data->regs) /* Already mapped by setup code */ port->membase = data->regs; @@ -730,11 +1229,17 @@ static void __devinit atmel_init_port(struct atmel_uart_port *atmel_port, struct port->membase = NULL; } - if (!atmel_port->clk) { /* for console, the clock could already be configured */ + /* for console, the clock could already be configured */ + if (!atmel_port->clk) { atmel_port->clk = clk_get(&pdev->dev, "usart"); clk_enable(atmel_port->clk); port->uartclk = clk_get_rate(atmel_port->clk); } + + atmel_port->use_dma_rx = data->use_dma_rx; + atmel_port->use_dma_tx = data->use_dma_tx; + if (atmel_use_dma_tx(port)) + port->fifosize = PDC_BUFFER_SIZE; } /* @@ -754,12 +1259,11 @@ void __init atmel_register_uart_fns(struct atmel_port_fns *fns) atmel_pops.set_wake = fns->set_wake; } - #ifdef CONFIG_SERIAL_ATMEL_CONSOLE static void atmel_console_putchar(struct uart_port *port, int ch) { while (!(UART_GET_CSR(port) & ATMEL_US_TXRDY)) - barrier(); + cpu_relax(); UART_PUT_CHAR(port, ch); } @@ -772,38 +1276,40 @@ static void atmel_console_write(struct console *co, const char *s, u_int count) unsigned int status, imr; /* - * First, save IMR and then disable interrupts + * First, save IMR and then disable interrupts */ - imr = UART_GET_IMR(port); /* get interrupt mask */ + imr = UART_GET_IMR(port); UART_PUT_IDR(port, ATMEL_US_RXRDY | ATMEL_US_TXRDY); uart_console_write(port, s, count, atmel_console_putchar); /* - * Finally, wait for transmitter to become empty - * and restore IMR + * Finally, wait for transmitter to become empty + * and restore IMR */ do { status = UART_GET_CSR(port); } while (!(status & ATMEL_US_TXRDY)); - UART_PUT_IER(port, imr); /* set interrupts back the way they were */ + /* set interrupts back the way they were */ + UART_PUT_IER(port, imr); } /* - * If the port was already initialised (eg, by a boot loader), try to determine - * the current setup. + * If the port was already initialised (eg, by a boot loader), + * try to determine the current setup. */ -static void __init atmel_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) +static void __init atmel_console_get_options(struct uart_port *port, int *baud, + int *parity, int *bits) { unsigned int mr, quot; -// TODO: CR is a write-only register -// unsigned int cr; -// -// cr = UART_GET_CR(port) & (ATMEL_US_RXEN | ATMEL_US_TXEN); -// if (cr == (ATMEL_US_RXEN | ATMEL_US_TXEN)) { -// /* ok, the port was enabled */ -// } + /* + * If the baud rate generator isn't running, the port wasn't + * initialized by the boot loader. + */ + quot = UART_GET_BRGR(port); + if (!quot) + return; mr = UART_GET_MR(port) & ATMEL_US_CHRL; if (mr == ATMEL_US_CHRL_8) @@ -823,7 +1329,6 @@ static void __init atmel_console_get_options(struct uart_port *port, int *baud, * lower than one of those, as it would make us fall through * to a much lower baud rate than we really want. */ - quot = UART_GET_BRGR(port); *baud = port->uartclk / (16 * (quot - 1)); } @@ -835,10 +1340,12 @@ static int __init atmel_console_setup(struct console *co, char *options) int parity = 'n'; int flow = 'n'; - if (port->membase == 0) /* Port not initialized yet - delay setup */ + if (port->membase == NULL) { + /* Port not initialized yet - delay setup */ return -ENODEV; + } - UART_PUT_IDR(port, -1); /* disable interrupts */ + UART_PUT_IDR(port, -1); UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX); UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN); @@ -870,13 +1377,16 @@ static struct console atmel_console = { static int __init atmel_console_init(void) { if (atmel_default_console_device) { - add_preferred_console(ATMEL_DEVICENAME, atmel_default_console_device->id, NULL); - atmel_init_port(&(atmel_ports[atmel_default_console_device->id]), atmel_default_console_device); + add_preferred_console(ATMEL_DEVICENAME, + atmel_default_console_device->id, NULL); + atmel_init_port(&atmel_ports[atmel_default_console_device->id], + atmel_default_console_device); register_console(&atmel_console); } return 0; } + console_initcall(atmel_console_init); /* @@ -884,34 +1394,48 @@ console_initcall(atmel_console_init); */ static int __init atmel_late_console_init(void) { - if (atmel_default_console_device && !(atmel_console.flags & CON_ENABLED)) + if (atmel_default_console_device + && !(atmel_console.flags & CON_ENABLED)) register_console(&atmel_console); return 0; } + core_initcall(atmel_late_console_init); +static inline bool atmel_is_console_port(struct uart_port *port) +{ + return port->cons && port->cons->index == port->line; +} + #else #define ATMEL_CONSOLE_DEVICE NULL + +static inline bool atmel_is_console_port(struct uart_port *port) +{ + return false; +} #endif static struct uart_driver atmel_uart = { - .owner = THIS_MODULE, - .driver_name = "atmel_serial", - .dev_name = ATMEL_DEVICENAME, - .major = SERIAL_ATMEL_MAJOR, - .minor = MINOR_START, - .nr = ATMEL_MAX_UART, - .cons = ATMEL_CONSOLE_DEVICE, + .owner = THIS_MODULE, + .driver_name = "atmel_serial", + .dev_name = ATMEL_DEVICENAME, + .major = SERIAL_ATMEL_MAJOR, + .minor = MINOR_START, + .nr = ATMEL_MAX_UART, + .cons = ATMEL_CONSOLE_DEVICE, }; #ifdef CONFIG_PM -static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state) +static int atmel_serial_suspend(struct platform_device *pdev, + pm_message_t state) { struct uart_port *port = platform_get_drvdata(pdev); - struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - if (device_may_wakeup(&pdev->dev) && !at91_suspend_entering_slow_clock()) + if (device_may_wakeup(&pdev->dev) + && !at91_suspend_entering_slow_clock()) enable_irq_wake(port->irq); else { uart_suspend_port(&atmel_uart, port); @@ -924,13 +1448,12 @@ static int atmel_serial_suspend(struct platform_device *pdev, pm_message_t state static int atmel_serial_resume(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); - struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); if (atmel_port->suspended) { uart_resume_port(&atmel_uart, port); atmel_port->suspended = 0; - } - else + } else disable_irq_wake(port->irq); return 0; @@ -943,15 +1466,40 @@ static int atmel_serial_resume(struct platform_device *pdev) static int __devinit atmel_serial_probe(struct platform_device *pdev) { struct atmel_uart_port *port; + void *data; int ret; + BUILD_BUG_ON(!is_power_of_2(ATMEL_SERIAL_RINGSIZE)); + port = &atmel_ports[pdev->id]; atmel_init_port(port, pdev); + if (!atmel_use_dma_rx(&port->uart)) { + ret = -ENOMEM; + data = kmalloc(sizeof(struct atmel_uart_char) + * ATMEL_SERIAL_RINGSIZE, GFP_KERNEL); + if (!data) + goto err_alloc_ring; + port->rx_ring.buf = data; + } + ret = uart_add_one_port(&atmel_uart, &port->uart); - if (!ret) { - device_init_wakeup(&pdev->dev, 1); - platform_set_drvdata(pdev, port); + if (ret) + goto err_add_port; + + device_init_wakeup(&pdev->dev, 1); + platform_set_drvdata(pdev, port); + + return 0; + +err_add_port: + kfree(port->rx_ring.buf); + port->rx_ring.buf = NULL; +err_alloc_ring: + if (!atmel_is_console_port(&port->uart)) { + clk_disable(port->clk); + clk_put(port->clk); + port->clk = NULL; } return ret; @@ -960,19 +1508,21 @@ static int __devinit atmel_serial_probe(struct platform_device *pdev) static int __devexit atmel_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); - struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; + struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); int ret = 0; - clk_disable(atmel_port->clk); - clk_put(atmel_port->clk); - device_init_wakeup(&pdev->dev, 0); platform_set_drvdata(pdev, NULL); - if (port) { - ret = uart_remove_one_port(&atmel_uart, port); - kfree(port); - } + ret = uart_remove_one_port(&atmel_uart, port); + + tasklet_kill(&atmel_port->tasklet); + kfree(atmel_port->rx_ring.buf); + + /* "port" is allocated statically, so we shouldn't free it */ + + clk_disable(atmel_port->clk); + clk_put(atmel_port->clk); return ret; } diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 276da148c57e..0f5a17987cca 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -58,7 +58,8 @@ static struct lock_class_key port_lock_key; #define uart_console(port) (0) #endif -static void uart_change_speed(struct uart_state *state, struct ktermios *old_termios); +static void uart_change_speed(struct uart_state *state, + struct ktermios *old_termios); static void uart_wait_until_sent(struct tty_struct *tty, int timeout); static void uart_change_pm(struct uart_state *state, int pm_state); @@ -129,8 +130,8 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) spin_unlock_irqrestore(&port->lock, flags); } -#define uart_set_mctrl(port,set) uart_update_mctrl(port,set,0) -#define uart_clear_mctrl(port,clear) uart_update_mctrl(port,0,clear) +#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) +#define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear) /* * Startup the port. This will be called once per open. All calls @@ -290,7 +291,7 @@ uart_update_timeout(struct uart_port *port, unsigned int cflag, break; default: bits = 10; - break; // CS8 + break; /* CS8 */ } if (cflag & CSTOPB) @@ -622,7 +623,7 @@ static int uart_get_info(struct uart_state *state, tmp.close_delay = state->close_delay / 10; tmp.closing_wait = state->closing_wait == USF_CLOSING_WAIT_NONE ? ASYNC_CLOSING_WAIT_NONE : - state->closing_wait / 10; + state->closing_wait / 10; tmp.custom_divisor = port->custom_divisor; tmp.hub6 = port->hub6; tmp.io_type = port->iotype; @@ -788,7 +789,8 @@ static int uart_set_info(struct uart_state *state, * We failed anyway. */ retval = -EBUSY; - goto exit; // Added to return the correct error -Ram Gupta + /* Added to return the correct error -Ram Gupta */ + goto exit; } } @@ -858,7 +860,7 @@ static int uart_get_lsr_info(struct uart_state *state, ((uart_circ_chars_pending(&state->info->xmit) > 0) && !state->info->tty->stopped && !state->info->tty->hw_stopped)) result &= ~TIOCSER_TEMT; - + return put_user(result, value); } @@ -996,8 +998,8 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts))) { - ret = 0; - break; + ret = 0; + break; } schedule(); @@ -1137,7 +1139,8 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, return ret; } -static void uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +static void uart_set_termios(struct tty_struct *tty, + struct ktermios *old_termios) { struct uart_state *state = tty->driver_data; unsigned long flags; @@ -1213,7 +1216,7 @@ static void uart_close(struct tty_struct *tty, struct file *filp) { struct uart_state *state = tty->driver_data; struct uart_port *port; - + BUG_ON(!kernel_locked()); if (!state || !state->port) @@ -1278,8 +1281,8 @@ static void uart_close(struct tty_struct *tty, struct file *filp) uart_shutdown(state); uart_flush_buffer(tty); - tty_ldisc_flush(tty); - + tty_ldisc_flush(tty); + tty->closing = 0; state->info->tty = NULL; @@ -1341,7 +1344,7 @@ static void uart_wait_until_sent(struct tty_struct *tty, int timeout) expire = jiffies + timeout; pr_debug("uart_wait_until_sent(%d), jiffies=%lu, expire=%lu...\n", - port->line, jiffies, expire); + port->line, jiffies, expire); /* * Check whether the transmitter is empty every 'char_time'. @@ -1460,10 +1463,9 @@ uart_block_til_ready(struct file *filp, struct uart_state *state) * have set TTY_IO_ERROR for a non-existant port. */ if ((filp->f_flags & O_NONBLOCK) || - (info->tty->termios->c_cflag & CLOCAL) || - (info->tty->flags & (1 << TTY_IO_ERROR))) { + (info->tty->termios->c_cflag & CLOCAL) || + (info->tty->flags & (1 << TTY_IO_ERROR))) break; - } /* * Set DTR to allow modem to know we're waiting. Do @@ -1551,8 +1553,8 @@ static struct uart_state *uart_get(struct uart_driver *drv, int line) } /* - * In 2.4.5, calls to uart_open are serialised by the BKL in - * linux/fs/devices.c:chrdev_open() + * calls to uart_open are serialised by the BKL in + * fs/char_dev.c:chrdev_open() * Note that if this fails, then uart_close() _will_ be called. * * In time, we want to scrap the "opening nonpresent ports" @@ -1674,7 +1676,7 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) port->line, uart_type(port), mmio ? "mmio:0x" : "port:", mmio ? (unsigned long long)port->mapbase - : (unsigned long long) port->iobase, + : (unsigned long long) port->iobase, port->irq); if (port->type == PORT_UNKNOWN) { @@ -1682,8 +1684,7 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) return ret + 1; } - if(capable(CAP_SYS_ADMIN)) - { + if (capable(CAP_SYS_ADMIN)) { mutex_lock(&state->mutex); pm_state = state->pm_state; if (pm_state) @@ -1709,12 +1710,12 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) if (port->icount.overrun) ret += sprintf(buf + ret, " oe:%d", port->icount.overrun); - -#define INFOBIT(bit,str) \ + +#define INFOBIT(bit, str) \ if (port->mctrl & (bit)) \ strncat(stat_buf, (str), sizeof(stat_buf) - \ strlen(stat_buf) - 2) -#define STATBIT(bit,str) \ +#define STATBIT(bit, str) \ if (status & (bit)) \ strncat(stat_buf, (str), sizeof(stat_buf) - \ strlen(stat_buf) - 2) @@ -1730,7 +1731,7 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i) if (stat_buf[0]) stat_buf[0] = ' '; strcat(stat_buf, "\n"); - + ret += sprintf(buf + ret, stat_buf); } else { strcat(buf, "\n"); @@ -1992,11 +1993,11 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *port) /* * Wait for the transmitter to empty. */ - for (tries = 3; !ops->tx_empty(port) && tries; tries--) { + for (tries = 3; !ops->tx_empty(port) && tries; tries--) msleep(10); - } if (!tries) - printk(KERN_ERR "%s%s%s%d: Unable to drain transmitter\n", + printk(KERN_ERR "%s%s%s%d: Unable to drain " + "transmitter\n", port->dev ? port->dev->bus_id : "", port->dev ? ": " : "", drv->dev_name, port->line); |