예제 #1
0
static void rs_interruptRx(int irq, void *dev_id, struct pt_regs *regs)
{
	struct s3c3410_serial *info = &s3c3410_info;
	struct tty_struct *tty = info->tty;
	unsigned int count;
	volatile u_int8_t status, fifo_status;

	if (!info || !tty || (!(info->flags & S_INITIALIZED)))
		return;

	if ((tty->flip.count + RX_FIFO_DEPTH) >= TTY_FLIPBUF_SIZE)
		queue_task_irq_off(&tty->flip.tqueue, &tq_timer);

	count = RX_FIFO_DEPTH;
	do {
		status = inb(S3C3410X_UART_BASE+S3C3410X_USTAT);
		if (!(status & USTAT_RFDR))
			break;

		/* check all error flags and accept data if valid */
		fifo_status = inb(S3C3410X_UART_BASE+S3C3410X_UFSTAT);
		if (!(status & USTAT_ERROR) && !(fifo_status & UFSTAT_ERROR))
			*tty->flip.flag_buf_ptr = TTY_NORMAL;
		else {
			if (fifo_status & UFSTAT_RFF) {
				*tty->flip.flag_buf_ptr = TTY_NORMAL;
				handle_status (info, UFSTAT_RFF);
			}
			if (status & USTAT_OE) {
				*tty->flip.flag_buf_ptr = TTY_OVERRUN;
				handle_status (info, USTAT_OE);
			}
			if 	(status & USTAT_BD) {
				*tty->flip.flag_buf_ptr = TTY_BREAK;
				handle_status (info, USTAT_BD);
			}
			if	(status & USTAT_PE) {
				*tty->flip.flag_buf_ptr = TTY_PARITY;
				handle_status (info, USTAT_PE);
			}
			if 	(status & USTAT_FE) {
				*tty->flip.flag_buf_ptr = TTY_FRAME;
				handle_status (info, USTAT_FE);
			}
		}
		*tty->flip.char_buf_ptr++ = 
			inb(S3C3410X_UART_BASE+S3C3410X_URXH_B);
		tty->flip.flag_buf_ptr++;
		tty->flip.count++;
	} while ((--count > 0) && !(status & USTAT_ERROR) && 
		!(fifo_status & UFSTAT_ERROR) );

//     if (fifo_status & (U_RFOV | U_E_RxTO))
// 		handle_status (info, (U_RFOV | U_E_RxTO));
	
	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);	
}
예제 #2
0
/*
 * This routine is used by the interrupt handler to schedule
 * processing in the software interrupt portion of the driver.
 */
static _INLINE_ void rs_sched_event(struct LEON_serial *info,
				    int event)
{
	info->event |= 1 << event;
	queue_task_irq_off(&info->tqueue, &tq_serial);
	mark_bh(SERIAL_BH);
}
예제 #3
0
/*
 * This routine is used by the interrupt handler to schedule
 * processing in the software interrupt portion of the driver.
 */
