18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Copyright (c) 1996-2001 Vojtech Pavlik
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci/*
78c2ecf20Sopenharmony_ci * This is just a very simple driver that can dump the data
88c2ecf20Sopenharmony_ci * out of the joystick port into the syslog ...
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/*
128c2ecf20Sopenharmony_ci */
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/gameport.h>
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <linux/delay.h>
188c2ecf20Sopenharmony_ci#include <linux/slab.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#define DRIVER_DESC	"Gameport data dumper module"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ciMODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
238c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC);
248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci#define BUF_SIZE 256
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistruct joydump {
298c2ecf20Sopenharmony_ci	unsigned int time;
308c2ecf20Sopenharmony_ci	unsigned char data;
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic int joydump_connect(struct gameport *gameport, struct gameport_driver *drv)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	struct joydump *buf;	/* all entries */
368c2ecf20Sopenharmony_ci	struct joydump *dump, *prev;	/* one entry each */
378c2ecf20Sopenharmony_ci	int axes[4], buttons;
388c2ecf20Sopenharmony_ci	int i, j, t, timeout;
398c2ecf20Sopenharmony_ci	unsigned long flags;
408c2ecf20Sopenharmony_ci	unsigned char u;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	printk(KERN_INFO "joydump: ,------------------ START ----------------.\n");
438c2ecf20Sopenharmony_ci	printk(KERN_INFO "joydump: | Dumping: %30s |\n", gameport->phys);
448c2ecf20Sopenharmony_ci	printk(KERN_INFO "joydump: | Speed: %28d kHz |\n", gameport->speed);
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	if (gameport_open(gameport, drv, GAMEPORT_MODE_RAW)) {
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci		printk(KERN_INFO "joydump: | Raw mode not available - trying cooked.    |\n");
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci		if (gameport_open(gameport, drv, GAMEPORT_MODE_COOKED)) {
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci			printk(KERN_INFO "joydump: | Cooked not available either. Failing.   |\n");
538c2ecf20Sopenharmony_ci			printk(KERN_INFO "joydump: `------------------- END -----------------'\n");
548c2ecf20Sopenharmony_ci			return -ENODEV;
558c2ecf20Sopenharmony_ci		}
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci		gameport_cooked_read(gameport, axes, &buttons);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci		for (i = 0; i < 4; i++)
608c2ecf20Sopenharmony_ci			printk(KERN_INFO "joydump: | Axis %d: %4d.                           |\n", i, axes[i]);
618c2ecf20Sopenharmony_ci		printk(KERN_INFO "joydump: | Buttons %02x.                             |\n", buttons);
628c2ecf20Sopenharmony_ci		printk(KERN_INFO "joydump: `------------------- END -----------------'\n");
638c2ecf20Sopenharmony_ci	}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	timeout = gameport_time(gameport, 10000); /* 10 ms */
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	buf = kmalloc_array(BUF_SIZE, sizeof(struct joydump), GFP_KERNEL);
688c2ecf20Sopenharmony_ci	if (!buf) {
698c2ecf20Sopenharmony_ci		printk(KERN_INFO "joydump: no memory for testing\n");
708c2ecf20Sopenharmony_ci		goto jd_end;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci	dump = buf;
738c2ecf20Sopenharmony_ci	t = 0;
748c2ecf20Sopenharmony_ci	i = 1;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	local_irq_save(flags);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	u = gameport_read(gameport);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	dump->data = u;
818c2ecf20Sopenharmony_ci	dump->time = t;
828c2ecf20Sopenharmony_ci	dump++;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	gameport_trigger(gameport);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	while (i < BUF_SIZE && t < timeout) {
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		dump->data = gameport_read(gameport);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci		if (dump->data ^ u) {
918c2ecf20Sopenharmony_ci			u = dump->data;
928c2ecf20Sopenharmony_ci			dump->time = t;
938c2ecf20Sopenharmony_ci			i++;
948c2ecf20Sopenharmony_ci			dump++;
958c2ecf20Sopenharmony_ci		}
968c2ecf20Sopenharmony_ci		t++;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	local_irq_restore(flags);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci/*
1028c2ecf20Sopenharmony_ci * Dump data.
1038c2ecf20Sopenharmony_ci */
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	t = i;
1068c2ecf20Sopenharmony_ci	dump = buf;
1078c2ecf20Sopenharmony_ci	prev = dump;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	printk(KERN_INFO "joydump: >------------------ DATA -----------------<\n");
1108c2ecf20Sopenharmony_ci	printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ", 0, 0);
1118c2ecf20Sopenharmony_ci	for (j = 7; j >= 0; j--)
1128c2ecf20Sopenharmony_ci		printk("%d", (dump->data >> j) & 1);
1138c2ecf20Sopenharmony_ci	printk(" |\n");
1148c2ecf20Sopenharmony_ci	dump++;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	for (i = 1; i < t; i++, dump++, prev++) {
1178c2ecf20Sopenharmony_ci		printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ",
1188c2ecf20Sopenharmony_ci			i, dump->time - prev->time);
1198c2ecf20Sopenharmony_ci		for (j = 7; j >= 0; j--)
1208c2ecf20Sopenharmony_ci			printk("%d", (dump->data >> j) & 1);
1218c2ecf20Sopenharmony_ci		printk(" |\n");
1228c2ecf20Sopenharmony_ci	}
1238c2ecf20Sopenharmony_ci	kfree(buf);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cijd_end:
1268c2ecf20Sopenharmony_ci	printk(KERN_INFO "joydump: `------------------- END -----------------'\n");
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return 0;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_cistatic void joydump_disconnect(struct gameport *gameport)
1328c2ecf20Sopenharmony_ci{
1338c2ecf20Sopenharmony_ci	gameport_close(gameport);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic struct gameport_driver joydump_drv = {
1378c2ecf20Sopenharmony_ci	.driver		= {
1388c2ecf20Sopenharmony_ci		.name	= "joydump",
1398c2ecf20Sopenharmony_ci	},
1408c2ecf20Sopenharmony_ci	.description	= DRIVER_DESC,
1418c2ecf20Sopenharmony_ci	.connect	= joydump_connect,
1428c2ecf20Sopenharmony_ci	.disconnect	= joydump_disconnect,
1438c2ecf20Sopenharmony_ci};
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_cimodule_gameport_driver(joydump_drv);
146