예제 #1
0
/*
 * Interrupt routine, called from Ingo's I/O layer
 */
static void raw3215_irq(int irq, void *int_parm, struct pt_regs *regs)
{
	raw3215_info *raw;
	raw3215_req *req;
	struct tty_struct *tty;
	devstat_t *stat;
        int cstat, dstat;
	int count, slen;

	stat = (devstat_t *) int_parm;
	req = (raw3215_req *) stat->intparm;
	cstat = stat->cstat;
	dstat = stat->dstat;
	if (cstat != 0) {
		raw = raw3215_find_info(irq);
		if (raw != NULL) {
			raw->message = KERN_WARNING
				"Got nonzero channel status in raw3215_irq "
				"(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
			raw->msg_dstat = dstat;
			raw->msg_cstat = cstat;
                        raw3215_sched_bh(raw);
		}
	}
        if (dstat & 0x01) { /* we got a unit exception */
		dstat &= ~0x01;  /* we can ignore it */
        }
	switch (dstat) {
	case 0x80:
		if (cstat != 0)
			break;
		/* Attention interrupt, someone hit the enter key */
		if ((raw = raw3215_find_info(irq)) == NULL)
			return;              /* That shouldn't happen ... */
		/* Setup a read request */
		raw3215_mk_read_req(raw);
                if (MACHINE_IS_P390)
                        memset(raw->inbuf, 0, RAW3215_INBUF_SIZE);
                raw3215_sched_bh(raw);
		break;
	case 0x08:
	case 0x0C:
		/* Channel end interrupt. */
		if ((raw = req->info) == NULL)
                        return;              /* That shouldn't happen ... */
		if (req->type == RAW3215_READ) {
			/* store residual count, then wait for device end */
			req->residual = stat->rescnt;
		}
		if (dstat == 0x08)
			break;
	case 0x04:
		/* Device end interrupt. */
                if ((raw = req->info) == NULL)
                        return;              /* That shouldn't happen ... */
		if (req->type == RAW3215_READ && raw->tty != NULL) {
			unsigned int cchar;

			tty = raw->tty;
			count = 160 - req->residual;
			if (MACHINE_IS_P390) {
				slen = strnlen(raw->inbuf, RAW3215_INBUF_SIZE);
				if (count > slen)
					count = slen;
			} else
			if (count >= TTY_FLIPBUF_SIZE - tty->flip.count)
				count = TTY_FLIPBUF_SIZE - tty->flip.count - 1;
			EBCASC(raw->inbuf, count);
			cchar = ctrlchar_handle(raw->inbuf, count, tty);
			switch (cchar & CTRLCHAR_MASK) {
			case CTRLCHAR_SYSRQ:
				break;

			case CTRLCHAR_CTRL:
				tty->flip.count++;
				*tty->flip.flag_buf_ptr++ = TTY_NORMAL;
				*tty->flip.char_buf_ptr++ = cchar;
				tty_flip_buffer_push(raw->tty);
				break;

			case CTRLCHAR_NONE:
				memcpy(tty->flip.char_buf_ptr,
				       raw->inbuf, count);
				if (count < 2 ||
				    (strncmp(raw->inbuf+count-2, "^n", 2) && 
				    strncmp(raw->inbuf+count-2, "\252n", 2)) ) {
					/* don't add the auto \n */
					tty->flip.char_buf_ptr[count] = '\n';
					memset(tty->flip.flag_buf_ptr,
					       TTY_NORMAL, count + 1);
					count++;
				} else
					count-=2;
				tty->flip.char_buf_ptr += count;
				tty->flip.flag_buf_ptr += count;
				tty->flip.count += count;
				tty_flip_buffer_push(raw->tty);
				break;
			}
		} else if (req->type == RAW3215_WRITE) {
			raw->count -= req->len;
                        raw->written -= req->len;
		} 
		raw->flags &= ~RAW3215_WORKING;
		raw3215_free_req(req);
		/* check for empty wait */
		if (waitqueue_active(&raw->empty_wait) &&
		    raw->queued_write == NULL &&
		    raw->queued_read == NULL) {
			wake_up_interruptible(&raw->empty_wait);
		}
                raw3215_sched_bh(raw);
		break;
	default:
		/* Strange interrupt, I'll do my best to clean up */
                if ((raw = raw3215_find_info(irq)) == NULL)
                        return;              /* That shouldn't happen ... */
                if (raw == NULL) break;
		if (req != NULL && req->type != RAW3215_FREE) {
		        if (req->type == RAW3215_WRITE) {
			        raw->count -= req->len;
                                raw->written -= req->len;
                        }
                        raw->flags &= ~RAW3215_WORKING;
                        raw3215_free_req(req);
		}
		raw->message = KERN_WARNING
			"Spurious interrupt in in raw3215_irq "
			"(dev %i, dev sts 0x%2x, sch sts 0x%2x)";
		raw->msg_dstat = dstat;
		raw->msg_cstat = cstat;
                raw3215_sched_bh(raw);
	}
	return;
}
예제 #2
0
/*
 * Interrupt routine, called from common io layer
 */