static _INLINE_ void rs_sched_event(struct sci_struct *sci,
				  int event)
{
	sci->info->event |= 1 << event;
	queue_task_irq_off(&sci->info->tqueue, &tq_serial);
	mark_bh(SERIAL_BH);
}
void rs_interrupt(int irq, void * dev_id, struct pt_regs * regs)
{
	char status;

	struct cnxt_serial * info = &uart_info;
  	struct uart_regs *uart = uart_info.uart;
  	
	status = (uart->iir & 0x0f); /* only concerned w/ lower nibble */
	
	if (status == ISR_Tx_Rdy_Source) {
		transmit_chars(info);
	}
	if ((status == ISR_Rx_Rdy_Source) ||
            (status == ISR_Rx_Rdy_TO_Src )){
		receive_chars(info,status);
	}
	#if 0
		if(!info->use_ints){
			serialpoll.data = (void *)&sp_uart_info;		
			queue_task_irq_off(&serialpoll, &tq_timer);
		}
	#endif


	return;
}
예제 #5
0
파일: serial.c 프로젝트: rohsaini/mkunity
static void
serial_handle_oob_event(struct async_struct *info,
			mach_port_t	device_port)
{
	kern_return_t			kr;
	mach_msg_type_number_t	count;
	struct tty_out_of_band	toob;

	count = TTY_OUT_OF_BAND_COUNT;
	kr = device_get_status(device_port, TTY_OUT_OF_BAND,
				(dev_status_t) &toob, &count);

	if (kr != D_SUCCESS) {
		MACH3_DEBUG(1, kr,
			    ("serial_handle_oob_event(%d):device_get_status",kr ));
		return;
	}

	switch (toob.toob_event) {
	case TOOB_NO_EVENT:
		break;

	case TOOB_BREAK:
		serial_put_status_byte(info, TTY_BREAK);
		break;

	case TOOB_BAD_PARITY:
		serial_put_status_byte(info, TTY_PARITY);
		break;

	case TOOB_FLUSHED:
		break;

	case TOOB_CARRIER:
		if (toob.toob_arg) {
			info->flags |= ASYNC_DCD_PRESENT;
			wake_up_interruptible(&info->open_wait);
		} else {
			info->flags &= ~ASYNC_DCD_PRESENT;

			if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
			(info->flags & ASYNC_CALLOUT_NOHUP))) {
#ifdef SERIAL_DEBUG_OPEN
				printk("scheduling hangup...");
#endif
                        	queue_task_irq_off(&info->tqueue_hangup, &tq_scheduler);
			}
		}
		break;

	default:
		printk("serial_handle_oob_event: unknown event 0x%x\n",
		       toob.toob_event);
		break;
	}

	return;
}
예제 #6
0
static _INLINE_ void receive_chars(struct gbatxt_serial *info, struct pt_regs *regs, unsigned short rx)
{
    volatile unsigned char	*uartp;
    struct tty_struct	*tty = info->tty;
    unsigned char		status, ch;

    if (!tty)
        return;

#if defined(CONFIG_LEDMAN)
    ledman_cmd(LEDMAN_CMD_SET, info->line ? LEDMAN_COM2_RX : LEDMAN_COM1_RX);
#endif

    uartp = (volatile unsigned char *) info->addr;

    while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) {

        if (tty->flip.count >= TTY_FLIPBUF_SIZE)
            break;

        ch = uartp[MCFUART_URB];
        info->stats.rx++;

#ifdef CONFIG_MAGIC_SYSRQ
        if (gbatxt_console_inited && (info->line == gbatxt_console_port)) {
            if (magic_sysrq_key(ch))
                continue;
        }
#endif

        tty->flip.count++;
        if (status & MCFUART_USR_RXERR)
            uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETERR;
        if (status & MCFUART_USR_RXBREAK) {
            info->stats.rxbreak++;
            *tty->flip.flag_buf_ptr++ = TTY_BREAK;
        } else if (status & MCFUART_USR_RXPARITY) {
            info->stats.rxparity++;
            *tty->flip.flag_buf_ptr++ = TTY_PARITY;
        } else if (status & MCFUART_USR_RXOVERRUN) {
            info->stats.rxoverrun++;
            *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
        } else if (status & MCFUART_USR_RXFRAMING) {
            info->stats.rxframing++;
            *tty->flip.flag_buf_ptr++ = TTY_FRAME;
        } else {
            *tty->flip.flag_buf_ptr++ = 0;
        }
        *tty->flip.char_buf_ptr++ = ch;
    }

    queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
    return;
}
예제 #7
0
/*
 *	Change of state on a DCD line.
 */
