hvsi.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,320 行 · 第 1/3 页
C
1,320 行
return NULL; if (overflow > 0) { pr_debug("%s: got >TTY_THRESHOLD_THROTTLE bytes\n", __FUNCTION__); datalen = TTY_THRESHOLD_THROTTLE; } hvsi_insert_chars(hp, data, datalen); if (overflow > 0) { /* * we still have more data to deliver, so we need to save off the * overflow and send it later */ pr_debug("%s: deferring overflow\n", __FUNCTION__); memcpy(hp->throttle_buf, data + TTY_THRESHOLD_THROTTLE, overflow); hp->n_throttle = overflow; } return hp->tty;}/* * Returns true/false indicating data successfully read from hypervisor. * Used both to get packets for tty connections and to advance the state * machine during console handshaking (in which case tty = NULL and we ignore * incoming data). */static int hvsi_load_chunk(struct hvsi_struct *hp, struct tty_struct **flip, struct tty_struct **hangup){ uint8_t *packet = hp->inbuf; int chunklen; *flip = NULL; *hangup = NULL; chunklen = hvsi_read(hp, hp->inbuf_end, HVSI_MAX_READ); if (chunklen == 0) return 0; pr_debug("%s: got %i bytes\n", __FUNCTION__, chunklen); dbg_dump_hex(hp->inbuf_end, chunklen); hp->inbuf_end += chunklen; /* handle all completed packets */ while ((packet < hp->inbuf_end) && got_packet(hp, packet)) { struct hvsi_header *header = (struct hvsi_header *)packet; if (!is_header(packet)) { printk(KERN_ERR "hvsi%i: got malformed packet\n", hp->index); /* skip bytes until we find a header or run out of data */ while ((packet < hp->inbuf_end) && (!is_header(packet))) packet++; continue; } pr_debug("%s: handling %i-byte packet\n", __FUNCTION__, len_packet(packet)); dbg_dump_packet(packet); switch (header->type) { case VS_DATA_PACKET_HEADER: if (!is_open(hp)) break; if (hp->tty == NULL) break; /* no tty buffer to put data in */ *flip = hvsi_recv_data(hp, packet); break; case VS_CONTROL_PACKET_HEADER: *hangup = hvsi_recv_control(hp, packet); break; case VS_QUERY_RESPONSE_PACKET_HEADER: hvsi_recv_response(hp, packet); break; case VS_QUERY_PACKET_HEADER: hvsi_recv_query(hp, packet); break; default: printk(KERN_ERR "hvsi%i: unknown HVSI packet type 0x%x\n", hp->index, header->type); dump_packet(packet); break; } packet += len_packet(packet); if (*hangup) { pr_debug("%s: hangup\n", __FUNCTION__); /* * we need to send the hangup now before receiving any more data. * If we get "data, hangup, data", we can't deliver the second * data before the hangup. */ break; } } compact_inbuf(hp, packet); return 1;}static void hvsi_send_overflow(struct hvsi_struct *hp){ pr_debug("%s: delivering %i bytes overflow\n", __FUNCTION__, hp->n_throttle); hvsi_insert_chars(hp, hp->throttle_buf, hp->n_throttle); hp->n_throttle = 0;}/* * must get all pending data because we only get an irq on empty->non-empty * transition */static irqreturn_t hvsi_interrupt(int irq, void *arg, struct pt_regs *regs){ struct hvsi_struct *hp = (struct hvsi_struct *)arg; struct tty_struct *flip; struct tty_struct *hangup; unsigned long flags; irqreturn_t handled = IRQ_NONE; int again = 1; pr_debug("%s\n", __FUNCTION__); while (again) { spin_lock_irqsave(&hp->lock, flags); again = hvsi_load_chunk(hp, &flip, &hangup); handled = IRQ_HANDLED; spin_unlock_irqrestore(&hp->lock, flags); /* * we have to call tty_flip_buffer_push() and tty_hangup() outside our * spinlock. But we also have to keep going until we've read all the * available data. */ if (flip) { /* there was data put in the tty flip buffer */ tty_flip_buffer_push(flip); flip = NULL; } if (hangup) { tty_hangup(hangup); } } spin_lock_irqsave(&hp->lock, flags); if (hp->tty && hp->n_throttle && (!test_bit(TTY_THROTTLED, &hp->tty->flags))) { /* we weren't hung up and we weren't throttled, so we can deliver the * rest now */ flip = hp->tty; hvsi_send_overflow(hp); } spin_unlock_irqrestore(&hp->lock, flags); if (flip) { tty_flip_buffer_push(flip); } return handled;}/* for boot console, before the irq handler is running */static int __init poll_for_state(struct hvsi_struct *hp, int state){ unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; for (;;) { hvsi_interrupt(hp->virq, (void *)hp, NULL); /* get pending data */ if (hp->state == state) return 0; mdelay(5); if (time_after(jiffies, end_jiffies)) return -EIO; }}/* wait for irq handler to change our state */static int wait_for_state(struct hvsi_struct *hp, int state){ unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; unsigned long timeout; int ret = 0; DECLARE_WAITQUEUE(myself, current); set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&hp->stateq, &myself); for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (hp->state == state) break; timeout = end_jiffies - jiffies; if (time_after(jiffies, end_jiffies)) { ret = -EIO; break; } schedule_timeout(timeout); } remove_wait_queue(&hp->stateq, &myself); set_current_state(TASK_RUNNING); return ret;}static int hvsi_query(struct hvsi_struct *hp, uint16_t verb){ struct hvsi_query packet __ALIGNED__; int wrote; packet.type = VS_QUERY_PACKET_HEADER; packet.len = sizeof(struct hvsi_query); packet.seqno = atomic_inc_return(&hp->seqno); packet.verb = verb; pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); dbg_dump_hex((uint8_t*)&packet, packet.len); wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); if (wrote != packet.len) { printk(KERN_ERR "hvsi%i: couldn't send query (%i)!\n", hp->index, wrote); return -EIO; } return 0;}static int hvsi_get_mctrl(struct hvsi_struct *hp){ int ret; set_state(hp, HVSI_WAIT_FOR_MCTRL_RESPONSE); hvsi_query(hp, VSV_SEND_MODEM_CTL_STATUS); ret = hvsi_wait(hp, HVSI_OPEN); if (ret < 0) { printk(KERN_ERR "hvsi%i: didn't get modem flags\n", hp->index); set_state(hp, HVSI_OPEN); return ret; } pr_debug("%s: mctrl 0x%x\n", __FUNCTION__, hp->mctrl); return 0;}/* note that we can only set DTR */static int hvsi_set_mctrl(struct hvsi_struct *hp, uint16_t mctrl){ struct hvsi_control packet __ALIGNED__; int wrote; packet.type = VS_CONTROL_PACKET_HEADER, packet.seqno = atomic_inc_return(&hp->seqno); packet.len = sizeof(struct hvsi_control); packet.verb = VSV_SET_MODEM_CTL; packet.mask = HVSI_TSDTR; if (mctrl & TIOCM_DTR) packet.word = HVSI_TSDTR; pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); dbg_dump_hex((uint8_t*)&packet, packet.len); wrote = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); if (wrote != packet.len) { printk(KERN_ERR "hvsi%i: couldn't set DTR!\n", hp->index); return -EIO; } return 0;}static void hvsi_drain_input(struct hvsi_struct *hp){ uint8_t buf[HVSI_MAX_READ] __ALIGNED__; unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; while (time_before(end_jiffies, jiffies)) if (0 == hvsi_read(hp, buf, HVSI_MAX_READ)) break;}static int hvsi_handshake(struct hvsi_struct *hp){ int ret; /* * We could have a CLOSE or other data waiting for us before we even try * to open; try to throw it all away so we don't get confused. (CLOSE * is the first message sent up the pipe when the FSP comes online. We * need to distinguish between "it came up a while ago and we're the first * user" and "it was just reset before it saw our handshake packet".) */ hvsi_drain_input(hp); set_state(hp, HVSI_WAIT_FOR_VER_RESPONSE); ret = hvsi_query(hp, VSV_SEND_VERSION_NUMBER); if (ret < 0) { printk(KERN_ERR "hvsi%i: couldn't send version query\n", hp->index); return ret; } ret = hvsi_wait(hp, HVSI_OPEN); if (ret < 0) return ret; return 0;}static int hvsi_put_chars(struct hvsi_struct *hp, const char *buf, int count){ struct hvsi_data packet __ALIGNED__; int ret; BUG_ON(count > HVSI_MAX_OUTGOING_DATA); packet.type = VS_DATA_PACKET_HEADER; packet.seqno = atomic_inc_return(&hp->seqno); packet.len = count + sizeof(struct hvsi_header); memcpy(&packet.data, buf, count); ret = hvc_put_chars(hp->vtermno, (char *)&packet, packet.len); if (ret == packet.len) { /* return the number of chars written, not the packet length */ return count; } return ret; /* return any errors */}static void hvsi_close_protocol(struct hvsi_struct *hp){ struct hvsi_control packet __ALIGNED__; packet.type = VS_CONTROL_PACKET_HEADER; packet.seqno = atomic_inc_return(&hp->seqno); packet.len = 6; packet.verb = VSV_CLOSE_PROTOCOL; pr_debug("%s: sending %i bytes\n", __FUNCTION__, packet.len); dbg_dump_hex((uint8_t*)&packet, packet.len); hvc_put_chars(hp->vtermno, (char *)&packet, packet.len);}static int hvsi_open(struct tty_struct *tty, struct file *filp){ struct hvsi_struct *hp; unsigned long flags; int line = tty->index; int ret; pr_debug("%s\n", __FUNCTION__); if (line < 0 || line >= hvsi_count) return -ENODEV; hp = &hvsi_ports[line]; tty->driver_data = hp; tty->low_latency = 1; /* avoid throttle/tty_flip_buffer_push race */ spin_lock_irqsave(&hp->lock, flags); hp->tty = tty; hp->count++; atomic_set(&hp->seqno, 0); h_vio_signal(hp->vtermno, VIO_IRQ_ENABLE); spin_unlock_irqrestore(&hp->lock, flags); if (hp->flags & HVSI_CONSOLE) return 0; /* this has already been handshaked as the console */ ret = hvsi_handshake(hp); if (ret < 0) { printk(KERN_ERR "%s: HVSI handshaking failed\n", tty->name); return ret; } ret = hvsi_get_mctrl(hp); if (ret < 0) { printk(KERN_ERR "%s: couldn't get initial modem flags\n", tty->name); return ret; } ret = hvsi_set_mctrl(hp, hp->mctrl | TIOCM_DTR); if (ret < 0) { printk(KERN_ERR "%s: couldn't set DTR\n", tty->name); return ret; } return 0;}/* wait for hvsi_write_worker to empty hp->outbuf */static void hvsi_flush_output(struct hvsi_struct *hp){ unsigned long end_jiffies = jiffies + HVSI_TIMEOUT; unsigned long timeout; DECLARE_WAITQUEUE(myself, current); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&hp->emptyq, &myself); for (;;) { set_current_state(TASK_UNINTERRUPTIBLE); if (hp->n_outbuf <= 0) break; timeout = end_jiffies - jiffies; if (time_after(jiffies, end_jiffies)) break; schedule_timeout(timeout); } remove_wait_queue(&hp->emptyq, &myself); set_current_state(TASK_RUNNING); /* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */ cancel_delayed_work(&hp->writer); flush_scheduled_work(); /* * it's also possible that our timeout expired and hvsi_write_worker * didn't manage to push outbuf. poof. */ hp->n_outbuf = 0;}static void hvsi_close(struct tty_struct *tty, struct file *filp){ struct hvsi_struct *hp = tty->driver_data; unsigned long flags; pr_debug("%s\n", __FUNCTION__);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?