/* * 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; }
/* * 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); }
/* * 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; }