162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/slab.h>
762306a36Sopenharmony_ci#include <linux/completion.h>
862306a36Sopenharmony_ci#include <linux/irqreturn.h>
962306a36Sopenharmony_ci#include <asm/irq.h>
1062306a36Sopenharmony_ci#include <irq_kern.h>
1162306a36Sopenharmony_ci#include <os.h>
1262306a36Sopenharmony_ci#include "xterm.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistruct xterm_wait {
1562306a36Sopenharmony_ci	struct completion ready;
1662306a36Sopenharmony_ci	int fd;
1762306a36Sopenharmony_ci	int pid;
1862306a36Sopenharmony_ci	int new_fd;
1962306a36Sopenharmony_ci};
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_cistatic irqreturn_t xterm_interrupt(int irq, void *data)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	struct xterm_wait *xterm = data;
2462306a36Sopenharmony_ci	int fd;
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	fd = os_rcv_fd(xterm->fd, &xterm->pid);
2762306a36Sopenharmony_ci	if (fd == -EAGAIN)
2862306a36Sopenharmony_ci		return IRQ_NONE;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	xterm->new_fd = fd;
3162306a36Sopenharmony_ci	complete(&xterm->ready);
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	return IRQ_HANDLED;
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciint xterm_fd(int socket, int *pid_out)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	struct xterm_wait *data;
3962306a36Sopenharmony_ci	int err, ret;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	data = kmalloc(sizeof(*data), GFP_KERNEL);
4262306a36Sopenharmony_ci	if (data == NULL) {
4362306a36Sopenharmony_ci		printk(KERN_ERR "xterm_fd : failed to allocate xterm_wait\n");
4462306a36Sopenharmony_ci		return -ENOMEM;
4562306a36Sopenharmony_ci	}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	/* This is a locked semaphore... */
4862306a36Sopenharmony_ci	*data = ((struct xterm_wait) { .fd 		= socket,
4962306a36Sopenharmony_ci				       .pid 		= -1,
5062306a36Sopenharmony_ci				       .new_fd	 	= -1 });
5162306a36Sopenharmony_ci	init_completion(&data->ready);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt,
5462306a36Sopenharmony_ci			     IRQF_SHARED, "xterm", data);
5562306a36Sopenharmony_ci	if (err < 0) {
5662306a36Sopenharmony_ci		printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, "
5762306a36Sopenharmony_ci		       "err = %d\n",  err);
5862306a36Sopenharmony_ci		ret = err;
5962306a36Sopenharmony_ci		goto out;
6062306a36Sopenharmony_ci	}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/* ... so here we wait for an xterm interrupt.
6362306a36Sopenharmony_ci	 *
6462306a36Sopenharmony_ci	 * XXX Note, if the xterm doesn't work for some reason (eg. DISPLAY
6562306a36Sopenharmony_ci	 * isn't set) this will hang... */
6662306a36Sopenharmony_ci	wait_for_completion(&data->ready);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	um_free_irq(XTERM_IRQ, data);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	ret = data->new_fd;
7162306a36Sopenharmony_ci	*pid_out = data->pid;
7262306a36Sopenharmony_ci out:
7362306a36Sopenharmony_ci	kfree(data);
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return ret;
7662306a36Sopenharmony_ci}
77