Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 163838
b: refs/heads/master
c: 8b92e87
h: refs/heads/master
v: v3
  • Loading branch information
Alan Cox authored and Live-CD User committed Sep 19, 2009
1 parent e1d8cfc commit 911a8d6
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 53 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 4455e344959a217ffc28de2ab1af87541322b343
refs/heads/master: 8b92e87d39bfd046e7581e1fe0f40eac40f88608
4 changes: 3 additions & 1 deletion trunk/drivers/char/vt.c
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,6 @@ static void notify_update(struct vc_data *vc)
struct vt_notifier_param param = { .vc = vc };
atomic_notifier_call_chain(&vt_notifier_list, VT_UPDATE, &param);
}

/*
* Low-Level Functions
*/
Expand Down Expand Up @@ -935,6 +934,7 @@ static int vc_do_resize(struct tty_struct *tty, struct vc_data *vc,

if (CON_IS_VISIBLE(vc))
update_screen(vc);
vt_event_post(VT_EVENT_RESIZE, vc->vc_num, vc->vc_num);
return err;
}

Expand Down Expand Up @@ -3637,6 +3637,7 @@ void do_blank_screen(int entering_gfx)
blank_state = blank_vesa_wait;
mod_timer(&console_timer, jiffies + vesa_off_interval);
}
vt_event_post(VT_EVENT_BLANK, vc->vc_num, vc->vc_num);
}
EXPORT_SYMBOL(do_blank_screen);

Expand Down Expand Up @@ -3681,6 +3682,7 @@ void do_unblank_screen(int leaving_gfx)
console_blank_hook(0);
set_palette(vc);
set_cursor(vc);
vt_event_post(VT_EVENT_UNBLANK, vc->vc_num, vc->vc_num);
}
EXPORT_SYMBOL(do_unblank_screen);

Expand Down
185 changes: 135 additions & 50 deletions trunk/drivers/char/vt_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,133 @@ extern struct tty_driver *console_driver;

static void complete_change_console(struct vc_data *vc);

/*
* User space VT_EVENT handlers
*/

struct vt_event_wait {
struct list_head list;
struct vt_event event;
int done;
};

static LIST_HEAD(vt_events);
static DEFINE_SPINLOCK(vt_event_lock);
static DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue);

/**
* vt_event_post
* @event: the event that occurred
* @old: old console
* @new: new console
*
* Post an VT event to interested VT handlers
*/

void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
{
struct list_head *pos, *head;
unsigned long flags;
int wake = 0;

spin_lock_irqsave(&vt_event_lock, flags);
head = &vt_events;

list_for_each(pos, head) {
struct vt_event_wait *ve = list_entry(pos,
struct vt_event_wait, list);
if (!(ve->event.event & event))
continue;
ve->event.event = event;
/* kernel view is consoles 0..n-1, user space view is
console 1..n with 0 meaning current, so we must bias */
ve->event.old = old + 1;
ve->event.new = new + 1;
wake = 1;
ve->done = 1;
}
spin_unlock_irqrestore(&vt_event_lock, flags);
if (wake)
wake_up_interruptible(&vt_event_waitqueue);
}

/**
* vt_event_wait - wait for an event
* @vw: our event
*
* Waits for an event to occur which completes our vt_event_wait
* structure. On return the structure has wv->done set to 1 for success
* or 0 if some event such as a signal ended the wait.
*/

static void vt_event_wait(struct vt_event_wait *vw)
{
unsigned long flags;
/* Prepare the event */
INIT_LIST_HEAD(&vw->list);
vw->done = 0;
/* Queue our event */
spin_lock_irqsave(&vt_event_lock, flags);
list_add(&vw->list, &vt_events);
spin_unlock_irqrestore(&vt_event_lock, flags);
/* Wait for it to pass */
wait_event_interruptible(vt_event_waitqueue, vw->done);
/* Dequeue it */
spin_lock_irqsave(&vt_event_lock, flags);
list_del(&vw->list);
spin_unlock_irqrestore(&vt_event_lock, flags);
}

/**
* vt_event_wait_ioctl - event ioctl handler
* @arg: argument to ioctl
*
* Implement the VT_WAITEVENT ioctl using the VT event interface
*/

static int vt_event_wait_ioctl(struct vt_event __user *event)
{
struct vt_event_wait vw;

if (copy_from_user(&vw.event, event, sizeof(struct vt_event)))
return -EFAULT;
/* Highest supported event for now */
if (vw.event.event & ~VT_MAX_EVENT)
return -EINVAL;

vt_event_wait(&vw);
/* If it occurred report it */
if (vw.done) {
if (copy_to_user(event, &vw.event, sizeof(struct vt_event)))
return -EFAULT;
return 0;
}
return -EINTR;
}

