10b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger/* 20b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger * TTY over Blackfin JTAG Communication 30b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger * 40b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger * Copyright 2008-2009 Analog Devices Inc. 50b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger * 60b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger * Enter bugs at http://blackfin.uclinux.org/ 70b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger * 80b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger * Licensed under the GPL-2 or later. 90b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger */ 100b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 1156578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger#define DRV_NAME "bfin-jtag-comm" 1256578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger#define DEV_NAME "ttyBFJC" 1356578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger#define pr_fmt(fmt) DRV_NAME ": " fmt 1456578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger 150b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#include <linux/circ_buf.h> 160b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#include <linux/console.h> 170b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#include <linux/delay.h> 180b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#include <linux/err.h> 190b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#include <linux/kernel.h> 200b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#include <linux/kthread.h> 210b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#include <linux/module.h> 220b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#include <linux/mutex.h> 230b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#include <linux/sched.h> 245a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h> 250b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#include <linux/tty.h> 260b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#include <linux/tty_driver.h> 270b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#include <linux/tty_flip.h> 2860063497a95e716c9a689af3be2687d261f115b4Arun Sharma#include <linux/atomic.h> 290b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 3056578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger#define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); }) 3156578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger 320b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger/* See the Debug/Emulation chapter in the HRM */ 330b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#define EMUDOF 0x00000001 /* EMUDAT_OUT full & valid */ 340b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#define EMUDIF 0x00000002 /* EMUDAT_IN full & valid */ 350b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#define EMUDOOVF 0x00000004 /* EMUDAT_OUT overflow */ 360b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#define EMUDIOVF 0x00000008 /* EMUDAT_IN overflow */ 370b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 380b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic inline uint32_t bfin_write_emudat(uint32_t emudat) 390b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 400b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger __asm__ __volatile__("emudat = %0;" : : "d"(emudat)); 410b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return emudat; 420b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 430b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 440b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic inline uint32_t bfin_read_emudat(void) 450b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 460b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger uint32_t emudat; 470b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger __asm__ __volatile__("%0 = emudat;" : "=d"(emudat)); 480b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return emudat; 490b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 500b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 510b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic inline uint32_t bfin_write_emudat_chars(char a, char b, char c, char d) 520b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 530b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return bfin_write_emudat((a << 0) | (b << 8) | (c << 16) | (d << 24)); 540b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 550b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 560b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#define CIRC_SIZE 2048 /* see comment in tty_io.c:do_tty_write() */ 570b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#define CIRC_MASK (CIRC_SIZE - 1) 580b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#define circ_empty(circ) ((circ)->head == (circ)->tail) 590b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#define circ_free(circ) CIRC_SPACE((circ)->head, (circ)->tail, CIRC_SIZE) 600b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#define circ_cnt(circ) CIRC_CNT((circ)->head, (circ)->tail, CIRC_SIZE) 610b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#define circ_byte(circ, idx) ((circ)->buf[(idx) & CIRC_MASK]) 620b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 630b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic struct tty_driver *bfin_jc_driver; 640b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic struct task_struct *bfin_jc_kthread; 650b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic struct tty_struct * volatile bfin_jc_tty; 660b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic unsigned long bfin_jc_count; 670b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic DEFINE_MUTEX(bfin_jc_tty_mutex); 680b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic volatile struct circ_buf bfin_jc_write_buf; 690b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 700b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic int 710b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_emudat_manager(void *arg) 720b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 730b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger uint32_t inbound_len = 0, outbound_len = 0; 740b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 750b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger while (!kthread_should_stop()) { 760b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger /* no one left to give data to, so sleep */ 770b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (bfin_jc_tty == NULL && circ_empty(&bfin_jc_write_buf)) { 7856578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger pr_debug("waiting for readers\n"); 790b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger __set_current_state(TASK_UNINTERRUPTIBLE); 800b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger schedule(); 810b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger __set_current_state(TASK_RUNNING); 820b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger } 830b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 840b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger /* no data available, so just chill */ 850b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (!(bfin_read_DBGSTAT() & EMUDIF) && circ_empty(&bfin_jc_write_buf)) { 8656578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger pr_debug("waiting for data (in_len = %i) (circ: %i %i)\n", 870b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger inbound_len, bfin_jc_write_buf.tail, bfin_jc_write_buf.head); 880b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (inbound_len) 890b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger schedule(); 900b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger else 910b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger schedule_timeout_interruptible(HZ); 920b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger continue; 930b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger } 940b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 950b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger /* if incoming data is ready, eat it */ 960b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (bfin_read_DBGSTAT() & EMUDIF) { 970b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger struct tty_struct *tty; 980b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger mutex_lock(&bfin_jc_tty_mutex); 990b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger tty = (struct tty_struct *)bfin_jc_tty; 1000b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (tty != NULL) { 1010b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger uint32_t emudat = bfin_read_emudat(); 1020b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (inbound_len == 0) { 10356578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger pr_debug("incoming length: 0x%08x\n", emudat); 1040b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger inbound_len = emudat; 1050b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger } else { 1060b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger size_t num_chars = (4 <= inbound_len ? 4 : inbound_len); 10756578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger pr_debug(" incoming data: 0x%08x (pushing %zu)\n", emudat, num_chars); 1080b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger inbound_len -= num_chars; 1090b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger tty_insert_flip_string(tty, (unsigned char *)&emudat, num_chars); 1100b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger tty_flip_buffer_push(tty); 1110b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger } 1120b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger } 1130b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger mutex_unlock(&bfin_jc_tty_mutex); 1140b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger } 1150b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 1160b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger /* if outgoing data is ready, post it */ 1170b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (!(bfin_read_DBGSTAT() & EMUDOF) && !circ_empty(&bfin_jc_write_buf)) { 1180b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (outbound_len == 0) { 1190b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger outbound_len = circ_cnt(&bfin_jc_write_buf); 1200b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_write_emudat(outbound_len); 12156578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger pr_debug("outgoing length: 0x%08x\n", outbound_len); 1220b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger } else { 1230b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger struct tty_struct *tty; 1240b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger int tail = bfin_jc_write_buf.tail; 1250b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger size_t ate = (4 <= outbound_len ? 4 : outbound_len); 1260b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger uint32_t emudat = 1270b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_write_emudat_chars( 1280b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger circ_byte(&bfin_jc_write_buf, tail + 0), 1290b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger circ_byte(&bfin_jc_write_buf, tail + 1), 1300b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger circ_byte(&bfin_jc_write_buf, tail + 2), 1310b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger circ_byte(&bfin_jc_write_buf, tail + 3) 1320b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger ); 1330b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_write_buf.tail += ate; 1340b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger outbound_len -= ate; 1350b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger mutex_lock(&bfin_jc_tty_mutex); 1360b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger tty = (struct tty_struct *)bfin_jc_tty; 1370b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (tty) 1380b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger tty_wakeup(tty); 1390b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger mutex_unlock(&bfin_jc_tty_mutex); 14056578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger pr_debug(" outgoing data: 0x%08x (pushing %zu)\n", emudat, ate); 1410b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger } 1420b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger } 1430b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger } 1440b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 1450b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger __set_current_state(TASK_RUNNING); 1460b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return 0; 1470b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 1480b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 1490b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic int 1500b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_open(struct tty_struct *tty, struct file *filp) 1510b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 1520b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger mutex_lock(&bfin_jc_tty_mutex); 15356578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger pr_debug("open %lu\n", bfin_jc_count); 1540b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger ++bfin_jc_count; 1550b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_tty = tty; 1560b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger wake_up_process(bfin_jc_kthread); 1570b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger mutex_unlock(&bfin_jc_tty_mutex); 1580b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return 0; 1590b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 1600b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 1610b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic void 1620b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_close(struct tty_struct *tty, struct file *filp) 1630b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 1640b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger mutex_lock(&bfin_jc_tty_mutex); 16556578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger pr_debug("close %lu\n", bfin_jc_count); 1660b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (--bfin_jc_count == 0) 1670b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_tty = NULL; 1680b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger wake_up_process(bfin_jc_kthread); 1690b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger mutex_unlock(&bfin_jc_tty_mutex); 1700b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 1710b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 1720b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger/* XXX: we dont handle the put_char() case where we must handle count = 1 */ 1730b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic int 1740b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_circ_write(const unsigned char *buf, int count) 1750b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 1760b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger int i; 1770b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger count = min(count, circ_free(&bfin_jc_write_buf)); 17856578abfd16a1a7554f64000d5fc0a377d4dda6aMike Frysinger pr_debug("going to write chunk of %i bytes\n", count); 1790b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger for (i = 0; i < count; ++i) 1800b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger circ_byte(&bfin_jc_write_buf, bfin_jc_write_buf.head + i) = buf[i]; 1810b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_write_buf.head += i; 1820b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return i; 1830b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 1840b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 1850b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#ifndef CONFIG_BFIN_JTAG_COMM_CONSOLE 186ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn# define console_lock() 187ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn# define console_unlock() 1880b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#endif 1890b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic int 1900b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_write(struct tty_struct *tty, const unsigned char *buf, int count) 1910b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 1920b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger int i; 193ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_lock(); 1940b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger i = bfin_jc_circ_write(buf, count); 195ac751efa6a0d70f2c9daef5c7e3a92270f5c2dffTorben Hohn console_unlock(); 1960b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger wake_up_process(bfin_jc_kthread); 1970b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return i; 1980b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 1990b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2000b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic void 2010b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_flush_chars(struct tty_struct *tty) 2020b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 2030b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger wake_up_process(bfin_jc_kthread); 2040b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 2050b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2060b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic int 2070b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_write_room(struct tty_struct *tty) 2080b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 2090b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return circ_free(&bfin_jc_write_buf); 2100b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 2110b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2120b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic int 2130b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_chars_in_buffer(struct tty_struct *tty) 2140b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 2150b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return circ_cnt(&bfin_jc_write_buf); 2160b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 2170b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2180b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic void 2190b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_wait_until_sent(struct tty_struct *tty, int timeout) 2200b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 2210b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger unsigned long expire = jiffies + timeout; 2220b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger while (!circ_empty(&bfin_jc_write_buf)) { 2230b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (signal_pending(current)) 2240b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger break; 2250b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (time_after(jiffies, expire)) 2260b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger break; 2270b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger } 2280b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 2290b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2301cceefd3a28e54c0777fe544e1fd32253b2a1de5Alexey Dobriyanstatic const struct tty_operations bfin_jc_ops = { 2310b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .open = bfin_jc_open, 2320b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .close = bfin_jc_close, 2330b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .write = bfin_jc_write, 2340b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger /*.put_char = bfin_jc_put_char,*/ 2350b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .flush_chars = bfin_jc_flush_chars, 2360b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .write_room = bfin_jc_write_room, 2370b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .chars_in_buffer = bfin_jc_chars_in_buffer, 2380b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .wait_until_sent = bfin_jc_wait_until_sent, 2390b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger}; 2400b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2410b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic int __init bfin_jc_init(void) 2420b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 2430b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger int ret; 2440b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2450b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_kthread = kthread_create(bfin_jc_emudat_manager, NULL, DRV_NAME); 2460b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (IS_ERR(bfin_jc_kthread)) 2470b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return PTR_ERR(bfin_jc_kthread); 2480b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2490b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger ret = -ENOMEM; 2500b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2510b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_write_buf.head = bfin_jc_write_buf.tail = 0; 2520b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_write_buf.buf = kmalloc(CIRC_SIZE, GFP_KERNEL); 2530b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (!bfin_jc_write_buf.buf) 254d9d691f584bd012d235c35279c043a2ccd23d7d7Julia Lawall goto err_buf; 2550b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2560b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_driver = alloc_tty_driver(1); 2570b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (!bfin_jc_driver) 258d9d691f584bd012d235c35279c043a2ccd23d7d7Julia Lawall goto err_driver; 2590b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2600b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_driver->driver_name = DRV_NAME; 2610b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_driver->name = DEV_NAME; 2620b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_driver->type = TTY_DRIVER_TYPE_SERIAL; 2630b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_driver->subtype = SERIAL_TYPE_NORMAL; 2640b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_driver->init_termios = tty_std_termios; 2650b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger tty_set_operations(bfin_jc_driver, &bfin_jc_ops); 2660b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2670b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger ret = tty_register_driver(bfin_jc_driver); 2680b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (ret) 2690b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger goto err; 2700b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2710b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger pr_init(KERN_INFO DRV_NAME ": initialized\n"); 2720b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2730b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return 0; 2740b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2750b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger err: 2760b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger put_tty_driver(bfin_jc_driver); 277d9d691f584bd012d235c35279c043a2ccd23d7d7Julia Lawall err_driver: 2780b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger kfree(bfin_jc_write_buf.buf); 279d9d691f584bd012d235c35279c043a2ccd23d7d7Julia Lawall err_buf: 2800b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger kthread_stop(bfin_jc_kthread); 2810b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return ret; 2820b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 2830b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingermodule_init(bfin_jc_init); 2840b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2850b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic void __exit bfin_jc_exit(void) 2860b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 2870b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger kthread_stop(bfin_jc_kthread); 2880b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger kfree(bfin_jc_write_buf.buf); 2890b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger tty_unregister_driver(bfin_jc_driver); 2900b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger put_tty_driver(bfin_jc_driver); 2910b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 2920b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingermodule_exit(bfin_jc_exit); 2930b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 2940b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#if defined(CONFIG_BFIN_JTAG_COMM_CONSOLE) || defined(CONFIG_EARLY_PRINTK) 2950b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic void 2960b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_straight_buffer_write(const char *buf, unsigned count) 2970b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 2980b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger unsigned ate = 0; 2990b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger while (bfin_read_DBGSTAT() & EMUDOF) 3000b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger continue; 3010b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_write_emudat(count); 3020b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger while (ate < count) { 3030b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger while (bfin_read_DBGSTAT() & EMUDOF) 3040b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger continue; 3050b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_write_emudat_chars(buf[ate], buf[ate+1], buf[ate+2], buf[ate+3]); 3060b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger ate += 4; 3070b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger } 3080b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 3090b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#endif 3100b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 3110b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#ifdef CONFIG_BFIN_JTAG_COMM_CONSOLE 3120b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic void 3130b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_console_write(struct console *co, const char *buf, unsigned count) 3140b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 3150b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger if (bfin_jc_kthread == NULL) 3160b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_straight_buffer_write(buf, count); 3170b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger else 3180b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_circ_write(buf, count); 3190b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 3200b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 3210b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic struct tty_driver * 3220b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_console_device(struct console *co, int *index) 3230b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 3240b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger *index = co->index; 3250b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return bfin_jc_driver; 3260b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 3270b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 3280b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic struct console bfin_jc_console = { 3290b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .name = DEV_NAME, 3300b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .write = bfin_jc_console_write, 3310b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .device = bfin_jc_console_device, 3320b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .flags = CON_ANYTIME | CON_PRINTBUFFER, 3330b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .index = -1, 3340b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger}; 3350b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 3360b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic int __init bfin_jc_console_init(void) 3370b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 3380b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger register_console(&bfin_jc_console); 3390b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return 0; 3400b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 3410b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerconsole_initcall(bfin_jc_console_init); 3420b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#endif 3430b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 3440b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#ifdef CONFIG_EARLY_PRINTK 3450b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic void __init 3460b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_early_write(struct console *co, const char *buf, unsigned int count) 3470b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 3480b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger bfin_jc_straight_buffer_write(buf, count); 3490b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 3500b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 3510b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstatic struct __initdata console bfin_jc_early_console = { 3520b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .name = "early_BFJC", 3530b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .write = bfin_jc_early_write, 3540b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .flags = CON_ANYTIME | CON_PRINTBUFFER, 3550b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger .index = -1, 3560b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger}; 3570b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 3580b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerstruct console * __init 3590b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysingerbfin_jc_early_init(unsigned int port, unsigned int cflag) 3600b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger{ 3610b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger return &bfin_jc_early_console; 3620b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger} 3630b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger#endif 3640b91421857414f525690ee452c0b0acb6ab1dba3Mike Frysinger 3650b91421857414f525690ee452c0b0acb6ab1dba3Mike FrysingerMODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>"); 3660b91421857414f525690ee452c0b0acb6ab1dba3Mike FrysingerMODULE_DESCRIPTION("TTY over Blackfin JTAG Communication"); 3670b91421857414f525690ee452c0b0acb6ab1dba3Mike FrysingerMODULE_LICENSE("GPL"); 368