viocons.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,334 行 · 第 1/3 页
C
1,334 行
size_t curlen; const char *curbuf; unsigned long flags; int copy_needed = (viochar == NULL); /* * Write to the hvlog of inbound data are now done prior to * calling internal_write() since internal_write() is only called in * the event that an lp event path is active, which isn't the case for * logging attempts prior to console initialization. * * If there is already data queued for this port, send it prior to * attempting to send any new data. */ if (pi->used) send_buffers(pi); spin_lock_irqsave(&consolelock, flags); /* * If the internal_write() was passed a pointer to a * viocharlpevent then we don't need to allocate a new one * (this is the case where we are internal_writing user space * data). If we aren't writing user space data then we need * to get an event from viopath. */ if (copy_needed) { /* This one is fetched from the viopath data structure */ viochar = (struct viocharlpevent *) vio_get_event_buffer(viomajorsubtype_chario); /* Make sure we got a buffer */ if (viochar == NULL) { spin_unlock_irqrestore(&consolelock, flags); hvlog("\n\rviocons: Can't get viochar buffer in internal_write()."); return -EAGAIN; } initDataEvent(viochar, pi->lp); } curbuf = buf; bleft = len; while ((bleft > 0) && (pi->used == 0) && ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) { if (bleft > VIOCHAR_MAX_DATA) curlen = VIOCHAR_MAX_DATA; else curlen = bleft; viochar->event.xCorrelationToken = pi->seq++; if (copy_needed) { memcpy(viochar->data, curbuf, curlen); viochar->len = curlen; } viochar->event.xSizeMinus1 = offsetof(struct viocharlpevent, data) + curlen; hvrc = HvCallEvent_signalLpEvent(&viochar->event); if (hvrc) { spin_unlock_irqrestore(&consolelock, flags); if (copy_needed) vio_free_event_buffer(viomajorsubtype_chario, viochar); hvlog("viocons: error sending event! %d\n", (int)hvrc); return len - bleft; } curbuf += curlen; bleft -= curlen; } /* If we didn't send it all, buffer as much of it as we can. */ if (bleft > 0) bleft -= buffer_add(pi, curbuf, bleft); /* * Since we grabbed it from the viopath data structure, return * it to the data structure. */ if (copy_needed) vio_free_event_buffer(viomajorsubtype_chario, viochar); spin_unlock_irqrestore(&consolelock, flags); return len - bleft;}static struct port_info *get_port_data(struct tty_struct *tty){ unsigned long flags; struct port_info *pi; spin_lock_irqsave(&consolelock, flags); if (tty) { pi = (struct port_info *)tty->driver_data; if (!pi || viotty_paranoia_check(pi, tty->name, "get_port_data")) { pi = NULL; } } else /* * If this is the console device, use the lp from * the first port entry */ pi = &port_info[0]; spin_unlock_irqrestore(&consolelock, flags); return pi;}/* * Initialize the common fields in a charLpEvent */static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp){ memset(viochar, 0, sizeof(struct viocharlpevent)); viochar->event.xFlags.xValid = 1; viochar->event.xFlags.xFunction = HvLpEvent_Function_Int; viochar->event.xFlags.xAckInd = HvLpEvent_AckInd_NoAck; viochar->event.xFlags.xAckType = HvLpEvent_AckType_DeferredAck; viochar->event.xType = HvLpEvent_Type_VirtualIo; viochar->event.xSubtype = viomajorsubtype_chario | viochardata; viochar->event.xSourceLp = HvLpConfig_getLpIndex(); viochar->event.xTargetLp = lp; viochar->event.xSizeMinus1 = sizeof(struct viocharlpevent); viochar->event.xSourceInstanceId = viopath_sourceinst(lp); viochar->event.xTargetInstanceId = viopath_targetinst(lp);}/* * early console device write */static void viocons_write_early(struct console *co, const char *s, unsigned count){ hvlogOutput(s, count);}/* * console device write */static void viocons_write(struct console *co, const char *s, unsigned count){ int index; int begin; struct port_info *pi; static const char cr = '\r'; /* * Check port data first because the target LP might be valid but * simply not active, in which case we want to hvlog the output. */ pi = get_port_data(NULL); if (pi == NULL) { hvlog("\n\rviocons_write: unable to get port data."); return; } hvlogOutput(s, count); if (!viopath_isactive(pi->lp)) { /* * This is a VERY noisy trace message in the case where the * path manager is not active or in the case where this * function is called prior to viocons initialization. It is * being commented out for the sake of a clear trace buffer. */#if 0 hvlog("\n\rviocons_write: path not active to lp %d", pi->lp);#endif return; } /* * Any newline character found will cause a * carriage return character to be emitted as well. */ begin = 0; for (index = 0; index < count; index++) { if (s[index] == '\n') { /* * Newline found. Print everything up to and * including the newline */ internal_write(pi, &s[begin], index - begin + 1, NULL); begin = index + 1; /* Emit a carriage return as well */ internal_write(pi, &cr, 1, NULL); } } /* If any characters left to write, write them now */ if ((index - begin) > 0) internal_write(pi, &s[begin], index - begin, NULL);}/* * Work out the device associate with this console */static struct tty_driver *viocons_device(struct console *c, int *index){ *index = c->index; return viotty_driver;}/* * console device I/O methods */static struct console viocons_early = { .name = "viocons", .write = viocons_write_early, .flags = CON_PRINTBUFFER, .index = -1,};static struct console viocons = { .name = "viocons", .write = viocons_write, .device = viocons_device, .flags = CON_PRINTBUFFER, .index = -1,};/* * TTY Open method */static int viotty_open(struct tty_struct *tty, struct file *filp){ int port; unsigned long flags; struct port_info *pi; port = tty->index; if ((port < 0) || (port >= VTTY_PORTS)) return -ENODEV; spin_lock_irqsave(&consolelock, flags); pi = &port_info[port]; /* If some other TTY is already connected here, reject the open */ if ((pi->tty) && (pi->tty != tty)) { spin_unlock_irqrestore(&consolelock, flags); printk(VIOCONS_KERN_WARN "attempt to open device twice from different ttys\n"); return -EBUSY; } tty->driver_data = pi; pi->tty = tty; spin_unlock_irqrestore(&consolelock, flags); return 0;}/* * TTY Close method */static void viotty_close(struct tty_struct *tty, struct file *filp){ unsigned long flags; struct port_info *pi; spin_lock_irqsave(&consolelock, flags); pi = (struct port_info *)tty->driver_data; if (!pi || viotty_paranoia_check(pi, tty->name, "viotty_close")) { spin_unlock_irqrestore(&consolelock, flags); return; } if (tty->count == 1) pi->tty = NULL; spin_unlock_irqrestore(&consolelock, flags);}/* * TTY Write method */static int viotty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count){ int ret; int total = 0; struct port_info *pi; pi = get_port_data(tty); if (pi == NULL) { hvlog("\n\rviotty_write: no port data."); return -ENODEV; } if (viochar_is_console(pi)) hvlogOutput(buf, count); /* * If the path to this LP is closed, don't bother doing anything more. * just dump the data on the floor and return count. For some reason * some user level programs will attempt to probe available tty's and * they'll attempt a viotty_write on an invalid port which maps to an * invalid target lp. If this is the case then ignore the * viotty_write call and, since the viopath isn't active to this * partition, return count. */ if (!viopath_isactive(pi->lp)) { /* Noisy trace. Commented unless needed. */#if 0 hvlog("\n\rviotty_write: viopath NOT active for lp %d.",pi->lp);#endif return count; } /* * If the viotty_write is invoked from user space we want to do the * copy_from_user() into an event buffer from the cfu buffer before * internal_write() is called because internal_write may need to buffer * data which will need to grab a spin_lock and we shouldn't * copy_from_user() while holding a spin_lock. Should internal_write() * not need to buffer data then it'll just use the event we created here * rather than checking one out from vio_get_event_buffer(). */ if (from_user) { struct viocharlpevent *viochar; int curlen; const char *curbuf = buf; viochar = viocons_get_cfu_buffer(); if (viochar == NULL) return -EAGAIN; initDataEvent(viochar, pi->lp); while (count > 0) { if (count > VIOCHAR_MAX_DATA) curlen = VIOCHAR_MAX_DATA; else curlen = count; viochar->len = curlen; ret = copy_from_user(viochar->data, curbuf, curlen); if (ret) break; ret = internal_write(pi, viochar->data, viochar->len, viochar); total += ret; if (ret != curlen) break; count -= curlen; curbuf += curlen; } viocons_free_cfu_buffer(viochar); } else total = internal_write(pi, buf, count, NULL); return total;}/* * TTY put_char method */static void viotty_put_char(struct tty_struct *tty, unsigned char ch){ struct port_info *pi; pi = get_port_data(tty); if (pi == NULL) return; /* This will append '\r' as well if the char is '\n' */ if (viochar_is_console(pi)) hvlogOutput(&ch, 1); if (viopath_isactive(pi->lp)) internal_write(pi, &ch, 1, NULL);}/* * TTY write_room method */static int viotty_write_room(struct tty_struct *tty){ int i; int room = 0; struct port_info *pi; unsigned long flags; spin_lock_irqsave(&consolelock, flags); pi = (struct port_info *)tty->driver_data; if (!pi || viotty_paranoia_check(pi, tty->name, "viotty_write_room")) { spin_unlock_irqrestore(&consolelock, flags); return 0; } /* If no buffers are used, return the max size. */ if (pi->used == 0) { spin_unlock_irqrestore(&consolelock, flags); return VIOCHAR_MAX_DATA * VIOCHAR_NUM_BUF; } /* * We retain the spinlock because we want to get an accurate * count and it can change on us between each operation if we * don't hold the spinlock. */ for (i = 0; ((i < VIOCHAR_NUM_BUF) && (room < VIOCHAR_MAX_DATA)); i++) room += (VIOCHAR_MAX_DATA - pi->bufferBytes[i]); spin_unlock_irqrestore(&consolelock, flags); if (room > VIOCHAR_MAX_DATA) room = VIOCHAR_MAX_DATA; return room;}/* * TTY chars_in_buffer method */static int viotty_chars_in_buffer(struct tty_struct *tty){ return 0;}static int viotty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){ switch (cmd) { /* * the ioctls below read/set the flags usually shown in the leds * don't use them - they will go away without warning */ case KDGETLED: case KDGKBLED: return put_user(0, (char *)arg); case KDSKBLED: return 0; } return n_tty_ioctl(tty, file, cmd, arg);}/* * Handle an open charLpEvent. Could be either interrupt or ack */static void vioHandleOpenEvent(struct HvLpEvent *event){ unsigned long flags; struct viocharlpevent *cevent = (struct viocharlpevent *)event; u8 port = cevent->virtual_device; struct port_info *pi; int reject = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?