/**
* vt_waitactive - active console wait
* @event: event code
* @n: new console
*
* Helper for event waits. Used to implement the legacy
* event waiting ioctls in terms of events
*/

int vt_waitactive(int n)
{
struct vt_event_wait vw;
do {
if (n == fg_console + 1)
break;
vw.event.event = VT_EVENT_SWITCH;
vt_event_wait(&vw);
if (vw.done == 0)
return -EINTR;
} while (vw.event.new != n);
return 0;
}

/*
* these are the valid i/o ports we're allowed to change. they map all the
* video ports
Expand Down Expand Up @@ -360,6 +487,8 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_
return 0;
}



/*
* We handle the console-specific ioctl's here. We allow the
* capability to modify any console, not just the fg_console.
Expand Down Expand Up @@ -851,7 +980,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (arg == 0 || arg > MAX_NR_CONSOLES)
ret = -ENXIO;
else
ret = vt_waitactive(arg - 1);
ret = vt_waitactive(arg);
break;

/*
Expand Down Expand Up @@ -1159,6 +1288,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
ret = put_user(vc->vc_hi_font_mask,
(unsigned short __user *)arg);
break;
case VT_WAITEVENT:
ret = vt_event_wait_ioctl((struct vt_event __user *)arg);
break;
default:
ret = -ENOIOCTLCMD;
}
Expand All @@ -1170,54 +1302,6 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
goto out;
}

/*
* Sometimes we want to wait until a particular VT has been activated. We
* do it in a very simple manner. Everybody waits on a single queue and
* get woken up at once. Those that are satisfied go on with their business,
* while those not ready go back to sleep. Seems overkill to add a wait
* to each vt just for this - usually this does nothing!
*/
static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue);

/*
* Sleeps until a vt is activated, or the task is interrupted. Returns
* 0 if activation, -EINTR if interrupted by a signal handler.
*/
int vt_waitactive(int vt)
{
int retval;
DECLARE_WAITQUEUE(wait, current);

add_wait_queue(&vt_activate_queue, &wait);
for (;;) {
retval = 0;

/*
* Synchronize with redraw_screen(). By acquiring the console
* semaphore we make sure that the console switch is completed
* before we return. If we didn't wait for the semaphore, we
* could return at a point where fg_console has already been
* updated, but the console switch hasn't been completed.
*/
acquire_console_sem();
set_current_state(TASK_INTERRUPTIBLE);
if (vt == fg_console) {
release_console_sem();
break;
}
release_console_sem();
retval = -ERESTARTNOHAND;
if (signal_pending(current))
break;
schedule();
}
remove_wait_queue(&vt_activate_queue, &wait);
__set_current_state(TASK_RUNNING);
return retval;
}

#define vt_wake_waitactive() wake_up(&vt_activate_queue)

void reset_vc(struct vc_data *vc)
{
vc->vc_mode = KD_TEXT;
Expand Down Expand Up @@ -1262,6 +1346,7 @@ void vc_SAK(struct work_struct *work)
static void complete_change_console(struct vc_data *vc)
{
unsigned char old_vc_mode;
int old = fg_console;

last_console = fg_console;

Expand Down Expand Up @@ -1325,7 +1410,7 @@ static void complete_change_console(struct vc_data *vc)
/*
* Wake anyone waiting for their VT to activate
*/
vt_wake_waitactive();
vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num);
return;
}

Expand Down
14 changes: 14 additions & 0 deletions trunk/include/linux/vt.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,18 @@ struct vt_consize {
#define VT_UNLOCKSWITCH 0x560C /* allow vt switching */
#define VT_GETHIFONTMASK 0x560D /* return hi font mask */

struct vt_event {
unsigned int event;
#define VT_EVENT_SWITCH 0x0001 /* Console switch */
#define VT_EVENT_BLANK 0x0002 /* Screen blank */
#define VT_EVENT_UNBLANK 0x0004 /* Screen unblank */
#define VT_EVENT_RESIZE 0x0008 /* Resize display */
#define VT_MAX_EVENT 0x000F
unsigned int old; /* Old console */
unsigned int new; /* New console (if changing) */
unsigned int pad[4]; /* Padding for expansion */
};

#define VT_WAITEVENT 0x560E /* Wait for an event */

#endif /* _LINUX_VT_H */
3 changes: 2 additions & 1 deletion trunk/include/linux/vt_kern.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc);
#endif

/* vt.c */
int vt_waitactive(int vt);
void vt_event_post(unsigned int event, unsigned int old, unsigned int new);
int vt_waitactive(int n);
void change_console(struct vc_data *new_vc);
void reset_vc(struct vc_data *vc);
extern int unbind_con_driver(const struct consw *csw, int first, int last,
Expand Down

0 comments on commit 911a8d6

Please sign in to comment.