static void raw3215_irq(struct ccw_device *cdev, unsigned long intparm,
			struct irb *irb)
{
	struct raw3215_info *raw;
	struct raw3215_req *req;
	struct tty_struct *tty;
	int cstat, dstat;
	int count;

	raw = dev_get_drvdata(&cdev->dev);
	req = (struct raw3215_req *) intparm;
	tty = tty_port_tty_get(&raw->port);
	cstat = irb->scsw.cmd.cstat;
	dstat = irb->scsw.cmd.dstat;
	if (cstat != 0)
		raw3215_next_io(raw, tty);
	if (dstat & 0x01) { /* we got a unit exception */
		dstat &= ~0x01;	 /* we can ignore it */
	}
	switch (dstat) {
	case 0x80:
		if (cstat != 0)
			break;
		/* Attention interrupt, someone hit the enter key */
		raw3215_mk_read_req(raw);
		raw3215_next_io(raw, tty);
		break;
	case 0x08:
	case 0x0C:
		/* Channel end interrupt. */
		if ((raw = req->info) == NULL)
			goto put_tty;	     /* That shouldn't happen ... */
		if (req->type == RAW3215_READ) {
			/* store residual count, then wait for device end */
			req->residual = irb->scsw.cmd.count;
		}
		if (dstat == 0x08)
			break;
	case 0x04:
		/* Device end interrupt. */
		if ((raw = req->info) == NULL)
			goto put_tty;	     /* That shouldn't happen ... */
		if (req->type == RAW3215_READ && tty != NULL) {
			unsigned int cchar;

			count = 160 - req->residual;
			EBCASC(raw->inbuf, count);
			cchar = ctrlchar_handle(raw->inbuf, count, tty);
			switch (cchar & CTRLCHAR_MASK) {
			case CTRLCHAR_SYSRQ:
				break;

			case CTRLCHAR_CTRL:
				tty_insert_flip_char(&raw->port, cchar,
						TTY_NORMAL);
				tty_flip_buffer_push(&raw->port);
				break;

			case CTRLCHAR_NONE:
				if (count < 2 ||
				    (strncmp(raw->inbuf+count-2, "\252n", 2) &&
				     strncmp(raw->inbuf+count-2, "^n", 2)) ) {
					/* add the auto \n */
					raw->inbuf[count] = '\n';
					count++;
				} else
					count -= 2;
				tty_insert_flip_string(&raw->port, raw->inbuf,
						count);
				tty_flip_buffer_push(&raw->port);
				break;
			}
		} else if (req->type == RAW3215_WRITE) {
			raw->count -= req->len;
			raw->written -= req->len;
		}
		raw->flags &= ~RAW3215_WORKING;
		raw3215_free_req(req);
		/* check for empty wait */
		if (waitqueue_active(&raw->empty_wait) &&
		    raw->queued_write == NULL &&
		    raw->queued_read == NULL) {
			wake_up_interruptible(&raw->empty_wait);
		}
		raw3215_next_io(raw, tty);
		break;
	default:
		/* Strange interrupt, I'll do my best to clean up */
		if (req != NULL && req->type != RAW3215_FREE) {
			if (req->type == RAW3215_WRITE) {
				raw->count -= req->len;
				raw->written -= req->len;
			}
			raw->flags &= ~RAW3215_WORKING;
			raw3215_free_req(req);
		}
		raw3215_next_io(raw, tty);
	}
put_tty:
	tty_kref_put(tty);
}
예제 #3
0
/*
 * Interrupt routine, called from common io layer
 */