void gbatxt_modem_change(struct gbatxt_serial *info, int dcd)
{
    if (info->count == 0)
        return;

    if (info->flags & ASYNC_CHECK_CD) {
        if (dcd) {
            wake_up_interruptible(&info->open_wait);
        } else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
                     (info->flags & ASYNC_CALLOUT_NOHUP))) {
            queue_task_irq_off(&info->tqueue_hangup, &tq_scheduler);
        }
    }
}
예제 #8
0
파일: serial.c 프로젝트: rohsaini/mkunity
static void
serial_put_status_byte(struct async_struct *info, 
			unsigned char	byte)
{
	if (info->tty == NULL)
		return;

	if (info->tty->flip.count >= TTY_FLIPBUF_SIZE)
		return;

	*info->tty->flip.flag_buf_ptr++ = byte;
	*info->tty->flip.char_buf_ptr++ = 0;
	info->tty->flip.count++;
	queue_task_irq_off(&info->tty->flip.tqueue, &tq_timer);
}
예제 #9
0
static _INLINE_ void receive_chars(struct sci_struct *sci)
{
	struct tty_struct *tty = sci->info->tty;
	unsigned char ch;

	do {
		ch = sci_inp(sci, SCI_RDR);
		sci_outp(sci,SCI_SSR,sci_in(sci,SCI_SSR) & ~SCI_SSR_RDRF);
		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
			break;
		tty->flip.count++;
		*tty->flip.flag_buf_ptr++ = 0;
		*tty->flip.char_buf_ptr++ = ch;
	} while (sci_inp(sci, SCI_SSR) & SCI_SSR_RDRF);
	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
#ifdef SERIAL_DEBUG_INTR
	printk("DR...");
#endif
}
예제 #10
0
static _INLINE_ void receive_chars(struct LEON_serial *info, struct pt_regs *regs, unsigned short rx)
{
	struct tty_struct *tty = info->tty;
	unsigned char ch;

	/*
	 * This do { } while() loop will get ALL chars out of Rx FIFO 
         */
	do {
		ch = leon->uartdata1;
	
		if(info->is_cons) {
			if(0 /* LEON does not report break */ & rx) { /* whee, break received */
				status_handle(info, rx);
				return;
			} else if (ch == 0x10) { /* ^P */
				show_state();
				show_free_areas();
				show_buffers();
				show_net_buffers();
				return;
			} else if (ch == 0x12) { /* ^R */
				hard_reset_now();
				return;
			}
			/* It is a 'keyboard interrupt' ;-) */
			wake_up(&keypress_wait);
		}

		if(!tty)
			goto clear_and_exit;
		
		/*
		 * Make sure that we do not overflow the buffer
		 */
		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
			queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
			return;
		}

		if(rx & USTAT_PE) {
			*tty->flip.flag_buf_ptr++ = TTY_PARITY;
			status_handle(info, rx);
		} else if(rx & USTAT_OV) {
			*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
			status_handle(info, rx);
		} else if(rx & USTAT_FE) {
			*tty->flip.flag_buf_ptr++ = TTY_FRAME;
			status_handle(info, rx);
		} else {
			*tty->flip.flag_buf_ptr++ = 0; /* XXX */
		}
                *tty->flip.char_buf_ptr++ = ch;
		tty->flip.count++;

	} while((rx = leon->uartstatus1) & USTAT_DR);

	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);

clear_and_exit:
	return;
}
예제 #11
0
/*
 * This routine is used by the interrupt handler to schedule
 * processing in the software interrupt portion of the driver.
 */
