16e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre/* 26e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * linux/drivers/mmc/card/sdio_uart.c - SDIO UART/GPS driver 36e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * 46e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Based on drivers/serial/8250.c and drivers/serial/serial_core.c 56e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * by Russell King. 66e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * 76e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Author: Nicolas Pitre 86e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Created: June 15, 2007 96e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Copyright: MontaVista Software, Inc. 106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * 116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * This program is free software; you can redistribute it and/or modify 126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * it under the terms of the GNU General Public License as published by 136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * the Free Software Foundation; either version 2 of the License, or (at 146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * your option) any later version. 156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre/* 186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Note: Although this driver assumes a 16550A-like UART implementation, 196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * it is not possible to leverage the common 8250/16550 driver, nor the 206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * core UART infrastructure, as they assumes direct access to the hardware 216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * registers, often under a spinlock. This is not possible in the SDIO 226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * context as SDIO access functions must be able to sleep. 236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * 246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Because we need to lock the SDIO host to ensure an exclusive access to 256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * the card, we simply rely on that lock to also prevent and serialize 266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * concurrent access to the same port. 276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/module.h> 306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/init.h> 316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/kernel.h> 324b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox#include <linux/sched.h> 336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/mutex.h> 34201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan#include <linux/seq_file.h> 356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/serial_reg.h> 366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/circ_buf.h> 376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/tty.h> 386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/tty_flip.h> 398b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox#include <linux/kfifo.h> 405a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/mmc/core.h> 436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/mmc/card.h> 446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/mmc/sdio_func.h> 456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#include <linux/mmc/sdio_ids.h> 466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#define UART_NR 8 /* Number of UARTs this driver can handle */ 496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 518b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox#define FIFO_SIZE PAGE_SIZE 526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#define WAKEUP_CHARS 256 536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestruct uart_icount { 556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre __u32 cts; 566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre __u32 dsr; 576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre __u32 rng; 586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre __u32 dcd; 596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre __u32 rx; 606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre __u32 tx; 616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre __u32 frame; 626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre __u32 overrun; 636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre __u32 parity; 646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre __u32 brk; 656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}; 666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestruct sdio_uart_port { 68b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox struct tty_port port; 696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct kref kref; 706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct tty_struct *tty; 716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int index; 726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_func *func; 736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct mutex func_lock; 7415b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre struct task_struct *in_sdio_uart_irq; 756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int regs_offset; 768b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox struct kfifo xmit_fifo; 776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre spinlock_t write_lock; 786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct uart_icount icount; 796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int uartclk; 806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int mctrl; 814b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox unsigned int rx_mctrl; 826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int read_status_mask; 836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int ignore_status_mask; 846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned char x_char; 856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned char ier; 866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned char lcr; 876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}; 886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic struct sdio_uart_port *sdio_uart_table[UART_NR]; 906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic DEFINE_SPINLOCK(sdio_uart_table_lock); 916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic int sdio_uart_add_port(struct sdio_uart_port *port) 936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre int index, ret = -EBUSY; 956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre kref_init(&port->kref); 976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre mutex_init(&port->func_lock); 986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre spin_lock_init(&port->write_lock); 998b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox if (kfifo_alloc(&port->xmit_fifo, FIFO_SIZE, GFP_KERNEL)) 1008b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox return -ENOMEM; 1016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre spin_lock(&sdio_uart_table_lock); 1036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre for (index = 0; index < UART_NR; index++) { 1046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!sdio_uart_table[index]) { 1056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->index = index; 1066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_table[index] = port; 1076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret = 0; 1086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre break; 1096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 1106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 1116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre spin_unlock(&sdio_uart_table_lock); 1126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return ret; 1146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 1156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic struct sdio_uart_port *sdio_uart_port_get(unsigned index) 1176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 1186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port; 1196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (index >= UART_NR) 1216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return NULL; 1226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre spin_lock(&sdio_uart_table_lock); 1246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port = sdio_uart_table[index]; 1256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (port) 1266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre kref_get(&port->kref); 1276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre spin_unlock(&sdio_uart_table_lock); 1286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return port; 1306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 1316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_port_destroy(struct kref *kref) 1336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 1346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = 1356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre container_of(kref, struct sdio_uart_port, kref); 1368b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox kfifo_free(&port->xmit_fifo); 1376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre kfree(port); 1386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 1396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_port_put(struct sdio_uart_port *port) 1416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 1426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre kref_put(&port->kref, sdio_uart_port_destroy); 1436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 1446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_port_remove(struct sdio_uart_port *port) 1466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 1476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_func *func; 148584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox struct tty_struct *tty; 1496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre BUG_ON(sdio_uart_table[port->index] != port); 1516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre spin_lock(&sdio_uart_table_lock); 1536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_table[port->index] = NULL; 1546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre spin_unlock(&sdio_uart_table_lock); 1556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 1576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * We're killing a port that potentially still is in use by 1586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * the tty layer. Be careful to prevent any further access 1596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * to the SDIO function and arrange for the tty layer to 1606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * give up on that port ASAP. 1616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Beware: the lock ordering is critical. 1626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 1630a68f64febf365313987c570ad59c9069f61306dAlan Cox mutex_lock(&port->port.mutex); 1646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre mutex_lock(&port->func_lock); 1656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre func = port->func; 1666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_claim_host(func); 1676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->func = NULL; 1686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre mutex_unlock(&port->func_lock); 169584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox tty = tty_port_tty_get(&port->port); 170584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox /* tty_hangup is async so is this safe as is ?? */ 171584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox if (tty) { 172584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox tty_hangup(tty); 173530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox tty_kref_put(tty); 174530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox } 1750a68f64febf365313987c570ad59c9069f61306dAlan Cox mutex_unlock(&port->port.mutex); 1766e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_release_irq(func); 1776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_disable_func(func); 1786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_release_host(func); 1796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_port_put(port); 1816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 1826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic int sdio_uart_claim_func(struct sdio_uart_port *port) 1846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 1856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre mutex_lock(&port->func_lock); 1866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (unlikely(!port->func)) { 1876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre mutex_unlock(&port->func_lock); 1886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return -ENODEV; 1896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 19015b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre if (likely(port->in_sdio_uart_irq != current)) 19115b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre sdio_claim_host(port->func); 1926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre mutex_unlock(&port->func_lock); 1936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return 0; 1946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 1956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 1966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic inline void sdio_uart_release_func(struct sdio_uart_port *port) 1976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 19815b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre if (likely(port->in_sdio_uart_irq != current)) 19915b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre sdio_release_host(port->func); 2006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 2016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic inline unsigned int sdio_in(struct sdio_uart_port *port, int offset) 2036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 2046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned char c; 2056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre c = sdio_readb(port->func, port->regs_offset + offset, NULL); 2066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return c; 2076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 2086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic inline void sdio_out(struct sdio_uart_port *port, int offset, int value) 2106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 2116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_writeb(port->func, value, port->regs_offset + offset, NULL); 2126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 2136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port) 2156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 2166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned char status; 2176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int ret; 2186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2194b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox /* FIXME: What stops this losing the delta bits and breaking 2204b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox sdio_uart_check_modem_status ? */ 2216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre status = sdio_in(port, UART_MSR); 2226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret = 0; 2246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (status & UART_MSR_DCD) 2256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret |= TIOCM_CAR; 2266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (status & UART_MSR_RI) 2276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret |= TIOCM_RNG; 2286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (status & UART_MSR_DSR) 2296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret |= TIOCM_DSR; 2306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (status & UART_MSR_CTS) 2316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret |= TIOCM_CTS; 2326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return ret; 2336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 2346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2351e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardostatic void sdio_uart_write_mctrl(struct sdio_uart_port *port, 2361e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo unsigned int mctrl) 2376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 2386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned char mcr = 0; 2396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (mctrl & TIOCM_RTS) 2416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre mcr |= UART_MCR_RTS; 2426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (mctrl & TIOCM_DTR) 2436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre mcr |= UART_MCR_DTR; 2446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (mctrl & TIOCM_OUT1) 2456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre mcr |= UART_MCR_OUT1; 2466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (mctrl & TIOCM_OUT2) 2476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre mcr |= UART_MCR_OUT2; 2486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (mctrl & TIOCM_LOOP) 2496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre mcr |= UART_MCR_LOOP; 2506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_MCR, mcr); 2526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 2536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic inline void sdio_uart_update_mctrl(struct sdio_uart_port *port, 2556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int set, unsigned int clear) 2566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 2576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int old; 2586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre old = port->mctrl; 2606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->mctrl = (old & ~clear) | set; 2616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (old != port->mctrl) 2626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_write_mctrl(port, port->mctrl); 2636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 2646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#define sdio_uart_set_mctrl(port, x) sdio_uart_update_mctrl(port, x, 0) 2666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre#define sdio_uart_clear_mctrl(port, x) sdio_uart_update_mctrl(port, 0, x) 2676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_change_speed(struct sdio_uart_port *port, 2696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct ktermios *termios, 2706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct ktermios *old) 2716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 2726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned char cval, fcr = 0; 2736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int baud, quot; 2746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre switch (termios->c_cflag & CSIZE) { 2766e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre case CS5: 2776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre cval = UART_LCR_WLEN5; 2786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre break; 2796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre case CS6: 2806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre cval = UART_LCR_WLEN6; 2816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre break; 2826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre case CS7: 2836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre cval = UART_LCR_WLEN7; 2846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre break; 2856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre default: 2866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre case CS8: 2876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre cval = UART_LCR_WLEN8; 2886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre break; 2896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 2906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (termios->c_cflag & CSTOPB) 2926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre cval |= UART_LCR_STOP; 2936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (termios->c_cflag & PARENB) 2946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre cval |= UART_LCR_PARITY; 2956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!(termios->c_cflag & PARODD)) 2966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre cval |= UART_LCR_EPAR; 2976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 2986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre for (;;) { 2996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre baud = tty_termios_baud_rate(termios); 3006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (baud == 0) 3016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre baud = 9600; /* Special case: B0 rate. */ 3026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (baud <= port->uartclk) 3036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre break; 3046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 3056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Oops, the quotient was zero. Try again with the old 3066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * baud rate if possible, otherwise default to 9600. 3076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 3086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre termios->c_cflag &= ~CBAUD; 3096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (old) { 3106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre termios->c_cflag |= old->c_cflag & CBAUD; 3116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre old = NULL; 3126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } else 3136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre termios->c_cflag |= B9600; 3146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 3156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre quot = (2 * port->uartclk + baud) / (2 * baud); 3166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 3176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (baud < 2400) 3186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; 3196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre else 3206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10; 3216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 3226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; 3236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (termios->c_iflag & INPCK) 3246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->read_status_mask |= UART_LSR_FE | UART_LSR_PE; 3256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (termios->c_iflag & (BRKINT | PARMRK)) 3266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->read_status_mask |= UART_LSR_BI; 3276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 3286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 3296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Characters to ignore 3306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 3316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->ignore_status_mask = 0; 3326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (termios->c_iflag & IGNPAR) 3336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE; 3346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (termios->c_iflag & IGNBRK) { 3356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->ignore_status_mask |= UART_LSR_BI; 3366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 3376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * If we're ignoring parity and break indicators, 3386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * ignore overruns too (for real raw support). 3396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 3406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (termios->c_iflag & IGNPAR) 3416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->ignore_status_mask |= UART_LSR_OE; 3426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 3436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 3446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 3456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * ignore all characters if CREAD is not set 3466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 3476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if ((termios->c_cflag & CREAD) == 0) 3486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->ignore_status_mask |= UART_LSR_DR; 3496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 3506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 3516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * CTS flow control flag and modem status interrupts 3526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 3536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->ier &= ~UART_IER_MSI; 3546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if ((termios->c_cflag & CRTSCTS) || !(termios->c_cflag & CLOCAL)) 3556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->ier |= UART_IER_MSI; 3566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 3576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->lcr = cval; 3586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 3596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_IER, port->ier); 3606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_LCR, cval | UART_LCR_DLAB); 3616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_DLL, quot & 0xff); 3626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_DLM, quot >> 8); 3636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_LCR, cval); 3646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_FCR, fcr); 3656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 3666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_write_mctrl(port, port->mctrl); 3676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 3686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 3696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_start_tx(struct sdio_uart_port *port) 3706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 3716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!(port->ier & UART_IER_THRI)) { 3726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->ier |= UART_IER_THRI; 3736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_IER, port->ier); 3746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 3756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 3766e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 3776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_stop_tx(struct sdio_uart_port *port) 3786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 3796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (port->ier & UART_IER_THRI) { 3806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->ier &= ~UART_IER_THRI; 3816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_IER, port->ier); 3826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 3836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 3846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 3856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_stop_rx(struct sdio_uart_port *port) 3866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 3876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->ier &= ~UART_IER_RLSI; 3886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->read_status_mask &= ~UART_LSR_DR; 3896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_IER, port->ier); 3906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 3916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 3921e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardostatic void sdio_uart_receive_chars(struct sdio_uart_port *port, 3931e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo unsigned int *status) 3946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 395530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox struct tty_struct *tty = tty_port_tty_get(&port->port); 3966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int ch, flag; 3976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre int max_count = 256; 3986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 3996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre do { 4006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ch = sdio_in(port, UART_RX); 4016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre flag = TTY_NORMAL; 4026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->icount.rx++; 4036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 4046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | 4051e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo UART_LSR_FE | UART_LSR_OE))) { 4066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 4076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * For statistics only 4086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 4096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (*status & UART_LSR_BI) { 4106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre *status &= ~(UART_LSR_FE | UART_LSR_PE); 4116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->icount.brk++; 4126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } else if (*status & UART_LSR_PE) 4136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->icount.parity++; 4146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre else if (*status & UART_LSR_FE) 4156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->icount.frame++; 4166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (*status & UART_LSR_OE) 4176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->icount.overrun++; 4186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 4196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 4206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Mask off conditions which should be ignored. 4216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 4226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre *status &= port->read_status_mask; 4231e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo if (*status & UART_LSR_BI) 4246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre flag = TTY_BREAK; 4251e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo else if (*status & UART_LSR_PE) 4266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre flag = TTY_PARITY; 4276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre else if (*status & UART_LSR_FE) 4286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre flag = TTY_FRAME; 4296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 4306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 4316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0) 432530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox if (tty) 433530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox tty_insert_flip_char(tty, ch, flag); 4346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 4356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 4366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Overrun is special. Since it's reported immediately, 4376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * it doesn't affect the current character. 4386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 4396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (*status & ~port->ignore_status_mask & UART_LSR_OE) 440530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox if (tty) 441530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox tty_insert_flip_char(tty, 0, TTY_OVERRUN); 4426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 4436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre *status = sdio_in(port, UART_LSR); 4446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } while ((*status & UART_LSR_DR) && (max_count-- > 0)); 445530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox if (tty) { 446530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox tty_flip_buffer_push(tty); 447530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox tty_kref_put(tty); 448530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox } 4496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 4506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 4516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_transmit_chars(struct sdio_uart_port *port) 4526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 4538b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox struct kfifo *xmit = &port->xmit_fifo; 4546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre int count; 455530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox struct tty_struct *tty; 4568b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox u8 iobuf[16]; 4578b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox int len; 4586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 4596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (port->x_char) { 4606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_TX, port->x_char); 4616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->icount.tx++; 4626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->x_char = 0; 4636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return; 4646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 465530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox 466530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox tty = tty_port_tty_get(&port->port); 467530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox 4688b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox if (tty == NULL || !kfifo_len(xmit) || 469c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox tty->stopped || tty->hw_stopped) { 4706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_stop_tx(port); 471530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox tty_kref_put(tty); 4726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return; 4736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 4746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 4758b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox len = kfifo_out_locked(xmit, iobuf, 16, &port->write_lock); 4768b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox for (count = 0; count < len; count++) { 4778b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox sdio_out(port, UART_TX, iobuf[count]); 4786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->icount.tx++; 4798b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox } 4806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 4818b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox len = kfifo_len(xmit); 4828b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox if (len < WAKEUP_CHARS) { 483b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox tty_wakeup(tty); 4848b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox if (len == 0) 4858b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox sdio_uart_stop_tx(port); 4868b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox } 487530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox tty_kref_put(tty); 4886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 4896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 4906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_check_modem_status(struct sdio_uart_port *port) 4916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 4926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre int status; 493530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox struct tty_struct *tty; 4946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 4956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre status = sdio_in(port, UART_MSR); 4966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 4976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if ((status & UART_MSR_ANY_DELTA) == 0) 4986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return; 4996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 5006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (status & UART_MSR_TERI) 5016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->icount.rng++; 5026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (status & UART_MSR_DDSR) 5036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->icount.dsr++; 5044b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox if (status & UART_MSR_DDCD) { 5056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->icount.dcd++; 5064b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox /* DCD raise - wake for open */ 5074b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox if (status & UART_MSR_DCD) 5084b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox wake_up_interruptible(&port->port.open_wait); 5094b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox else { 5104b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox /* DCD drop - hang up if tty attached */ 5114b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox tty = tty_port_tty_get(&port->port); 5124b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox if (tty) { 5134b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox tty_hangup(tty); 5144b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox tty_kref_put(tty); 5154b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox } 5164b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox } 5174b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox } 5186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (status & UART_MSR_DCTS) { 5196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->icount.cts++; 520530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox tty = tty_port_tty_get(&port->port); 521530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox if (tty && (tty->termios->c_cflag & CRTSCTS)) { 5226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre int cts = (status & UART_MSR_CTS); 523b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox if (tty->hw_stopped) { 5246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (cts) { 525b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox tty->hw_stopped = 0; 5266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_start_tx(port); 527b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox tty_wakeup(tty); 5286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 5296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } else { 5306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!cts) { 531b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox tty->hw_stopped = 1; 5326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_stop_tx(port); 5336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 5346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 5356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 536530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox tty_kref_put(tty); 5376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 5386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 5396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 5406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre/* 5416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * This handles the interrupt from one port. 5426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 5436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_irq(struct sdio_func *func) 5446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 5456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = sdio_get_drvdata(func); 5466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int iir, lsr; 5476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 54815b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre /* 54915b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre * In a few places sdio_uart_irq() is called directly instead of 55015b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre * waiting for the actual interrupt to be raised and the SDIO IRQ 55115b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre * thread scheduled in order to reduce latency. However, some 55215b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre * interaction with the tty core may end up calling us back 55315b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre * (serial echo, flow control, etc.) through those same places 55415b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre * causing undesirable effects. Let's stop the recursion here. 55515b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre */ 55615b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre if (unlikely(port->in_sdio_uart_irq == current)) 55715b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre return; 55815b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre 5596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre iir = sdio_in(port, UART_IIR); 5606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (iir & UART_IIR_NO_INT) 5616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return; 56215b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre 56315b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre port->in_sdio_uart_irq = current; 5646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre lsr = sdio_in(port, UART_LSR); 5656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (lsr & UART_LSR_DR) 5666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_receive_chars(port, &lsr); 5676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_check_modem_status(port); 5686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (lsr & UART_LSR_THRE) 5696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_transmit_chars(port); 57015b82b46de358a574c2a6a6dea4c8076bef7ac43Nicolas Pitre port->in_sdio_uart_irq = NULL; 5716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 5726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 5734b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Coxstatic int uart_carrier_raised(struct tty_port *tport) 5744b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox{ 5754b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox struct sdio_uart_port *port = 5764b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox container_of(tport, struct sdio_uart_port, port); 5774b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox unsigned int ret = sdio_uart_claim_func(port); 578c9404c9c392d557a4687c4cbda022b03cb787ce9Adam Buchbinder if (ret) /* Missing hardware shouldn't block for carrier */ 5794b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox return 1; 5804b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox ret = sdio_uart_get_mctrl(port); 5814b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox sdio_uart_release_func(port); 5824b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox if (ret & TIOCM_CAR) 5834b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox return 1; 5844b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox return 0; 5854b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox} 5864b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox 587584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox/** 588584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * uart_dtr_rts - port helper to set uart signals 589584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * @tport: tty port to be updated 590584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * @onoff: set to turn on DTR/RTS 591584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * 592584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * Called by the tty port helpers when the modem signals need to be 593584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * adjusted during an open, close and hangup. 594584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox */ 595584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox 596584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic void uart_dtr_rts(struct tty_port *tport, int onoff) 5976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 598584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox struct sdio_uart_port *port = 599584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox container_of(tport, struct sdio_uart_port, port); 6001f100b323d19469b06a63ccd6130ed71760145ccAlan Cox int ret = sdio_uart_claim_func(port); 6011f100b323d19469b06a63ccd6130ed71760145ccAlan Cox if (ret) 6021f100b323d19469b06a63ccd6130ed71760145ccAlan Cox return; 603584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox if (onoff == 0) 604584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); 605584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox else 606584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS); 6071f100b323d19469b06a63ccd6130ed71760145ccAlan Cox sdio_uart_release_func(port); 608584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox} 609530646f4695b396aeeec2ca912dcc3a9c95e0f52Alan Cox 610584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox/** 611584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * sdio_uart_activate - start up hardware 612584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * @tport: tty port to activate 613584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * @tty: tty bound to this port 614584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * 615584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * Activate a tty port. The port locking guarantees us this will be 616584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * run exactly once per set of opens, and if successful will see the 617584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * shutdown method run exactly once to match. Start up and shutdown are 618584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * protected from each other by the internal locking and will not run 619584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * at the same time even during a hangup event. 620584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * 621584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * If we successfully start up the port we take an extra kref as we 622584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * will keep it around until shutdown when the kref is dropped. 623584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox */ 624584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox 625584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) 626584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox{ 627584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox struct sdio_uart_port *port = 628584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox container_of(tport, struct sdio_uart_port, port); 629584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox int ret; 6306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 6316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 6326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Set the TTY IO error marker - we will only clear this 6336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * once we have successfully opened the port. 6346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 635b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox set_bit(TTY_IO_ERROR, &tty->flags); 6366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 6378b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox kfifo_reset(&port->xmit_fifo); 6386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 6396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret = sdio_uart_claim_func(port); 6406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (ret) 6418b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox return ret; 6426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret = sdio_enable_func(port->func); 6436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (ret) 6448b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox goto err1; 6456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret = sdio_claim_irq(port->func, sdio_uart_irq); 6466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (ret) 6478b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox goto err2; 6486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 6496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 6506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Clear the FIFO buffers and disable them. 6516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * (they will be reenabled in sdio_change_speed()) 6526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 6536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); 6546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO | 6551e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); 6566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_FCR, 0); 6576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 6586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 6596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Clear the interrupt registers. 6606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 6616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre (void) sdio_in(port, UART_LSR); 6626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre (void) sdio_in(port, UART_RX); 6636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre (void) sdio_in(port, UART_IIR); 6646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre (void) sdio_in(port, UART_MSR); 6656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 6666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 6676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * Now, initialize the UART 6686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 6696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_LCR, UART_LCR_WLEN8); 6706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 671c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE; 6726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->mctrl = TIOCM_OUT2; 6736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 674b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox sdio_uart_change_speed(port, tty->termios, NULL); 6756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 676b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox if (tty->termios->c_cflag & CBAUD) 6776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); 6786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 679b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox if (tty->termios->c_cflag & CRTSCTS) 6806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) 681b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox tty->hw_stopped = 1; 6826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 6830395b48c78ed822f251ab15d0fbc3ce06f41ffb1Nicolas Pitre clear_bit(TTY_IO_ERROR, &tty->flags); 6846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 6856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* Kick the IRQ handler once while we're still holding the host lock */ 6866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_irq(port->func); 6876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 6886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_release_func(port); 6896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return 0; 6906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 6916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitreerr2: 6928b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox sdio_disable_func(port->func); 6936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitreerr1: 6948b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox sdio_uart_release_func(port); 6956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return ret; 6966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 6976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 698584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox/** 699584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * sdio_uart_shutdown - stop hardware 700584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * @tport: tty port to shut down 701584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * 702584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * Deactivate a tty port. The port locking guarantees us this will be 703584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * run only if a successful matching activate already ran. The two are 704584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * protected from each other by the internal locking and will not run 705584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * at the same time even during a hangup event. 706584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox */ 707584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox 708584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic void sdio_uart_shutdown(struct tty_port *tport) 7096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 710584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox struct sdio_uart_port *port = 711584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox container_of(tport, struct sdio_uart_port, port); 7126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre int ret; 7136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 7146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret = sdio_uart_claim_func(port); 7156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (ret) 7168b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox return; 7176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 7186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_stop_rx(port); 7196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 7201e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo /* Disable interrupts from this port */ 7216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_release_irq(port->func); 7226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->ier = 0; 7236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_IER, 0); 7246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 7256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_clear_mctrl(port, TIOCM_OUT2); 7266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 7276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* Disable break condition and FIFOs. */ 7286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->lcr &= ~UART_LCR_SBC; 7296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_LCR, port->lcr); 7306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO | 7316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre UART_FCR_CLEAR_RCVR | 7326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre UART_FCR_CLEAR_XMIT); 7336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_FCR, 0); 7346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 7356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_disable_func(port->func); 7366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 7376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_release_func(port); 7386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 7396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 740584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox/** 741584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * sdio_uart_install - install method 742584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * @driver: the driver in use (sdio_uart in our case) 743584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * @tty: the tty being bound 744584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * 745584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * Look up and bind the tty and the driver together. Initialize 746584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * any needed private data (in our case the termios) 747584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox */ 7486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 749584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty) 750584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox{ 751584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox int idx = tty->index; 752584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox struct sdio_uart_port *port = sdio_uart_port_get(idx); 75381f5835eae424be646753ec5a044ed4db1fcc09aJiri Slaby int ret = tty_standard_install(driver, tty); 754584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox 75581f5835eae424be646753ec5a044ed4db1fcc09aJiri Slaby if (ret == 0) 756584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox /* This is the ref sdio_uart_port get provided */ 757584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox tty->driver_data = port; 75881f5835eae424be646753ec5a044ed4db1fcc09aJiri Slaby else 7596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_port_put(port); 760584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox return ret; 7616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 7626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 763584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox/** 764584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * sdio_uart_cleanup - called on the last tty kref drop 765584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * @tty: the tty being destroyed 766584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * 767584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * Called asynchronously when the last reference to the tty is dropped. 768584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * We cannot destroy the tty->driver_data port kref until this point 769584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox */ 770584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox 771584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic void sdio_uart_cleanup(struct tty_struct *tty) 7726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 7736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = tty->driver_data; 774584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox tty->driver_data = NULL; /* Bug trap */ 775584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox sdio_uart_port_put(port); 776584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox} 7776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 778584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox/* 779584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox * Open/close/hangup is now entirely boilerplate 780584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox */ 7816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 782584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic int sdio_uart_open(struct tty_struct *tty, struct file *filp) 783584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox{ 784584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox struct sdio_uart_port *port = tty->driver_data; 785584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox return tty_port_open(&port->port, tty, filp); 786584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox} 7876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 788584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic void sdio_uart_close(struct tty_struct *tty, struct file * filp) 789584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox{ 790584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox struct sdio_uart_port *port = tty->driver_data; 791584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox tty_port_close(&port->port, tty, filp); 792584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox} 7936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 794584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic void sdio_uart_hangup(struct tty_struct *tty) 795584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox{ 796584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox struct sdio_uart_port *port = tty->driver_data; 797584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox tty_port_hangup(&port->port); 7986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 7996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 800c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Coxstatic int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf, 8016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre int count) 8026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 8036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = tty->driver_data; 8048b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox int ret; 8056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!port->func) 8076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return -ENODEV; 8086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8098b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox ret = kfifo_in_locked(&port->xmit_fifo, buf, count, &port->write_lock); 810c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox if (!(port->ier & UART_IER_THRI)) { 8116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre int err = sdio_uart_claim_func(port); 8126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!err) { 8136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_start_tx(port); 8146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_irq(port->func); 8156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_release_func(port); 8166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } else 8176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret = err; 8186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 8196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return ret; 8216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 8226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic int sdio_uart_write_room(struct tty_struct *tty) 8246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 8256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = tty->driver_data; 8268b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox return FIFO_SIZE - kfifo_len(&port->xmit_fifo); 8276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 8286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic int sdio_uart_chars_in_buffer(struct tty_struct *tty) 8306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 8316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = tty->driver_data; 8328b197a5ce7a7218bb9fc721647ba0d5734f27348Alan Cox return kfifo_len(&port->xmit_fifo); 8336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 8346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_send_xchar(struct tty_struct *tty, char ch) 8366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 8376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = tty->driver_data; 8386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->x_char = ch; 8406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (ch && !(port->ier & UART_IER_THRI)) { 8416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (sdio_uart_claim_func(port) != 0) 8426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return; 8436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_start_tx(port); 8446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_irq(port->func); 8456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_release_func(port); 8466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 8476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 8486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_throttle(struct tty_struct *tty) 8506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 8516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = tty->driver_data; 8526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) 8546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return; 8556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (sdio_uart_claim_func(port) != 0) 8576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return; 8586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (I_IXOFF(tty)) { 8606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->x_char = STOP_CHAR(tty); 8616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_start_tx(port); 8626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 8636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (tty->termios->c_cflag & CRTSCTS) 8656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_clear_mctrl(port, TIOCM_RTS); 8666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_irq(port->func); 8686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_release_func(port); 8696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 8706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_unthrottle(struct tty_struct *tty) 8726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 8736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = tty->driver_data; 8746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) 8766e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return; 8776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (sdio_uart_claim_func(port) != 0) 8796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return; 8806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (I_IXOFF(tty)) { 8826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (port->x_char) { 8836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->x_char = 0; 8846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } else { 8856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->x_char = START_CHAR(tty); 8866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_start_tx(port); 8876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 8886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 8896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (tty->termios->c_cflag & CRTSCTS) 8916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_set_mctrl(port, TIOCM_RTS); 8926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 8936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_irq(port->func); 8946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_release_func(port); 8956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 8966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 897c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Coxstatic void sdio_uart_set_termios(struct tty_struct *tty, 898c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox struct ktermios *old_termios) 8996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 9006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = tty->driver_data; 9016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int cflag = tty->termios->c_cflag; 9026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 9036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (sdio_uart_claim_func(port) != 0) 9046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return; 9056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 9066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_change_speed(port, tty->termios, old_termios); 9076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 9086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* Handle transition to B0 status */ 9096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) 9106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_clear_mctrl(port, TIOCM_RTS | TIOCM_DTR); 9116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 9126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* Handle transition away from B0 status */ 9136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) { 9146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int mask = TIOCM_DTR; 9156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!(cflag & CRTSCTS) || !test_bit(TTY_THROTTLED, &tty->flags)) 9166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre mask |= TIOCM_RTS; 9176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_set_mctrl(port, mask); 9186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 9196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 9206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* Handle turning off CRTSCTS */ 9216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) { 9226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty->hw_stopped = 0; 9236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_start_tx(port); 9246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 9256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 9266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* Handle turning on CRTSCTS */ 9276e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) { 9286e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) { 9296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty->hw_stopped = 1; 9306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_stop_tx(port); 9316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 9326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 9336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 9346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_release_func(port); 9356e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 9366e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 937c43d8636971c39da993e94082fd65bfff421618eDavid Howellsstatic int sdio_uart_break_ctl(struct tty_struct *tty, int break_state) 9386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 9396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = tty->driver_data; 940c43d8636971c39da993e94082fd65bfff421618eDavid Howells int result; 9416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 942c43d8636971c39da993e94082fd65bfff421618eDavid Howells result = sdio_uart_claim_func(port); 943c43d8636971c39da993e94082fd65bfff421618eDavid Howells if (result != 0) 944c43d8636971c39da993e94082fd65bfff421618eDavid Howells return result; 9456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 9466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (break_state == -1) 9476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->lcr |= UART_LCR_SBC; 9486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre else 9496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->lcr &= ~UART_LCR_SBC; 9506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_out(port, UART_LCR, port->lcr); 9516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 9526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_release_func(port); 953c43d8636971c39da993e94082fd65bfff421618eDavid Howells return 0; 9546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 9556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 95660b33c133ca0b7c0b6072c87234b63fee6e80558Alan Coxstatic int sdio_uart_tiocmget(struct tty_struct *tty) 9576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 9586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = tty->driver_data; 9596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre int result; 9606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 9616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre result = sdio_uart_claim_func(port); 9626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!result) { 9636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre result = port->mctrl | sdio_uart_get_mctrl(port); 9646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_release_func(port); 9656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 9666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 9676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return result; 9686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 9696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 97020b9d17715017ae4dd4ec87fabc36d33b9de708eAlan Coxstatic int sdio_uart_tiocmset(struct tty_struct *tty, 9716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre unsigned int set, unsigned int clear) 9726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 9736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = tty->driver_data; 9746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre int result; 9756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 9761e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo result = sdio_uart_claim_func(port); 977c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox if (!result) { 9786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_update_mctrl(port, set, clear); 9796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_release_func(port); 9806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 9816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 9826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return result; 9836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 9846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 985201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyanstatic int sdio_uart_proc_show(struct seq_file *m, void *v) 9865ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre{ 987201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan int i; 9885ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre 989201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", 9905ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre "", "", ""); 991201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan for (i = 0; i < UART_NR; i++) { 9925ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre struct sdio_uart_port *port = sdio_uart_port_get(i); 9935ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre if (port) { 994201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan seq_printf(m, "%d: uart:SDIO", i); 995c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox if (capable(CAP_SYS_ADMIN)) { 996201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan seq_printf(m, " tx:%d rx:%d", 9971e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo port->icount.tx, port->icount.rx); 9985ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre if (port->icount.frame) 999201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan seq_printf(m, " fe:%d", 10001e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo port->icount.frame); 10015ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre if (port->icount.parity) 1002201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan seq_printf(m, " pe:%d", 10031e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo port->icount.parity); 10045ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre if (port->icount.brk) 1005201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan seq_printf(m, " brk:%d", 10061e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo port->icount.brk); 10075ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre if (port->icount.overrun) 1008201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan seq_printf(m, " oe:%d", 10091e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo port->icount.overrun); 10105ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre if (port->icount.cts) 1011201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan seq_printf(m, " cts:%d", 10121e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo port->icount.cts); 10135ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre if (port->icount.dsr) 1014201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan seq_printf(m, " dsr:%d", 10151e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo port->icount.dsr); 10165ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre if (port->icount.rng) 1017201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan seq_printf(m, " rng:%d", 10181e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo port->icount.rng); 10195ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre if (port->icount.dcd) 1020201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan seq_printf(m, " dcd:%d", 10211e04b7ae709d19d5c9f69c64e1e30253018ce102Thadeu Lima de Souza Cascardo port->icount.dcd); 10225ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre } 10235ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre sdio_uart_port_put(port); 1024201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan seq_putc(m, '\n'); 10255ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre } 10265ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre } 1027201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan return 0; 1028201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan} 10295ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre 1030201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyanstatic int sdio_uart_proc_open(struct inode *inode, struct file *file) 1031201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan{ 1032201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan return single_open(file, sdio_uart_proc_show, NULL); 10335ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre} 10345ed334a1f8caaae98806d572f78c5802975ea20fNicolas Pitre 1035201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyanstatic const struct file_operations sdio_uart_proc_fops = { 1036201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan .owner = THIS_MODULE, 1037201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan .open = sdio_uart_proc_open, 1038201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan .read = seq_read, 1039201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan .llseek = seq_lseek, 1040201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan .release = single_release, 1041201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan}; 1042201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan 1043584abc3775e76c1a2abe725355915851ed23ed6cAlan Coxstatic const struct tty_port_operations sdio_uart_port_ops = { 1044584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox .dtr_rts = uart_dtr_rts, 10454b3b49bb77eddb540e7c69e2129f5334cf713bf8Alan Cox .carrier_raised = uart_carrier_raised, 1046584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox .shutdown = sdio_uart_shutdown, 1047584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox .activate = sdio_uart_activate, 1048584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox}; 1049584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox 10506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic const struct tty_operations sdio_uart_ops = { 10516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .open = sdio_uart_open, 10526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .close = sdio_uart_close, 10536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .write = sdio_uart_write, 10546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .write_room = sdio_uart_write_room, 10556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .chars_in_buffer = sdio_uart_chars_in_buffer, 10566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .send_xchar = sdio_uart_send_xchar, 10576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .throttle = sdio_uart_throttle, 10586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .unthrottle = sdio_uart_unthrottle, 10596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .set_termios = sdio_uart_set_termios, 1060584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox .hangup = sdio_uart_hangup, 10616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .break_ctl = sdio_uart_break_ctl, 10626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .tiocmget = sdio_uart_tiocmget, 10636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .tiocmset = sdio_uart_tiocmset, 1064584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox .install = sdio_uart_install, 1065584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox .cleanup = sdio_uart_cleanup, 1066201a50ba6627dd00aa7b7673a5c454ca387095fbAlexey Dobriyan .proc_fops = &sdio_uart_proc_fops, 10676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}; 10686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 10696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic struct tty_driver *sdio_uart_tty_driver; 10706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 10716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic int sdio_uart_probe(struct sdio_func *func, 10726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre const struct sdio_device_id *id) 10736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 10746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port; 10756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre int ret; 10766e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 10776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port = kzalloc(sizeof(struct sdio_uart_port), GFP_KERNEL); 10786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!port) 10796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return -ENOMEM; 10806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 10816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (func->class == SDIO_CLASS_UART) { 1082a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_warning("%s: need info on UART class basic setup\n", 10836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_func_id(func)); 10846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre kfree(port); 10856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return -ENOSYS; 10866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } else if (func->class == SDIO_CLASS_GPS) { 10876e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre /* 10886e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * We need tuple 0x91. It contains SUBTPL_SIOREG 10896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre * and SUBTPL_RCVCAPS. 10906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre */ 10916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_func_tuple *tpl; 10926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre for (tpl = func->tuples; tpl; tpl = tpl->next) { 10936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (tpl->code != 0x91) 10946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre continue; 10956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (tpl->size < 10) 10966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre continue; 10976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (tpl->data[1] == 0) /* SUBTPL_SIOREG */ 10986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre break; 10996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 11006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!tpl) { 1101a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_warning( 1102c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n", 11036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_func_id(func)); 11046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre kfree(port); 11056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return -EINVAL; 11066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 1107a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_debug("%s: Register ID = 0x%02x, Exp ID = 0x%02x\n", 11086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_func_id(func), tpl->data[2], tpl->data[3]); 11096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->regs_offset = (tpl->data[4] << 0) | 11106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre (tpl->data[5] << 8) | 11116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre (tpl->data[6] << 16); 1112a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_debug("%s: regs offset = 0x%x\n", 11136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_func_id(func), port->regs_offset); 11146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->uartclk = tpl->data[7] * 115200; 11156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (port->uartclk == 0) 11166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->uartclk = 115200; 1117a3c76eb9d4a1e68a69dd880cf0bcb8a52418b993Girish K S pr_debug("%s: clk %d baudcode %u 4800-div %u\n", 11186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_func_id(func), port->uartclk, 11196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tpl->data[7], tpl->data[8] | (tpl->data[9] << 8)); 11206e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } else { 11216e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre kfree(port); 11226e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return -EINVAL; 11236e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 11246e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11256e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre port->func = func; 11266e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_set_drvdata(func, port); 1127b5849b1a82853171ce8a35220204f17ec282a9a8Alan Cox tty_port_init(&port->port); 1128584abc3775e76c1a2abe725355915851ed23ed6cAlan Cox port->port.ops = &sdio_uart_port_ops; 11296e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11306e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret = sdio_uart_add_port(port); 11316e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (ret) { 11326e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre kfree(port); 11336e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } else { 11346e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct device *dev; 1135c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox dev = tty_register_device(sdio_uart_tty_driver, 1136c271cf37ba17631e371c97e2e8c8c353a83793e2Alan Cox port->index, &func->dev); 11376e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (IS_ERR(dev)) { 11386e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_port_remove(port); 11396e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret = PTR_ERR(dev); 11406e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 11416e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre } 11426e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11436e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return ret; 11446e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 11456e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11466e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void sdio_uart_remove(struct sdio_func *func) 11476e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 11486e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct sdio_uart_port *port = sdio_get_drvdata(func); 11496e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11506e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty_unregister_device(sdio_uart_tty_driver, port->index); 11516e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_port_remove(port); 11526e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 11536e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11546e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic const struct sdio_device_id sdio_uart_ids[] = { 11556e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre { SDIO_DEVICE_CLASS(SDIO_CLASS_UART) }, 11566e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre { SDIO_DEVICE_CLASS(SDIO_CLASS_GPS) }, 11576e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre { /* end: all zeroes */ }, 11586e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}; 11596e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11606e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas PitreMODULE_DEVICE_TABLE(sdio, sdio_uart_ids); 11616e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11626e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic struct sdio_driver sdio_uart_driver = { 11636e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .probe = sdio_uart_probe, 11646e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .remove = sdio_uart_remove, 11656e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .name = "sdio_uart", 11666e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre .id_table = sdio_uart_ids, 11676e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre}; 11686e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11696e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic int __init sdio_uart_init(void) 11706e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 11716e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre int ret; 11726e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre struct tty_driver *tty_drv; 11736e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11746e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_uart_tty_driver = tty_drv = alloc_tty_driver(UART_NR); 11756e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (!tty_drv) 11766e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return -ENOMEM; 11776e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11786e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty_drv->driver_name = "sdio_uart"; 11796e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty_drv->name = "ttySDIO"; 11806e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty_drv->major = 0; /* dynamically allocated */ 11816e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty_drv->minor_start = 0; 11826e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty_drv->type = TTY_DRIVER_TYPE_SERIAL; 11836e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty_drv->subtype = SERIAL_TYPE_NORMAL; 11846e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV; 11856e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty_drv->init_termios = tty_std_termios; 11866e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty_drv->init_termios.c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL; 11872ba30eedec37e2f65babf4ea54233f98afbe0871Nicolas Pitre tty_drv->init_termios.c_ispeed = 4800; 11882ba30eedec37e2f65babf4ea54233f98afbe0871Nicolas Pitre tty_drv->init_termios.c_ospeed = 4800; 11896e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty_set_operations(tty_drv, &sdio_uart_ops); 11906e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11916e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret = tty_register_driver(tty_drv); 11926e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (ret) 11936e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre goto err1; 11946e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11956e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre ret = sdio_register_driver(&sdio_uart_driver); 11966e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre if (ret) 11976e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre goto err2; 11986e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 11996e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return 0; 12006e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 12016e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitreerr2: 12026e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty_unregister_driver(tty_drv); 12036e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitreerr1: 12046e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre put_tty_driver(tty_drv); 12056e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre return ret; 12066e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 12076e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 12086e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitrestatic void __exit sdio_uart_exit(void) 12096e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre{ 12106e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre sdio_unregister_driver(&sdio_uart_driver); 12116e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre tty_unregister_driver(sdio_uart_tty_driver); 12126e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre put_tty_driver(sdio_uart_tty_driver); 12136e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre} 12146e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 12156e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitremodule_init(sdio_uart_init); 12166e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitremodule_exit(sdio_uart_exit); 12176e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas Pitre 12186e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas PitreMODULE_AUTHOR("Nicolas Pitre"); 12196e418a9d26ab4fd44b3e07dc1158027cbdf0a919Nicolas PitreMODULE_LICENSE("GPL"); 1220