예제 #1
0
static ssize_t
vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
	struct inode *inode = file->f_path.dentry->d_inode;
	unsigned int currcons = iminor(inode);
	struct vc_data *vc;
	long pos;
	long viewed, attr, read;
	int col, maxcol;
	unsigned short *org = NULL;
	ssize_t ret;

	mutex_lock(&con_buf_mtx);

	pos = *ppos;

	
	acquire_console_sem();

	attr = (currcons & 128);
	currcons = (currcons & 127);
	if (currcons == 0) {
		currcons = fg_console;
		viewed = 1;
	} else {
		currcons--;
		viewed = 0;
	}
	ret = -ENXIO;
	if (!vc_cons_allocated(currcons))
		goto unlock_out;
	vc = vc_cons[currcons].d;

	ret = -EINVAL;
	if (pos < 0)
		goto unlock_out;
	read = 0;
	ret = 0;
	while (count) {
		char *con_buf0, *con_buf_start;
		long this_round, size;
		ssize_t orig_count;
		long p = pos;

		
		size = vcs_size(inode);
		if (pos >= size)
			break;
		if (count > size - pos)
			count = size - pos;

		this_round = count;
		if (this_round > CON_BUF_SIZE)
			this_round = CON_BUF_SIZE;

		

		con_buf_start = con_buf0 = con_buf;
		orig_count = this_round;
		maxcol = vc->vc_cols;
		if (!attr) {
			org = screen_pos(vc, p, viewed);
			col = p % maxcol;
			p += maxcol - col;
			while (this_round-- > 0) {
				*con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff);
				if (++col == maxcol) {
					org = screen_pos(vc, p, viewed);
					col = 0;
					p += maxcol;
				}
			}
		} else {
			if (p < HEADER_SIZE) {
				size_t tmp_count;

				con_buf0[0] = (char)vc->vc_rows;
				con_buf0[1] = (char)vc->vc_cols;
				getconsxy(vc, con_buf0 + 2);

				con_buf_start += p;
				this_round += p;
				if (this_round > CON_BUF_SIZE) {
					this_round = CON_BUF_SIZE;
					orig_count = this_round - p;
				}

				tmp_count = HEADER_SIZE;
				if (tmp_count > this_round)
					tmp_count = this_round;

				
				this_round -= tmp_count;
				p = HEADER_SIZE;
				con_buf0 = con_buf + HEADER_SIZE;
				
			} else if (p & 1) {
				
				con_buf_start++;
				if (this_round < CON_BUF_SIZE)
					this_round++;
				else
					orig_count--;
			}
			if (this_round > 0) {
				unsigned short *tmp_buf = (unsigned short *)con_buf0;

				p -= HEADER_SIZE;
				p /= 2;
				col = p % maxcol;

				org = screen_pos(vc, p, viewed);
				p += maxcol - col;

				
				this_round = (this_round + 1) >> 1;

				while (this_round) {
					*tmp_buf++ = vcs_scr_readw(vc, org++);
					this_round --;
					if (++col == maxcol) {
						org = screen_pos(vc, p, viewed);
						col = 0;
						p += maxcol;
					}
				}
			}
		}

		

		release_console_sem();
		ret = copy_to_user(buf, con_buf_start, orig_count);
		acquire_console_sem();

		if (ret) {
			read += (orig_count - ret);
			ret = -EFAULT;
			break;
		}
		buf += orig_count;
		pos += orig_count;
		read += orig_count;
		count -= orig_count;
	}