static void
raw3215_irq(struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
{
	struct raw3215_info *raw;
	struct raw3215_req *req;
	struct tty_struct *tty;
	int cstat, dstat;
	int count, slen;

	raw = cdev->dev.driver_data;
	req = (struct raw3215_req *) intparm;
	cstat = irb->scsw.cstat;
	dstat = irb->scsw.dstat;
	if (cstat != 0) {
		raw->message = KERN_WARNING
			"Got nonzero channel status in raw3215_irq "
			"(dev sts 0x%2x, sch sts 0x%2x)";
		raw->msg_dstat = dstat;
		raw->msg_cstat = cstat;
		tasklet_schedule(&raw->tasklet);
	}
	if (dstat & 0x01) { /* we got a unit exception */
		dstat &= ~0x01;	 /* we can ignore it */
	}
	switch (dstat) {
	case 0x80:
		if (cstat != 0)
			break;
		/* Attention interrupt, someone hit the enter key */
		raw3215_mk_read_req(raw);
		if (MACHINE_IS_P390)
			memset(raw->inbuf, 0, RAW3215_INBUF_SIZE);
		tasklet_schedule(&raw->tasklet);
		break;
	case 0x08:
	case 0x0C:
		/* Channel end interrupt. */
		if ((raw = req->info) == NULL)
			return;		     /* That shouldn't happen ... */
		if (req->type == RAW3215_READ) {
			/* store residual count, then wait for device end */
			req->residual = irb->scsw.count;
		}
		if (dstat == 0x08)
			break;
	case 0x04:
		/* Device end interrupt. */
		if ((raw = req->info) == NULL)
			return;		     /* That shouldn't happen ... */
		if (req->type == RAW3215_READ && raw->tty != NULL) {
			unsigned int cchar;

			tty = raw->tty;
			count = 160 - req->residual;
			if (MACHINE_IS_P390) {
				slen = strnlen(raw->inbuf, RAW3215_INBUF_SIZE);
				if (count > slen)
					count = slen;
			} else
			EBCASC(raw->inbuf, count);
			cchar = ctrlchar_handle(raw->inbuf, count, tty);
			switch (cchar & CTRLCHAR_MASK) {
			case CTRLCHAR_SYSRQ:
				break;

			case CTRLCHAR_CTRL:
				tty_insert_flip_char(tty, cchar, TTY_NORMAL);
				tty_flip_buffer_push(raw->tty);
				break;

			case CTRLCHAR_NONE:
				if (count < 2 ||
				    (strncmp(raw->inbuf+count-2, "\252n", 2) &&
				     strncmp(raw->inbuf+count-2, "^n", 2)) ) {
					/* add the auto \n */
					raw->inbuf[count] = '\n';
					count++;
				} else
					count -= 2;
				tty_insert_flip_string(tty, raw->inbuf, count);
				tty_flip_buffer_push(raw->tty);
				break;
			}
		} else if (req->type == RAW3215_WRITE) {
			raw->count -= req->len;
			raw->written -= req->len;
		}
		raw->flags &= ~RAW3215_WORKING;
		raw3215_free_req(req);
		/* check for empty wait */
		if (waitqueue_active(&raw->empty_wait) &&
		    raw->queued_write == NULL &&
		    raw->queued_read == NULL) {
			wake_up_interruptible(&raw->empty_wait);
		}
		tasklet_schedule(&raw->tasklet);
		break;
	default:
		/* Strange interrupt, I'll do my best to clean up */
		if (req != NULL && req->type != RAW3215_FREE) {
			if (req->type == RAW3215_WRITE) {
				raw->count -= req->len;
				raw->written -= req->len;
			}
			raw->flags &= ~RAW3215_WORKING;
			raw3215_free_req(req);
		}
		raw->message = KERN_WARNING
			"Spurious interrupt in in raw3215_irq "
			"(dev sts 0x%2x, sch sts 0x%2x)";
		raw->msg_dstat = dstat;
		raw->msg_cstat = cstat;
		tasklet_schedule(&raw->tasklet);
	}
	return;
}