File: x52pro.c

package info (click to toggle)
x52pro 0.2.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 196 kB
  • sloc: ansic: 137; makefile: 85; xml: 24
file content (349 lines) | stat: -rw-r--r-- 7,558 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
/* x52pro driver library
 * Copyright (C) 2007 Eduard Hasenleithner <eduard@hasenleithner.at>
 * Licensed under the LGPL. Please see "COPYING".
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libusb.h>
#include "x52pro.h"

struct x52 {
	libusb_device_handle *hdl;
	enum x52_type type;
	unsigned feat_mfd:1;
	unsigned feat_led:1;
	unsigned feat_sec:1;
	unsigned debug:1;
};

#define X52PRO_REQUEST 0x91

#define X52PRO_CLEAR1 0xd9
#define X52PRO_CLEAR2 0xda
#define X52PRO_CLEAR3 0xdc
#define X52PRO_WRITE1 0xd1
#define X52PRO_WRITE2 0xd2
#define X52PRO_WRITE3 0xd4
#define X52PRO_SETLED 0xb8
#define X52PRO_MFDBRI 0xb1
#define X52PRO_LEDBRI 0xb2

#define X52PRO_TIME   0xc0
#define X52PRO_OFFS2  0xc1
#define X52PRO_OFFS3  0xc2
#define X52PRO_DATE   0xc4
#define X52PRO_YEAR   0xc8

#define YOKE_SECOND   0xca

int write_idx[3] = {
	X52PRO_WRITE1,
	X52PRO_WRITE2,
	X52PRO_WRITE3,
};

int clear_idx[3] = {
	X52PRO_CLEAR1,
	X52PRO_CLEAR2,
	X52PRO_CLEAR3,
};

#define x52printf if (x52->debug) fprintf

int x52_settext(struct x52 *x52, int line, char *text, int length)
{
	if ((!x52) || (!text)) {
		// Reject NULL pointers
		return -10;
	}

	int r;
	if (!x52->feat_mfd) {
		x52printf(stderr, "settext not supported\n");
		return -3;
	}
	if (line > 3) return -1;
	r = libusb_control_transfer(x52->hdl,
		LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE,
		X52PRO_REQUEST, 0x00, clear_idx[line], NULL, 0, 1000);
	if (r != LIBUSB_SUCCESS) {
		x52printf(stderr, "x52_settext failed at clear command (%s)\n",
			libusb_strerror(r));
		return -2;
	}

	while (length >= 1) {
		int chars;
		if (length == 1) chars = (' ' << 8) + *text;
		else chars = *(unsigned short*) text;
		r = libusb_control_transfer(x52->hdl,
			LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE,
			X52PRO_REQUEST, chars, write_idx[line], NULL, 0, 1000);
		if (r != LIBUSB_SUCCESS) {
			x52printf(stderr, "x52_settext failed at write %d (%s)\n",
				length, libusb_strerror(r));
			return -2;
		}
		length -= 2;
		text += 2;
	}
	return 0;
}

int x52_setbri(struct x52 *x52, int mfd, int brightness)
{
	if (!x52) {
		// Reject NULL pointers
		return -10;
	}

	int r;
	if (!x52->feat_mfd) {
		x52printf(stderr, "setbri not supported\n");
		return -3;
	}
	r = libusb_control_transfer(x52->hdl,
		LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE,
		X52PRO_REQUEST, brightness, mfd ? X52PRO_MFDBRI : X52PRO_LEDBRI,
		NULL, 0, 1000);
	if (r != LIBUSB_SUCCESS) {
		x52printf(stderr, "x52_setbri failed (%s)\n", libusb_strerror(r));
		return -2;
	}
	return 0;
}

int x52_setled(struct x52 *x52, int led, int on)
{
	if (!x52) {
		// Reject NULL pointers
		return -10;
	}

	int r;
	if (!x52->feat_led) {
		x52printf(stderr, "setled not supported\n");
		return -3;
	}

	on = !!on; // Ensure that only least significant bit is set

	r = libusb_control_transfer(x52->hdl,
		LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE,
		X52PRO_REQUEST, on | (led<<8), X52PRO_SETLED,
		NULL, 0, 1000);
	if (r != LIBUSB_SUCCESS) {
		x52printf(stderr, "x52_setled failed (%s)\n", libusb_strerror(r));
		return -2;
	}
	return 0;
}

int x52_settime(struct x52 *x52, int h24, int hour, int minute)
{
	if (!x52) {
		// Reject NULL pointers
		return -10;
	}

	int r;
	r = libusb_control_transfer(x52->hdl,
		LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE,
		X52PRO_REQUEST, minute | (hour<<8) | (h24?0x8000:0), X52PRO_TIME,
		NULL, 0, 1000);
	if (r != LIBUSB_SUCCESS) {
		x52printf(stderr, "x52_settime failed (%s)\n", libusb_strerror(r));
		return -2;
	}
	return 0;
}

int x52_setoffs(struct x52 *x52, int idx, int h24, int inv, int offset)
{
	if (!x52) {
		// Reject NULL pointers
		return -10;
	}

	int r;
	r = libusb_control_transfer(x52->hdl,
		LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE,
		X52PRO_REQUEST,
		offset | (inv?1024:0) | (h24?0x8000:0), idx?X52PRO_OFFS3:X52PRO_OFFS2,
		NULL, 0, 1000);
	if (r != LIBUSB_SUCCESS) {
		x52printf(stderr, "x52_settime failed (%s)\n", libusb_strerror(r));
		return -2;
	}

	return 0;
}

int x52_setsecond(struct x52 *x52, int second)
{
	if (!x52) {
		// Reject NULL pointers
		return -10;
	}

	int r;
	if (!x52->feat_sec) {
		x52printf(stderr, "setsecond not supported\n");
		return -3;
	}
	r = libusb_control_transfer(x52->hdl,
		LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE,
		X52PRO_REQUEST, second<<8, YOKE_SECOND,
		NULL, 0, 1000);
	if (r != LIBUSB_SUCCESS) {
		x52printf(stderr, "x52_setsecond failed (%s)\n", libusb_strerror(r));
		return -2;
	}
	return 0;
}

int x52_setdate(struct x52 *x52, int year, int month, int day)
{
	if (!x52) {
		// Reject NULL pointers
		return -10;
	}

	int r;
	if (!x52->feat_mfd) {
		x52printf(stderr, "setdate not supported\n");
		return -3;
	}
	r = libusb_control_transfer(x52->hdl,
		LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE,
		X52PRO_REQUEST, day | (month<<8), X52PRO_DATE,
		NULL, 0, 1000);
	if (r != LIBUSB_SUCCESS) {
		x52printf(stderr, "x52_setdate failed (%s)\n", libusb_strerror(r));
		return -2;
	}
	r = libusb_control_transfer(x52->hdl,
		LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE,
		X52PRO_REQUEST, year, X52PRO_YEAR,
		NULL, 0, 1000);
	if (r != LIBUSB_SUCCESS) {
		x52printf(stderr, "x52_setdate failed for year (%s)\n", libusb_strerror(r));
		return -2;
	}
	return 0;
}

int x52_custom(struct x52 *x52, int index, int value)
{
	if (!x52) {
		// Reject NULL pointers
		return -10;
	}

	int r = libusb_control_transfer(x52->hdl,
		LIBUSB_REQUEST_TYPE_VENDOR|LIBUSB_RECIPIENT_DEVICE,
		X52PRO_REQUEST, value, index, NULL, 0, 1000);
	if (r != LIBUSB_SUCCESS) {
		x52printf(stderr, "x52_settext failed at clear command (%s)\n",
			libusb_strerror(r));
		return -2;
	}
	return 0;
}

#define VENDOR_SAITEK 0x6a3
#define PRODUCT_X52_0 0x255
#define PRODUCT_X52_1 0x75c
#define PRODUCT_X52PRO 0x762
#define PRODUCT_YOKE 0xbac

struct x52* x52_init(void)
{
	int r;
	struct x52 x52, *x52p;
	libusb_device **device_list;
	libusb_device *joydev = NULL;

#if LIBUSB_API_VERSION >= 0x0100010A
	libusb_init_context(NULL, NULL, 0);
# else
	libusb_init(NULL);
#endif /* LIBUSB_API_VERSION >= 0x0100010A */
	ssize_t num_devices = libusb_get_device_list(NULL, &device_list);

	memset(&x52, 0, sizeof(x52));

	for (int i=0; i<num_devices; i++) {
		struct libusb_device_descriptor desc;
		libusb_device *dev = device_list[i];
		r = libusb_get_device_descriptor(dev, &desc);
		if (desc.idVendor != VENDOR_SAITEK) continue;
		switch (desc.idProduct) {
		case PRODUCT_X52_0:
		case PRODUCT_X52_1:
			x52.feat_mfd = 1;
			x52.type = DEV_X52;
			joydev = dev;
			break;
		case PRODUCT_X52PRO:
			x52.feat_mfd = 1;
			x52.feat_led = 1;
			x52.type = DEV_X52PRO;
			joydev = dev;
			break;
		case PRODUCT_YOKE:
			x52.feat_sec = 1;
			x52.type = DEV_YOKE;
			joydev = dev;
			break;
		}
		if (joydev) break;
	}
	if (!joydev) {
		fprintf(stderr, "joystick not found\n");
		libusb_free_device_list(device_list, 1);
		return NULL;
	}
	r = libusb_open(joydev, &x52.hdl);
	if (r != LIBUSB_SUCCESS) {
		fprintf(stderr, "joystick open failed\n");
		libusb_free_device_list(device_list, 1);
		return NULL;
	}
	libusb_free_device_list(device_list, 1);
	x52p = malloc(sizeof(*x52p));
	*x52p = x52;
	return x52p;
}

enum x52_type x52_gettype(struct x52* hdl)
{
	if (!hdl) {
		// Reject NULL pointers
		return DEV_INVALID;
	}

	return hdl->type;
}

void x52_close(struct x52* x52) 
{
	if (!x52) {
		// Reject NULL pointers
		return;
	}

	libusb_close(x52->hdl);
	free(x52);
}

void x52_debug(struct x52* x52, int debug)
{
	if (!x52) {
		// Reject NULL pointers
		return;
	}

	x52->debug = !!debug;
}