aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/vt_ioctl.c
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2009-09-19 16:13:24 -0400
committerLive-CD User <linux@linux.site>2009-09-19 16:13:24 -0400
commit8b92e87d39bfd046e7581e1fe0f40eac40f88608 (patch)
treeb558f69f2a9875ea6029546f9f70d268fd3ebaf6 /drivers/char/vt_ioctl.c
parent4455e344959a217ffc28de2ab1af87541322b343 (diff)
vt: add an event interface
This is needed and requested in various forms for ConsoleKit, screenblank handling and the like so do the job with a single interface. Also build the interface so that unlike VT_WAITACTIVE and friends it won't miss events. FIXME: Should this be a waitactive ioctl or a new device file you can poll and read events from. We need the code anyway to fix up the existing broken wait for console switch logic but the ConsoleKit people would prefer the new device to the ioctl we have here Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/char/vt_ioctl.c')
-rw-r--r--drivers/char/vt_ioctl.c185
1 files changed, 135 insertions, 50 deletions
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index 95189f288f8c..35ad94e65d0d 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -62,6 +62,133 @@ extern struct tty_driver *console_driver;
62static void complete_change_console(struct vc_data *vc); 62static void complete_change_console(struct vc_data *vc);
63 63
64/* 64/*
65 * User space VT_EVENT handlers
66 */
67
68struct vt_event_wait {
69 struct list_head list;
70 struct vt_event event;
71 int done;
72};
73
74static LIST_HEAD(vt_events);
75static DEFINE_SPINLOCK(vt_event_lock);
76static DECLARE_WAIT_QUEUE_HEAD(vt_event_waitqueue);
77
78/**
79 * vt_event_post
80 * @event: the event that occurred
81 * @old: old console
82 * @new: new console
83 *
84 * Post an VT event to interested VT handlers
85 */
86
87void vt_event_post(unsigned int event, unsigned int old, unsigned int new)
88{
89 struct list_head *pos, *head;
90 unsigned long flags;
91 int wake = 0;
92
93 spin_lock_irqsave(&vt_event_lock, flags);
94 head = &vt_events;
95
96 list_for_each(pos, head) {
97 struct vt_event_wait *ve = list_entry(pos,
98 struct vt_event_wait, list);
99 if (!(ve->event.event & event))
100 continue;
101 ve->event.event = event;
102 /* kernel view is consoles 0..n-1, user space view is
103 console 1..n with 0 meaning current, so we must bias */
104 ve->event.old = old + 1;
105 ve->event.new = new + 1;
106 wake = 1;
107 ve->done = 1;
108 }
109 spin_unlock_irqrestore(&vt_event_lock, flags);
110 if (wake)
111 wake_up_interruptible(&vt_event_waitqueue);
112}
113
114/**
115 * vt_event_wait - wait for an event
116 * @vw: our event
117 *
118 * Waits for an event to occur which completes our vt_event_wait
119 * structure. On return the structure has wv->done set to 1 for success
120 * or 0 if some event such as a signal ended the wait.
121 */
122
123static void vt_event_wait(struct vt_event_wait *vw)
124{
125 unsigned long flags;
126 /* Prepare the event */
127 INIT_LIST_HEAD(&vw->list);
128 vw->done = 0;
129 /* Queue our event */
130 spin_lock_irqsave(&vt_event_lock, flags);
131 list_add(&vw->list, &vt_events);
132 spin_unlock_irqrestore(&vt_event_lock, flags);
133 /* Wait for it to pass */
134 wait_event_interruptible(vt_event_waitqueue, vw->done);
135 /* Dequeue it */
136 spin_lock_irqsave(&vt_event_lock, flags);
137 list_del(&vw->list);
138 spin_unlock_irqrestore(&vt_event_lock, flags);
139}
140
141/**
142 * vt_event_wait_ioctl - event ioctl handler
143 * @arg: argument to ioctl
144 *
145 * Implement the VT_WAITEVENT ioctl using the VT event interface
146 */
147
148static int vt_event_wait_ioctl(struct vt_event __user *event)
149{
150 struct vt_event_wait vw;
151
152 if (copy_from_user(&vw.event, event, sizeof(struct vt_event)))
153 return -EFAULT;
154 /* Highest supported event for now */
155 if (vw.event.event & ~VT_MAX_EVENT)
156 return -EINVAL;
157
158 vt_event_wait(&vw);
159 /* If it occurred report it */
160 if (vw.done) {
161 if (copy_to_user(event, &vw.event, sizeof(struct vt_event)))
162 return -EFAULT;
163 return 0;
164 }
165 return -EINTR;
166}
167
168/**
169 * vt_waitactive - active console wait
170 * @event: event code
171 * @n: new console
172 *
173 * Helper for event waits. Used to implement the legacy
174 * event waiting ioctls in terms of events
175 */
176
177int vt_waitactive(int n)
178{
179 struct vt_event_wait vw;
180 do {
181 if (n == fg_console + 1)
182 break;
183 vw.event.event = VT_EVENT_SWITCH;
184 vt_event_wait(&vw);
185 if (vw.done == 0)
186 return -EINTR;
187 } while (vw.event.new != n);
188 return 0;
189}
190
191/*
65 * these are the valid i/o ports we're allowed to change. they map all the 192 * these are the valid i/o ports we're allowed to change. they map all the
66 * video ports 193 * video ports
67 */ 194 */
@@ -360,6 +487,8 @@ do_unimap_ioctl(int cmd, struct unimapdesc __user *user_ud, int perm, struct vc_
360 return 0; 487 return 0;
361} 488}
362 489
490
491
363/* 492/*
364 * We handle the console-specific ioctl's here. We allow the 493 * We handle the console-specific ioctl's here. We allow the
365 * capability to modify any console, not just the fg_console. 494 * capability to modify any console, not just the fg_console.
@@ -851,7 +980,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
851 if (arg == 0 || arg > MAX_NR_CONSOLES) 980 if (arg == 0 || arg > MAX_NR_CONSOLES)
852 ret = -ENXIO; 981 ret = -ENXIO;
853 else 982 else
854 ret = vt_waitactive(arg - 1); 983 ret = vt_waitactive(arg);
855 break; 984 break;
856 985
857 /* 986 /*
@@ -1159,6 +1288,9 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
1159 ret = put_user(vc->vc_hi_font_mask, 1288 ret = put_user(vc->vc_hi_font_mask,
1160 (unsigned short __user *)arg); 1289 (unsigned short __user *)arg);
1161 break; 1290 break;
1291 case VT_WAITEVENT:
1292 ret = vt_event_wait_ioctl((struct vt_event __user *)arg);
1293 break;
1162 default: 1294 default:
1163 ret = -ENOIOCTLCMD; 1295 ret = -ENOIOCTLCMD;
1164 } 1296 }
@@ -1170,54 +1302,6 @@ eperm:
1170 goto out; 1302 goto out;
1171} 1303}
1172 1304
1173/*
1174 * Sometimes we want to wait until a particular VT has been activated. We
1175 * do it in a very simple manner. Everybody waits on a single queue and
1176 * get woken up at once. Those that are satisfied go on with their business,
1177 * while those not ready go back to sleep. Seems overkill to add a wait
1178 * to each vt just for this - usually this does nothing!
1179 */
1180static DECLARE_WAIT_QUEUE_HEAD(vt_activate_queue);
1181
1182/*
1183 * Sleeps until a vt is activated, or the task is interrupted. Returns
1184 * 0 if activation, -EINTR if interrupted by a signal handler.
1185 */
1186int vt_waitactive(int vt)
1187{
1188 int retval;
1189 DECLARE_WAITQUEUE(wait, current);
1190
1191 add_wait_queue(&vt_activate_queue, &wait);
1192 for (;;) {
1193 retval = 0;
1194
1195 /*
1196 * Synchronize with redraw_screen(). By acquiring the console
1197 * semaphore we make sure that the console switch is completed
1198 * before we return. If we didn't wait for the semaphore, we
1199 * could return at a point where fg_console has already been
1200 * updated, but the console switch hasn't been completed.
1201 */
1202 acquire_console_sem();
1203 set_current_state(TASK_INTERRUPTIBLE);
1204 if (vt == fg_console) {
1205 release_console_sem();
1206 break;
1207 }
1208 release_console_sem();
1209 retval = -ERESTARTNOHAND;
1210 if (signal_pending(current))
1211 break;
1212 schedule();
1213 }
1214 remove_wait_queue(&vt_activate_queue, &wait);
1215 __set_current_state(TASK_RUNNING);
1216 return retval;
1217}
1218
1219#define vt_wake_waitactive() wake_up(&vt_activate_queue)
1220
1221void reset_vc(struct vc_data *vc) 1305void reset_vc(struct vc_data *vc)
1222{ 1306{
1223 vc->vc_mode = KD_TEXT; 1307 vc->vc_mode = KD_TEXT;
@@ -1262,6 +1346,7 @@ void vc_SAK(struct work_struct *work)
1262static void complete_change_console(struct vc_data *vc) 1346static void complete_change_console(struct vc_data *vc)
1263{ 1347{
1264 unsigned char old_vc_mode; 1348 unsigned char old_vc_mode;
1349 int old = fg_console;
1265 1350
1266 last_console = fg_console; 1351 last_console = fg_console;
1267 1352
@@ -1325,7 +1410,7 @@ static void complete_change_console(struct vc_data *vc)
1325 /* 1410 /*
1326 * Wake anyone waiting for their VT to activate 1411 * Wake anyone waiting for their VT to activate
1327 */ 1412 */
1328 vt_wake_waitactive(); 1413 vt_event_post(VT_EVENT_SWITCH, old, vc->vc_num);
1329 return; 1414 return;
1330} 1415}
1331 1416