SCC2691 UART , writing device drivers , debug help
From: Rushi Lala (rushi.lala_at_gmail.com)
Date: 10/29/04
- Next message: Antonio Musumeci: "Re: mmap & MAP_FIXED"
- Previous message: Dragan Cvetkovic: "Re: mmap & MAP_FIXED"
- Next in thread: Gary Kato: "Re: SCC2691 UART , writing device drivers , debug help"
- Reply: Gary Kato: "Re: SCC2691 UART , writing device drivers , debug help"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: 29 Oct 2004 04:53:45 -0700
uart_irq, termios help
I am porting Vxworks custom drivers for SCC2691 UART to linux. When i
try to open and write from simple user application driver goes in to
open and then close but it never goes to write function.
I am wondering why ?? any ideas ??
I still have to implement set_cflag, but right now i am just asking
UART to run on fix baud 19200.
Do i need to implement console drivers for rs422 communication with
custom hardware ?
Why user application is not calling write function at all ?
Any help is appreciated .
Rushi
/*
* This program is free software; you can redistribute it and/or
modify
* it under the terms of the GNU General Public License as published
by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA.
*/
//Written by Rushi Lala <rushi@iee.org>, 2004
/* linux/drivers/char/scc2691_tty.c */
//****************************************************************************
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/major.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/mm.h>
#include <linux/malloc.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/console.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
//****************************************************************************
#define DRIVER_VERSION "Debug V1.1"
#define DRIVER_DESC "scc2691_drivers"
#define base_addr 0x8620
# define preset 0xF8CC
#define TRUE 1
#define FALSE 0
//********************************************************************************
#define IRQ_DUART 15
#define MSB(x) (((x) >> 8) & 0xff) /* most signif byte of 2-byte
integer*/
#define LSB(x) ((x) & 0xff) /* least signif byte of 2-byte
integer*/
#define BASE_ADDR 0x8620
#define PRESET 0xF8CC
#define SERIAL_2691_NAME "ttyS2691"
#define SERIAL_2691_MAJOR 4
#define SERIAL_2691_MINOR 255
#define KDEBUG 1
//********************************************************************************
//****************************************************************************
// SCC2691 UART Register Map
// Spacings are multiplied by 2 since address line A0 is not used
#define SCC2691_MR (2 * 0x00) // Mode Register (uses Aux
pointer)
#define SCC2691_SR (2 * 0x01) // Status Register (read only)
#define SCC2691_CSR (2 * 0x01) // Clock Select Register
(write only)
#define SCC2691_CR (2 * 0x02) // Command Register (write
only)
#define SCC2691_RHR (2 * 0x03) // Rx Holding Register (read
only)
#define SCC2691_THR (2 * 0x03) // Tx Holding Register (write
only)
#define SCC2691_ACR (2 * 0x04) // Auxiliary Control Register
(write only)
#define SCC2691_ISR (2 * 0x05) // Interrupt Status Register
(read only)
#define SCC2691_IMR (2 * 0x05) // Interrupt Mask Register
(write only)
#define SCC2691_CTU (2 * 0x06) // Counter/Timer Upper Output
Register (read only)
#define SCC2691_CTUR (2 * 0x06) // Counter/Timer Upper Preset
Register (write only)
#define SCC2691_CTL (2 * 0x07) // Counter/Timer Lower Output
Register (read only)
#define SCC2691_CTLR (2 * 0x07) // Counter/Timer Lower Preset
Register (write only)
#define SCC2691_ERR_MASK 0xF0
#define SCC2691_ERR_OE 0x10 // Overrun error
#define SCC2691_ERR_PE 0x20 // Parity Error
#define SCC2691_ERR_FE 0x40 // Framing Error
#define SCC2691_ERR_BI 0x80 // Break Interrupt
#define SCC2691_RX_RDY 0x01
#define SCC2691_FFULL 0x02
#define SCC2691_TX_RDY 0x04
#define SCC2691_TX_EMT 0x08
//****************************************************************************
//****************************************************************************
static struct tty_driver scc2691_driver ;
static int scc2691_refcount;
static struct tty_struct *scc2691_tty;
static int scc2691_use_count;
static struct tty_struct *scc2691_table[1];
static struct termios *scc2691_termios[1];
static struct termios *scc2691_termios_locked[1];
static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char;
//****************************************************************************
int isr_count = 0;
int err_count = 0;
int rx_count = 0;
int tx_count = 0;
int max_ix = 0;
int tx_int_on = 0 ;
int repeat_count = 0;
int repeat_errors;
char repeat_char = 0;
//*****************init
UART*******************************************************
void init_uart(void)
{
outw(0x30,BASE_ADDR + SCC2691_CR); // Reset Tx
outw(0x20,BASE_ADDR + SCC2691_CR); // Reset Rx
outw(0x00,BASE_ADDR + SCC2691_IMR); // Disable interrupts - get
enabled later
outw(0x1A,BASE_ADDR + SCC2691_CR); // Reset MR pointer, disable
Tx and Rx
outw(0x13,BASE_ADDR + SCC2691_MR); // 8-bits, no parity
outw(0x07,BASE_ADDR + SCC2691_MR); // 1 stop bit
outw(0xA0,BASE_ADDR + SCC2691_CR); // Assert MPO low - enables
422 driver
#ifdef KDEBUG
printk("DUART: init scc2691- \n");
#endif
outw(MSB(preset),BASE_ADDR + SCC2691_ACR); //speed
outw (LSB(preset),BASE_ADDR + SCC2691_CSR);
#ifdef KDEBUG
printk("DUART: set the spped - \n");
#endif
}
//****************************************************************************
static int scc2691_write_room(struct tty_struct *tty)
{
#ifdef KDEBUG
printk("DUART: scc2691_write_room - \n");
#endif
return putp >= getp ? (sizeof(wbuf) - (long) putp + (long) getp) :
((long) getp - (long) putp - 1);
}
//****************************************************************************
static void scc2691_send_xchar(struct tty_struct *tty, char ch)
{
#ifdef KDEBUG
printk("DUART: scc2691_send_xchar - \n");
#endif
x_char = ch;
enable_irq(IRQ_DUART);
}
//****************************************************************************
static void scc2691_throttle(struct tty_struct *tty)
{
#ifdef KDEBUG
printk("DUART: scc2691_throttle - \n ");
#endif
if (I_IXOFF(tty))
scc2691_send_xchar(tty, STOP_CHAR(tty));
}
//****************************************************************************
//****************************************************************************
static void scc2691_unthrottle(struct tty_struct *tty)
{
#ifdef KDEBUG
printk("DUART: scc2691_unthrottle - \n");
#endif
if (I_IXOFF(tty)) {
if (x_char)
x_char = 0;
else
scc2691_send_xchar(tty, START_CHAR(tty));
}
}
//****************************************************************************
//****************************************************************************
static int scc2691_chars_in_buffer(struct tty_struct *tty)
{
#ifdef KDEBUG
printk("DUART: scc2691_chars_in_buffer - \n");
#endif
return sizeof(wbuf) - scc2691_write_room(tty);
}
//****************************************************************************
static void scc2691_flush_buffer(struct tty_struct *tty)
{
#ifdef KDEBUG
printk("DUART: scc2691_flush_buffer - \n ");
#endif
disable_irq(IRQ_DUART);
putp = getp = wbuf;
if (x_char)
enable_irq(IRQ_DUART);
}
//****************************************************************************
static inline int scc2691_xmit(int ch)
{
#ifdef KDEBUG
printk("DUART: scc2691_xmit ** %c ** - \n",ch);
#endif
if (putp + 1 == getp || (putp + 1 == wbuf + sizeof(wbuf) && getp ==
wbuf))
return 0;
*putp = ch;
if (++putp >= wbuf + sizeof(wbuf))
putp = wbuf;
outw(0x05,BASE_ADDR + SCC2691_IMR); // IMR
tx_int_on = TRUE;
enable_irq(IRQ_DUART);
return 1;
}
//****************************************************************************
//****************************************************************************
static int scc2691_write(struct tty_struct *tty, int from_user,
const u_char * buf, int count)
{
int i;
#ifdef KDEBUG
printk("DUART: scc2691_write -\n ");
#endif
if (from_user && verify_area(VERIFY_READ, buf, count))
{
#ifdef KDEBUG
printk("DUART: not from user space return -\n ");
#endif
return -EINVAL;
}
for (i = 0; i < count; i++) {
char ch;
if (from_user)
{ __get_user(ch, buf + i);
#ifdef KDEBUG
printk("DUART: scc2691_write FROM USER %c -\n", ch);
#endif
}
else
ch = buf[i];
if (!scc2691_xmit(ch))
break;
}
return i;
}
//****************************************************************************
//****************************************************************************
static void scc2691_put_char(struct tty_struct *tty, u_char ch)
{
#ifdef KDEBUG
printk("DUART: scc2691_put_char - \n");
#endif
scc2691_xmit(ch);
}
//****************************************************************************
//****************************************************************************
static int scc2691_open(struct tty_struct *tty, struct file *filp)
{
MOD_INC_USE_COUNT;
#ifdef KDEBUG
printk("DUART: scc2691_open - \n");
#endif
tty->driver_data = NULL;
if (!scc2691_tty)
{
scc2691_tty = tty;
#ifdef KDEBUG
printk("DUART: scc2691_tty scc2691_tty = tty - \n");
#endif
}
scc2691_use_count++;
init_uart(); // reset the port again
outw(0x40,BASE_ADDR + SCC2691_CR ); // Clear any outstanding
errors
outw(0x05,BASE_ADDR + SCC2691_CR ); // Enable Rx and Tx
outw(0x04,BASE_ADDR + SCC2691_IMR ); // Enable interrupts
enable_irq(IRQ_DUART);
#ifdef KDEBUG
printk("DUART: enable tx, rx - \n");
#endif
return 0;
}
//****************************************************************************
static void scc2691_wait_until_sent(struct tty_struct *tty, int
timeout)
{
#ifdef KDEBUG
printk("DUART: scc2691_wait_until_sent - \n");
#endif
int orig_jiffies = jiffies;
// Wait till TxEMT in SR
while (SCC2691_SR & 0x08) {
current->state = TASK_INTERRUPTIBLE;
schedule_timeout(1);
if (signal_pending(current))
break;
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
current->state = TASK_RUNNING;
}
static void scc2691_close(struct tty_struct *tty, struct file *filp)
{
#ifdef KDEBUG
printk("DUART: scc2691_close - \n");
#endif
if (!--scc2691_use_count)
{
//scc2691_wait_until_sent(tty, 0);
disable_irq(IRQ_DUART);
scc2691_tty = NULL;
}
MOD_DEC_USE_COUNT;
}
static void duart_irq(int irq, void *dev_id, struct pt_regs *regs)
{
#ifdef KDEBUG
printk("DUART: duart_irq - \n");
#endif
int interruptID,flag = 0;
char ch;
if (!scc2691_tty) {
disable_irq(IRQ_DUART);
return;
}
interruptID = inw(BASE_ADDR + SCC2691_SR); // Get 8 bit Status
Register
if (interruptID & SCC2691_ERR_MASK) // Mask last 4 bits
for with Error flags so get error flags
{
// if error
err_count ++;
outw(0x40,BASE_ADDR + SCC2691_CR); // Reset errors
outw(0x20, BASE_ADDR + SCC2691_CR ); // Reset (and
disable) Rx
outw(0x01, BASE_ADDR + SCC2691_CR ); // Re-enable Rx
interruptID = inw(BASE_ADDR + SCC2691_SR); // Get 8 bit
Status Register
}
while (tx_int_on && (interruptID & SCC2691_TX_RDY)) {
if (x_char) {
#ifdef KDEBUG
printk("CHAR FROM USER %c - \n",ch);
#endif
outw(ch,BASE_ADDR + SCC2691_THR); // put the data in Tx holding
Register
x_char = 0;
continue;
}
if (putp == getp) {
disable_irq(IRQ_DUART);
break;
}
outw(0x04,BASE_ADDR + SCC2691_IMR); // set IMR to 100 rx full and
there is set tx_int_on false
outw(*getp,BASE_ADDR + SCC2691_THR); // put the data in Tx
holding Register
tx_int_on = FALSE;
if (++getp >= wbuf + sizeof(wbuf))
getp = wbuf;
}
if (scc2691_tty)
wake_up_interruptible(&scc2691_tty->write_wait);
while (interruptID & SCC2691_RX_RDY) // Last bit of CR is RX Enable
so if Data Ready
{
rx_count ++; // count rx
ch = inw(BASE_ADDR + SCC2691_RHR); // read holding
register
if (ch == repeat_char)
{
repeat_count++;
if (repeat_count > 10) // If there are more then 10
repeat_char then reset the UART
{
repeat_errors++;
repeat_count = 0;
outw(0x40,BASE_ADDR + SCC2691_CR); // Reset
errors
outw(0x20,BASE_ADDR + SCC2691_CR); // Reset
(and disable) Rx
outw(0x01,BASE_ADDR + SCC2691_CR); // Re-enable
Rx
interruptID = inw(BASE_ADDR + SCC2691_SR); // Get 8 bit Status
Register
}
}
else
{
repeat_char = ch;
repeat_count = 0;
}
tty_insert_flip_char(scc2691_tty, ch, flag);
//User space
}
tty_flip_buffer_push(scc2691_tty);
}
static void scc2691_stop(struct tty_struct *tty)
{
#ifdef KDEBUG
printk("DUART: scc2691_stop - \n ");
#endif
disable_irq(IRQ_DUART);
}
static void scc2691_start(struct tty_struct *tty)
{
#ifdef KDEBUGksdb.sh
printk("DUART: scc2691_start - \n");
#endif
enable_irq(IRQ_DUART);
}
//****************************************************************************
int __init scc2691_init(void)
{
memset(&scc2691_driver, 0, sizeof(scc2691_driver));
scc2691_driver.magic = TTY_DRIVER_MAGIC;
scc2691_driver.driver_name = "SCC2691";
scc2691_driver.name = SERIAL_2691_NAME;
scc2691_driver.major = SERIAL_2691_MAJOR;
scc2691_driver.minor_start = SERIAL_2691_MINOR;
scc2691_driver.num = 1;
scc2691_driver.type = TTY_DRIVER_TYPE_SERIAL;
scc2691_driver.subtype = SERIAL_TYPE_NORMAL;
scc2691_driver.init_termios = tty_std_termios;
scc2691_driver.init_termios.c_cflag = B19200 | CS8 | CREAD | HUPCL |
CLOCAL;
scc2691_driver.flags = TTY_DRIVER_REAL_RAW;
scc2691_driver.refcount = &scc2691_refcount;
scc2691_driver.table = scc2691_table;
scc2691_driver.termios = scc2691_termios;
scc2691_driver.termios_locked = scc2691_termios_locked;
scc2691_driver.open = scc2691_open;
scc2691_driver.close = scc2691_close;
scc2691_driver.stop = scc2691_stop;
scc2691_driver.start = scc2691_start;
scc2691_driver.stop = scc2691_write;
scc2691_driver.put_char = scc2691_put_char;
scc2691_driver.start = scc2691_xmit;
scc2691_driver.write_room = scc2691_write_room;
scc2691_driver.chars_in_buffer = scc2691_chars_in_buffer;
scc2691_driver.flush_buffer = scc2691_flush_buffer;
scc2691_driver.throttle = scc2691_throttle;
scc2691_driver.unthrottle = scc2691_unthrottle;
scc2691_driver.send_xchar = scc2691_send_xchar;
scc2691_driver.hangup = NULL;
scc2691_driver.break_ctl = NULL;
scc2691_driver.read_proc = NULL;
if (tty_register_driver(&scc2691_driver)) {
printk(KERN_ERR "Couldn't register scc2691 serial driver\n");
return -EAGAIN;
}
if (request_irq(IRQ_DUART, duart_irq, SA_SHIRQ, "scc2691",
&scc2691_tty)) {
printk(KERN_ERR "Couldn't register for scc2691 irqs\n");
return -EAGAIN;
}
printk(DRIVER_DESC ":"DRIVER_VERSION "Rushi Lala" );
init_uart(); // initialise the UART
return 0;
}
module_init(scc2691_init);
MODULE_AUTHOR("Rushi Lala");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
EXPORT_NO_SYMBOLS;
- Next message: Antonio Musumeci: "Re: mmap & MAP_FIXED"
- Previous message: Dragan Cvetkovic: "Re: mmap & MAP_FIXED"
- Next in thread: Gary Kato: "Re: SCC2691 UART , writing device drivers , debug help"
- Reply: Gary Kato: "Re: SCC2691 UART , writing device drivers , debug help"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|