예제 #2
0
파일: vc_screen.c 프로젝트: 274914765/C
static ssize_t
vcs_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
    struct inode *inode = file->f_path.dentry->d_inode;
    unsigned int currcons = iminor(inode);
    struct vc_data *vc;
    long pos;
    long viewed, attr, read;
    int col, maxcol;
    unsigned short *org = NULL;
    ssize_t ret;

    mutex_lock(&con_buf_mtx);

    pos = *ppos;

    /* Select the proper current console and verify
     * sanity of the situation under the console lock.
     */
    acquire_console_sem();

    attr = (currcons & 128);
    currcons = (currcons & 127);
    if (currcons == 0) {
        currcons = fg_console;
        viewed = 1;
    } else {
        currcons--;
        viewed = 0;
    }
    ret = -ENXIO;
    if (!vc_cons_allocated(currcons))
        goto unlock_out;
    vc = vc_cons[currcons].d;

    ret = -EINVAL;
    if (pos < 0)
        goto unlock_out;
    read = 0;
    ret = 0;
    while (count) {
        char *con_buf0, *con_buf_start;
        long this_round, size;
        ssize_t orig_count;
        long p = pos;

        /* Check whether we are above size each round,
         * as copy_to_user at the end of this loop
         * could sleep.
         */
        size = vcs_size(inode);
        if (pos >= size)
            break;
        if (count > size - pos)
            count = size - pos;

        this_round = count;
        if (this_round > CON_BUF_SIZE)
            this_round = CON_BUF_SIZE;

        /* Perform the whole read into the local con_buf.
         * Then we can drop the console spinlock and safely
         * attempt to move it to userspace.
         */

        con_buf_start = con_buf0 = con_buf;
        orig_count = this_round;
        maxcol = vc->vc_cols;
        if (!attr) {
            org = screen_pos(vc, p, viewed);
            col = p % maxcol;
            p += maxcol - col;
            while (this_round-- > 0) {
                *con_buf0++ = (vcs_scr_readw(vc, org++) & 0xff);
                if (++col == maxcol) {
                    org = screen_pos(vc, p, viewed);
                    col = 0;
                    p += maxcol;
                }
            }
        } else {
            if (p < HEADER_SIZE) {
                size_t tmp_count;

                con_buf0[0] = (char)vc->vc_rows;
                con_buf0[1] = (char)vc->vc_cols;
                getconsxy(vc, con_buf0 + 2);

                con_buf_start += p;
                this_round += p;
                if (this_round > CON_BUF_SIZE) {
                    this_round = CON_BUF_SIZE;
                    orig_count = this_round - p;
                }

                tmp_count = HEADER_SIZE;
                if (tmp_count > this_round)
                    tmp_count = this_round;

                /* Advance state pointers and move on. */
                this_round -= tmp_count;
                p = HEADER_SIZE;
                con_buf0 = con_buf + HEADER_SIZE;
                /* If this_round >= 0, then p is even... */
            } else if (p & 1) {
                /* Skip first byte for output if start address is odd
                 * Update region sizes up/down depending on free
                 * space in buffer.
                 */
                con_buf_start++;
                if (this_round < CON_BUF_SIZE)
                    this_round++;
                else
                    orig_count--;
            }
            if (this_round > 0) {
                unsigned short *tmp_buf = (unsigned short *)con_buf0;

                p -= HEADER_SIZE;
                p /= 2;
                col = p % maxcol;

                org = screen_pos(vc, p, viewed);
                p += maxcol - col;

                /* Buffer has even length, so we can always copy
                 * character + attribute. We do not copy last byte
                 * to userspace if this_round is odd.
                 */
                this_round = (this_round + 1) >> 1;

                while (this_round) {
                    *tmp_buf++ = vcs_scr_readw(vc, org++);
                    this_round --;
                    if (++col == maxcol) {
                        org = screen_pos(vc, p, viewed);
                        col = 0;
                        p += maxcol;
                    }
                }
            }
        }

        /* Finally, release the console semaphore while we push
         * all the data to userspace from our temporary buffer.
         *
         * AKPM: Even though it's a semaphore, we should drop it because
         * the pagefault handling code may want to call printk().
         */

        release_console_sem();
        ret = copy_to_user(buf, con_buf_start, orig_count);
        acquire_console_sem();

        if (ret) {
            read += (orig_count - ret);
            ret = -EFAULT;
            break;
        }
        buf += orig_count;
        pos += orig_count;
        read += orig_count;
        count -= orig_count;
    }
예제 #3
0
static ssize_t
vcs_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
	struct inode *inode = file->f_dentry->d_inode;
	unsigned int currcons = MINOR(inode->i_rdev);
	long p = *ppos;
	long viewed, attr, size, read;
	char *buf0;
	int col, maxcol;
	unsigned short *org = NULL;

	attr = (currcons & 128);
	currcons = (currcons & 127);
	disable_bh(CONSOLE_BH);
	if (currcons == 0) {
		currcons = fg_console;
		viewed = 1;
	} else {
		currcons--;
		viewed = 0;
	}
	if (!vc_cons_allocated(currcons))
		RETURN( -ENXIO );

	size = vcs_size(inode);
	if (p < 0 || p > size)
		RETURN( -EINVAL );
	if (count > size - p)
		count = size - p;

	buf0 = buf;
	maxcol = video_num_columns;
	if (!attr) {
		org = screen_pos(currcons, p, viewed);
		col = p % maxcol;
		p += maxcol - col;
		while (count-- > 0) {
			put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++);
			if (++col == maxcol) {
				org = screen_pos(currcons, p, viewed);
				col = 0;
				p += maxcol;
			}
		}
	} else {
		if (p < HEADER_SIZE) {
			char header[HEADER_SIZE];
			header[0] = (char) video_num_lines;
			header[1] = (char) video_num_columns;
			getconsxy(currcons, header+2);
			while (p < HEADER_SIZE && count > 0)
			    { count--; put_user(header[p++], buf++); }
		}
		p -= HEADER_SIZE;
		col = (p/2) % maxcol;
		if (count > 0) {
			org = screen_pos(currcons, p/2, viewed);
			if ((p & 1) && count > 0) {
				count--;   
#ifdef __BIG_ENDIAN
				put_user(vcs_scr_readw(currcons, org++) & 0xff, buf++);
#else
				put_user(vcs_scr_readw(currcons, org++) >> 8, buf++);
#endif
				p++;
				if (++col == maxcol) {
					org = screen_pos(currcons, p/2, viewed);
					col = 0;
				}
			}
			p /= 2;
			p += maxcol - col;
		}