static _INLINE_ void gbatxt_sched_event(struct gbatxt_serial *info, int event)
{
    info->event |= 1 << event;
    queue_task_irq_off(&info->tqueue, &mcf_tq_serial);
    mark_bh(CM206_BH);
}
static inline void receive_chars(struct cnxt_serial *info, unsigned long status)
{
	unsigned char ch;

	struct uart_regs *uart = info->uart;
	
#if 0
	// hack to receive chars by polling from anywhere
	struct tty_struct *tty = info->tty;
	if (!(info->flags & S_INITIALIZED))
		return;
#else
	struct tty_struct *tty = info->tty;
	if (!(info->flags & S_INITIALIZED))
		return;
#endif	
	
	ch = (unsigned char)uart->fifo;

	if(info->is_cons)
	{
		
		if (ch == 0x10)
		{ 
			show_state();
			show_free_areas();
			show_buffers();
			//show_net_buffers();
			return;
		}
		else if (ch == 0x12)
		{ 
			HARD_RESET_NOW();
			return;
		}
	}

	/* Look for kgdb 'stop' character, consult the gdb documentation
	 * for remote target debugging and arch/sparc/kernel/sparc-stub.c
	 * to see how all this works.
	 */

	
	if(!tty)
	{
	  printk("no tty\n");
	  goto clear_and_exit;
	}
#if 0
	if (tty->flip.count >= TTY_FLIPBUF_SIZE)
		queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
	tty->flip.count++;
	if(status & US_PARE)
		*tty->flip.flag_buf_ptr++ = TTY_PARITY;
	else if(status & US_OVRE)
		*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
	else if(status & US_FRAME)
		*tty->flip.flag_buf_ptr++ = TTY_FRAME;
	else
		*tty->flip.flag_buf_ptr++ = 0; 
#endif
        tty->flip.count++;
        *tty->flip.flag_buf_ptr++ = 0;
	*tty->flip.char_buf_ptr++ = ch;

	
	queue_task(&tty->flip.tqueue, &tq_timer);
	

clear_and_exit:
	
	return;
}
예제 #13
0
파일: serial.c 프로젝트: rohsaini/mkunity
void *
serial_read_thread(
	void	*arg)
{
	struct server_thread_priv_data	priv_data;
	kern_return_t			kr;
	struct async_struct	*info;
	int				line, wait_loop, count;
	io_buf_ptr_inband_t		inbuf;		/* 128 chars */
	mach_msg_type_number_t		data_count;
	mach_port_t			device_port;

	cthread_set_name(cthread_self(), "serial read");
	server_thread_set_priv_data(cthread_self(), &priv_data);

	line = (int) arg;
	info = rs_table + line;
	uniproc_enter();
	device_port = info->device_port;

	for (;;) {
		data_count = sizeof inbuf;
		uniproc_exit();
		kr = device_read_inband(device_port,
					0,	/* mode */
					0,	/* recnum */
					sizeof inbuf,
					inbuf,
					&data_count);
		uniproc_enter();

		if (kr == D_OUT_OF_BAND) {
			serial_handle_oob_event(info, device_port);
			continue;
		} else if (kr != D_SUCCESS) {
			/* Something happened.. simply shutdown the line.. */
			if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
                           (info->flags & ASYNC_CALLOUT_NOHUP))) 
                       		queue_task_irq_off(&info->tqueue_hangup, &tq_scheduler);
			uniproc_exit();
			cthread_detach(cthread_self());
			cthread_exit((void *) 0);
			/* NEVER REACHED */
		}

		if (data_count <= 0) 
			continue;

		/*
		 * Its very possible with the Power Mac
		 * to overflow the Linux TTY buffers.
		 * (A serial interrupt can present up to
		 * 8K worth of data in one shot)
		 *
		 * The following loops attempts to give the
		 * PPP line disc. a chance to clear the queue
		 * out.
		 */

		for (wait_loop = 0; wait_loop < 6; wait_loop++) {
			/* Check to make sure the tty did not
			 * go away..
			 */

			if (info->tty == NULL)
				break;

			if ((info->tty->flip.count+data_count) < TTY_FLIPBUF_SIZE)
				break;

			/* Try to give another thread some time.. */
			osfmach3_yield();
		}

		if (info->tty == NULL)
			continue;

		count = MIN(TTY_FLIPBUF_SIZE + info->tty->flip.count, data_count);
		if (count <= 0)
			continue;

		info->last_active = jiffies; 
		info->tty->flip.count += count;
		memcpy(info->tty->flip.char_buf_ptr, inbuf, count);
		memset(info->tty->flip.flag_buf_ptr, 0, count);
		info->tty->flip.flag_buf_ptr += count;
		info->tty->flip.char_buf_ptr += count;
		queue_task_irq_off(&info->tty->flip.tqueue, &tq_timer);
	}
}