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