aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/vt_ioctl.c
diff options
context:
space:
mode:
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