Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/compat/linux/linux_ioctl.c
102076 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 1994-1995 Søren Schmidt
5
* All rights reserved.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*/
28
29
#include <sys/param.h>
30
#include <sys/capsicum.h>
31
#include <sys/cdio.h>
32
#include <sys/consio.h>
33
#include <sys/disk.h>
34
#include <sys/dvdio.h>
35
#include <sys/fcntl.h>
36
#include <sys/filio.h>
37
#include <sys/jail.h>
38
#include <sys/kbio.h>
39
#include <sys/kcov.h>
40
#include <sys/kernel.h>
41
#include <sys/linker_set.h>
42
#include <sys/lock.h>
43
#include <sys/malloc.h>
44
#include <sys/mman.h>
45
#include <sys/proc.h>
46
#include <sys/sbuf.h>
47
#include <sys/sockio.h>
48
#include <sys/soundcard.h>
49
#include <sys/syscallsubr.h>
50
#include <sys/sysctl.h>
51
#include <sys/sysproto.h>
52
#include <sys/sx.h>
53
#include <sys/tty.h>
54
55
#include <net/if.h>
56
#include <net/if_var.h>
57
#include <net/if_dl.h>
58
#include <net/if_types.h>
59
60
#include <dev/evdev/input.h>
61
#include <dev/hid/hidraw.h>
62
#include <dev/usb/usb_ioctl.h>
63
64
#ifdef COMPAT_LINUX32
65
#include <machine/../linux32/linux.h>
66
#include <machine/../linux32/linux32_proto.h>
67
#else
68
#include <machine/../linux/linux.h>
69
#include <machine/../linux/linux_proto.h>
70
#endif
71
72
#include <compat/linux/linux_common.h>
73
#include <compat/linux/linux_ioctl.h>
74
#include <compat/linux/linux_mib.h>
75
#include <compat/linux/linux_socket.h>
76
#include <compat/linux/linux_time.h>
77
#include <compat/linux/linux_util.h>
78
79
#include <contrib/v4l/videodev.h>
80
#include <compat/linux/linux_videodev_compat.h>
81
82
#include <contrib/v4l/videodev2.h>
83
#include <compat/linux/linux_videodev2_compat.h>
84
85
#include <cam/scsi/scsi_sg.h>
86
87
#include <dev/nvme/nvme_linux.h>
88
89
#define DEFINE_LINUX_IOCTL_SET(shortname, SHORTNAME) \
90
static linux_ioctl_function_t linux_ioctl_ ## shortname; \
91
static struct linux_ioctl_handler shortname ## _handler = { \
92
.func = linux_ioctl_ ## shortname, \
93
.low = LINUX_IOCTL_ ## SHORTNAME ## _MIN, \
94
.high = LINUX_IOCTL_ ## SHORTNAME ## _MAX, \
95
}; \
96
DATA_SET(linux_ioctl_handler_set, shortname ## _handler)
97
98
DEFINE_LINUX_IOCTL_SET(cdrom, CDROM);
99
DEFINE_LINUX_IOCTL_SET(vfat, VFAT);
100
DEFINE_LINUX_IOCTL_SET(console, CONSOLE);
101
DEFINE_LINUX_IOCTL_SET(hdio, HDIO);
102
DEFINE_LINUX_IOCTL_SET(disk, DISK);
103
DEFINE_LINUX_IOCTL_SET(socket, SOCKET);
104
DEFINE_LINUX_IOCTL_SET(sound, SOUND);
105
DEFINE_LINUX_IOCTL_SET(termio, TERMIO);
106
DEFINE_LINUX_IOCTL_SET(private, PRIVATE);
107
DEFINE_LINUX_IOCTL_SET(drm, DRM);
108
DEFINE_LINUX_IOCTL_SET(sg, SG);
109
DEFINE_LINUX_IOCTL_SET(v4l, VIDEO);
110
DEFINE_LINUX_IOCTL_SET(v4l2, VIDEO2);
111
DEFINE_LINUX_IOCTL_SET(fbsd_usb, FBSD_LUSB);
112
DEFINE_LINUX_IOCTL_SET(evdev, EVDEV);
113
DEFINE_LINUX_IOCTL_SET(kcov, KCOV);
114
#ifndef COMPAT_LINUX32
115
DEFINE_LINUX_IOCTL_SET(nvme, NVME);
116
#endif
117
DEFINE_LINUX_IOCTL_SET(hidraw, HIDRAW);
118
119
#undef DEFINE_LINUX_IOCTL_SET
120
121
static int linux_ioctl_special(struct thread *, struct linux_ioctl_args *);
122
123
/*
124
* Keep sorted by low.
125
*/
126
static struct linux_ioctl_handler linux_ioctls[] = {
127
{ .func = linux_ioctl_termio, .low = LINUX_IOCTL_TERMIO_MIN,
128
.high = LINUX_IOCTL_TERMIO_MAX },
129
};
130
131
#ifdef __i386__
132
static TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers =
133
TAILQ_HEAD_INITIALIZER(linux_ioctl_handlers);
134
static struct sx linux_ioctl_sx;
135
SX_SYSINIT(linux_ioctl, &linux_ioctl_sx, "Linux ioctl handlers");
136
#else
137
extern TAILQ_HEAD(, linux_ioctl_handler_element) linux_ioctl_handlers;
138
extern struct sx linux_ioctl_sx;
139
#endif
140
#ifdef COMPAT_LINUX32
141
static TAILQ_HEAD(, linux_ioctl_handler_element) linux32_ioctl_handlers =
142
TAILQ_HEAD_INITIALIZER(linux32_ioctl_handlers);
143
#endif
144
145
/*
146
* hdio related ioctls for VMWare support
147
*/
148
149
struct linux_hd_geometry {
150
uint8_t heads;
151
uint8_t sectors;
152
uint16_t cylinders;
153
uint32_t start;
154
};
155
156
struct linux_hd_big_geometry {
157
uint8_t heads;
158
uint8_t sectors;
159
uint32_t cylinders;
160
uint32_t start;
161
};
162
163
static int
164
linux_ioctl_hdio(struct thread *td, struct linux_ioctl_args *args)
165
{
166
struct file *fp;
167
int error;
168
u_int sectorsize, fwcylinders, fwheads, fwsectors;
169
off_t mediasize, bytespercyl;
170
171
error = fget(td, args->fd, &cap_ioctl_rights, &fp);
172
if (error != 0)
173
return (error);
174
switch (args->cmd & 0xffff) {
175
case LINUX_HDIO_GET_GEO:
176
case LINUX_HDIO_GET_GEO_BIG:
177
error = fo_ioctl(fp, DIOCGMEDIASIZE,
178
(caddr_t)&mediasize, td->td_ucred, td);
179
if (!error)
180
error = fo_ioctl(fp, DIOCGSECTORSIZE,
181
(caddr_t)&sectorsize, td->td_ucred, td);
182
if (!error)
183
error = fo_ioctl(fp, DIOCGFWHEADS,
184
(caddr_t)&fwheads, td->td_ucred, td);
185
if (!error)
186
error = fo_ioctl(fp, DIOCGFWSECTORS,
187
(caddr_t)&fwsectors, td->td_ucred, td);
188
/*
189
* XXX: DIOCGFIRSTOFFSET is not yet implemented, so
190
* so pretend that GEOM always says 0. This is NOT VALID
191
* for slices or partitions, only the per-disk raw devices.
192
*/
193
194
fdrop(fp, td);
195
if (error)
196
return (error);
197
/*
198
* 1. Calculate the number of bytes in a cylinder,
199
* given the firmware's notion of heads and sectors
200
* per cylinder.
201
* 2. Calculate the number of cylinders, given the total
202
* size of the media.
203
* All internal calculations should have 64-bit precision.
204
*/
205
bytespercyl = (off_t) sectorsize * fwheads * fwsectors;
206
fwcylinders = mediasize / bytespercyl;
207
208
if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO) {
209
struct linux_hd_geometry hdg;
210
211
hdg.cylinders = fwcylinders;
212
hdg.heads = fwheads;
213
hdg.sectors = fwsectors;
214
hdg.start = 0;
215
error = copyout(&hdg, (void *)args->arg, sizeof(hdg));
216
} else if ((args->cmd & 0xffff) == LINUX_HDIO_GET_GEO_BIG) {
217
struct linux_hd_big_geometry hdbg;
218
219
memset(&hdbg, 0, sizeof(hdbg));
220
hdbg.cylinders = fwcylinders;
221
hdbg.heads = fwheads;
222
hdbg.sectors = fwsectors;
223
hdbg.start = 0;
224
error = copyout(&hdbg, (void *)args->arg, sizeof(hdbg));
225
}
226
return (error);
227
break;
228
default:
229
/* XXX */
230
linux_msg(td,
231
"%s fd=%d, cmd=0x%x ('%c',%d) is not implemented",
232
__func__, args->fd, args->cmd,
233
(int)(args->cmd & 0xff00) >> 8,
234
(int)(args->cmd & 0xff));
235
break;
236
}
237
fdrop(fp, td);
238
return (ENOIOCTL);
239
}
240
241
static int
242
linux_ioctl_disk(struct thread *td, struct linux_ioctl_args *args)
243
{
244
struct file *fp;
245
int error;
246
u_int sectorsize, psectorsize;
247
uint64_t blksize64;
248
off_t mediasize, stripesize;
249
250
error = fget(td, args->fd, &cap_ioctl_rights, &fp);
251
if (error != 0)
252
return (error);
253
switch (args->cmd & 0xffff) {
254
case LINUX_BLKGETSIZE:
255
error = fo_ioctl(fp, DIOCGSECTORSIZE,
256
(caddr_t)&sectorsize, td->td_ucred, td);
257
if (!error)
258
error = fo_ioctl(fp, DIOCGMEDIASIZE,
259
(caddr_t)&mediasize, td->td_ucred, td);
260
fdrop(fp, td);
261
if (error)
262
return (error);
263
sectorsize = mediasize / sectorsize;
264
/*
265
* XXX: How do we know we return the right size of integer ?
266
*/
267
return (copyout(&sectorsize, (void *)args->arg,
268
sizeof(sectorsize)));
269
break;
270
case LINUX_BLKGETSIZE64:
271
error = fo_ioctl(fp, DIOCGMEDIASIZE,
272
(caddr_t)&mediasize, td->td_ucred, td);
273
fdrop(fp, td);
274
if (error)
275
return (error);
276
blksize64 = mediasize;
277
return (copyout(&blksize64, (void *)args->arg,
278
sizeof(blksize64)));
279
case LINUX_BLKSSZGET:
280
error = fo_ioctl(fp, DIOCGSECTORSIZE,
281
(caddr_t)&sectorsize, td->td_ucred, td);
282
fdrop(fp, td);
283
if (error)
284
return (error);
285
return (copyout(&sectorsize, (void *)args->arg,
286
sizeof(sectorsize)));
287
break;
288
case LINUX_BLKPBSZGET:
289
error = fo_ioctl(fp, DIOCGSTRIPESIZE,
290
(caddr_t)&stripesize, td->td_ucred, td);
291
if (error != 0) {
292
fdrop(fp, td);
293
return (error);
294
}
295
if (stripesize > 0 && stripesize <= 4096) {
296
psectorsize = stripesize;
297
} else {
298
error = fo_ioctl(fp, DIOCGSECTORSIZE,
299
(caddr_t)&sectorsize, td->td_ucred, td);
300
if (error != 0) {
301
fdrop(fp, td);
302
return (error);
303
}
304
psectorsize = sectorsize;
305
}
306
fdrop(fp, td);
307
return (copyout(&psectorsize, (void *)args->arg,
308
sizeof(psectorsize)));
309
}
310
fdrop(fp, td);
311
return (ENOIOCTL);
312
}
313
314
/*
315
* termio related ioctls
316
*/
317
318
struct linux_termio {
319
unsigned short c_iflag;
320
unsigned short c_oflag;
321
unsigned short c_cflag;
322
unsigned short c_lflag;
323
unsigned char c_line;
324
unsigned char c_cc[LINUX_NCC];
325
};
326
327
struct linux_termios {
328
unsigned int c_iflag;
329
unsigned int c_oflag;
330
unsigned int c_cflag;
331
unsigned int c_lflag;
332
unsigned char c_line;
333
unsigned char c_cc[LINUX_NCCS];
334
};
335
336
struct linux_termios2 {
337
unsigned int c_iflag;
338
unsigned int c_oflag;
339
unsigned int c_cflag;
340
unsigned int c_lflag;
341
unsigned char c_line;
342
unsigned char c_cc[LINUX_NCCS];
343
unsigned int c_ispeed;
344
unsigned int c_ospeed;
345
};
346
347
struct linux_winsize {
348
unsigned short ws_row, ws_col;
349
unsigned short ws_xpixel, ws_ypixel;
350
};
351
352
struct speedtab {
353
int sp_speed; /* Speed. */
354
int sp_code; /* Code. */
355
};
356
357
static struct speedtab sptab[] = {
358
{ B0, LINUX_B0 }, { B50, LINUX_B50 },
359
{ B75, LINUX_B75 }, { B110, LINUX_B110 },
360
{ B134, LINUX_B134 }, { B150, LINUX_B150 },
361
{ B200, LINUX_B200 }, { B300, LINUX_B300 },
362
{ B600, LINUX_B600 }, { B1200, LINUX_B1200 },
363
{ B1800, LINUX_B1800 }, { B2400, LINUX_B2400 },
364
{ B4800, LINUX_B4800 }, { B9600, LINUX_B9600 },
365
{ B19200, LINUX_B19200 }, { B38400, LINUX_B38400 },
366
{ B57600, LINUX_B57600 }, { B115200, LINUX_B115200 },
367
{-1, -1 }
368
};
369
370
struct linux_serial_struct {
371
int type;
372
int line;
373
int port;
374
int irq;
375
int flags;
376
int xmit_fifo_size;
377
int custom_divisor;
378
int baud_base;
379
unsigned short close_delay;
380
char reserved_char[2];
381
int hub6;
382
unsigned short closing_wait;
383
unsigned short closing_wait2;
384
int reserved[4];
385
};
386
387
static int
388
linux_to_bsd_speed(int code, struct speedtab *table)
389
{
390
for ( ; table->sp_code != -1; table++)
391
if (table->sp_code == code)
392
return (table->sp_speed);
393
return (-1);
394
}
395
396
static int
397
bsd_to_linux_speed(int speed, struct speedtab *table)
398
{
399
for ( ; table->sp_speed != -1; table++)
400
if (table->sp_speed == speed)
401
return (table->sp_code);
402
return (LINUX_BOTHER);
403
}
404
405
static void
406
bsd_to_linux_termios(struct termios *bios, struct linux_termios *lios)
407
{
408
int i;
409
410
lios->c_iflag = 0;
411
if (bios->c_iflag & IGNBRK)
412
lios->c_iflag |= LINUX_IGNBRK;
413
if (bios->c_iflag & BRKINT)
414
lios->c_iflag |= LINUX_BRKINT;
415
if (bios->c_iflag & IGNPAR)
416
lios->c_iflag |= LINUX_IGNPAR;
417
if (bios->c_iflag & PARMRK)
418
lios->c_iflag |= LINUX_PARMRK;
419
if (bios->c_iflag & INPCK)
420
lios->c_iflag |= LINUX_INPCK;
421
if (bios->c_iflag & ISTRIP)
422
lios->c_iflag |= LINUX_ISTRIP;
423
if (bios->c_iflag & INLCR)
424
lios->c_iflag |= LINUX_INLCR;
425
if (bios->c_iflag & IGNCR)
426
lios->c_iflag |= LINUX_IGNCR;
427
if (bios->c_iflag & ICRNL)
428
lios->c_iflag |= LINUX_ICRNL;
429
if (bios->c_iflag & IXON)
430
lios->c_iflag |= LINUX_IXON;
431
if (bios->c_iflag & IXANY)
432
lios->c_iflag |= LINUX_IXANY;
433
if (bios->c_iflag & IXOFF)
434
lios->c_iflag |= LINUX_IXOFF;
435
if (bios->c_iflag & IMAXBEL)
436
lios->c_iflag |= LINUX_IMAXBEL;
437
if (bios->c_iflag & IUTF8)
438
lios->c_iflag |= LINUX_IUTF8;
439
440
lios->c_oflag = 0;
441
if (bios->c_oflag & OPOST)
442
lios->c_oflag |= LINUX_OPOST;
443
if (bios->c_oflag & ONLCR)
444
lios->c_oflag |= LINUX_ONLCR;
445
if (bios->c_oflag & TAB3)
446
lios->c_oflag |= LINUX_XTABS;
447
448
lios->c_cflag = bsd_to_linux_speed(bios->c_ispeed, sptab);
449
lios->c_cflag |= (bios->c_cflag & CSIZE) >> 4;
450
if (bios->c_cflag & CSTOPB)
451
lios->c_cflag |= LINUX_CSTOPB;
452
if (bios->c_cflag & CREAD)
453
lios->c_cflag |= LINUX_CREAD;
454
if (bios->c_cflag & PARENB)
455
lios->c_cflag |= LINUX_PARENB;
456
if (bios->c_cflag & PARODD)
457
lios->c_cflag |= LINUX_PARODD;
458
if (bios->c_cflag & HUPCL)
459
lios->c_cflag |= LINUX_HUPCL;
460
if (bios->c_cflag & CLOCAL)
461
lios->c_cflag |= LINUX_CLOCAL;
462
if (bios->c_cflag & CRTSCTS)
463
lios->c_cflag |= LINUX_CRTSCTS;
464
465
lios->c_lflag = 0;
466
if (bios->c_lflag & ISIG)
467
lios->c_lflag |= LINUX_ISIG;
468
if (bios->c_lflag & ICANON)
469
lios->c_lflag |= LINUX_ICANON;
470
if (bios->c_lflag & ECHO)
471
lios->c_lflag |= LINUX_ECHO;
472
if (bios->c_lflag & ECHOE)
473
lios->c_lflag |= LINUX_ECHOE;
474
if (bios->c_lflag & ECHOK)
475
lios->c_lflag |= LINUX_ECHOK;
476
if (bios->c_lflag & ECHONL)
477
lios->c_lflag |= LINUX_ECHONL;
478
if (bios->c_lflag & NOFLSH)
479
lios->c_lflag |= LINUX_NOFLSH;
480
if (bios->c_lflag & TOSTOP)
481
lios->c_lflag |= LINUX_TOSTOP;
482
if (bios->c_lflag & ECHOCTL)
483
lios->c_lflag |= LINUX_ECHOCTL;
484
if (bios->c_lflag & ECHOPRT)
485
lios->c_lflag |= LINUX_ECHOPRT;
486
if (bios->c_lflag & ECHOKE)
487
lios->c_lflag |= LINUX_ECHOKE;
488
if (bios->c_lflag & FLUSHO)
489
lios->c_lflag |= LINUX_FLUSHO;
490
if (bios->c_lflag & PENDIN)
491
lios->c_lflag |= LINUX_PENDIN;
492
if (bios->c_lflag & IEXTEN)
493
lios->c_lflag |= LINUX_IEXTEN;
494
495
for (i=0; i<LINUX_NCCS; i++)
496
lios->c_cc[i] = LINUX_POSIX_VDISABLE;
497
lios->c_cc[LINUX_VINTR] = bios->c_cc[VINTR];
498
lios->c_cc[LINUX_VQUIT] = bios->c_cc[VQUIT];
499
lios->c_cc[LINUX_VERASE] = bios->c_cc[VERASE];
500
lios->c_cc[LINUX_VKILL] = bios->c_cc[VKILL];
501
lios->c_cc[LINUX_VEOF] = bios->c_cc[VEOF];
502
lios->c_cc[LINUX_VEOL] = bios->c_cc[VEOL];
503
lios->c_cc[LINUX_VMIN] = bios->c_cc[VMIN];
504
lios->c_cc[LINUX_VTIME] = bios->c_cc[VTIME];
505
lios->c_cc[LINUX_VEOL2] = bios->c_cc[VEOL2];
506
lios->c_cc[LINUX_VSUSP] = bios->c_cc[VSUSP];
507
lios->c_cc[LINUX_VSTART] = bios->c_cc[VSTART];
508
lios->c_cc[LINUX_VSTOP] = bios->c_cc[VSTOP];
509
lios->c_cc[LINUX_VREPRINT] = bios->c_cc[VREPRINT];
510
lios->c_cc[LINUX_VDISCARD] = bios->c_cc[VDISCARD];
511
lios->c_cc[LINUX_VWERASE] = bios->c_cc[VWERASE];
512
lios->c_cc[LINUX_VLNEXT] = bios->c_cc[VLNEXT];
513
if (linux_preserve_vstatus)
514
lios->c_cc[LINUX_VSTATUS] = bios->c_cc[VSTATUS];
515
516
for (i=0; i<LINUX_NCCS; i++) {
517
if (i != LINUX_VMIN && i != LINUX_VTIME &&
518
lios->c_cc[i] == _POSIX_VDISABLE)
519
lios->c_cc[i] = LINUX_POSIX_VDISABLE;
520
}
521
lios->c_line = 0;
522
}
523
524
static void
525
bsd_to_linux_termios2(struct termios *bios, struct linux_termios2 *lios2)
526
{
527
bsd_to_linux_termios(bios, (struct linux_termios *)lios2);
528
lios2->c_ospeed = bios->c_ospeed;
529
lios2->c_ispeed = bios->c_ispeed;
530
}
531
532
static void
533
linux_to_bsd_termios(struct linux_termios *lios, struct termios *bios)
534
{
535
int i;
536
537
bios->c_iflag = 0;
538
if (lios->c_iflag & LINUX_IGNBRK)
539
bios->c_iflag |= IGNBRK;
540
if (lios->c_iflag & LINUX_BRKINT)
541
bios->c_iflag |= BRKINT;
542
if (lios->c_iflag & LINUX_IGNPAR)
543
bios->c_iflag |= IGNPAR;
544
if (lios->c_iflag & LINUX_PARMRK)
545
bios->c_iflag |= PARMRK;
546
if (lios->c_iflag & LINUX_INPCK)
547
bios->c_iflag |= INPCK;
548
if (lios->c_iflag & LINUX_ISTRIP)
549
bios->c_iflag |= ISTRIP;
550
if (lios->c_iflag & LINUX_INLCR)
551
bios->c_iflag |= INLCR;
552
if (lios->c_iflag & LINUX_IGNCR)
553
bios->c_iflag |= IGNCR;
554
if (lios->c_iflag & LINUX_ICRNL)
555
bios->c_iflag |= ICRNL;
556
if (lios->c_iflag & LINUX_IXON)
557
bios->c_iflag |= IXON;
558
if (lios->c_iflag & LINUX_IXANY)
559
bios->c_iflag |= IXANY;
560
if (lios->c_iflag & LINUX_IXOFF)
561
bios->c_iflag |= IXOFF;
562
if (lios->c_iflag & LINUX_IMAXBEL)
563
bios->c_iflag |= IMAXBEL;
564
if (lios->c_iflag & LINUX_IUTF8)
565
bios->c_iflag |= IUTF8;
566
567
bios->c_oflag = 0;
568
if (lios->c_oflag & LINUX_OPOST)
569
bios->c_oflag |= OPOST;
570
if (lios->c_oflag & LINUX_ONLCR)
571
bios->c_oflag |= ONLCR;
572
if (lios->c_oflag & LINUX_XTABS)
573
bios->c_oflag |= TAB3;
574
575
bios->c_cflag = (lios->c_cflag & LINUX_CSIZE) << 4;
576
if (lios->c_cflag & LINUX_CSTOPB)
577
bios->c_cflag |= CSTOPB;
578
if (lios->c_cflag & LINUX_CREAD)
579
bios->c_cflag |= CREAD;
580
if (lios->c_cflag & LINUX_PARENB)
581
bios->c_cflag |= PARENB;
582
if (lios->c_cflag & LINUX_PARODD)
583
bios->c_cflag |= PARODD;
584
if (lios->c_cflag & LINUX_HUPCL)
585
bios->c_cflag |= HUPCL;
586
if (lios->c_cflag & LINUX_CLOCAL)
587
bios->c_cflag |= CLOCAL;
588
if (lios->c_cflag & LINUX_CRTSCTS)
589
bios->c_cflag |= CRTSCTS;
590
591
bios->c_lflag = 0;
592
if (lios->c_lflag & LINUX_ISIG)
593
bios->c_lflag |= ISIG;
594
if (lios->c_lflag & LINUX_ICANON)
595
bios->c_lflag |= ICANON;
596
if (lios->c_lflag & LINUX_ECHO)
597
bios->c_lflag |= ECHO;
598
if (lios->c_lflag & LINUX_ECHOE)
599
bios->c_lflag |= ECHOE;
600
if (lios->c_lflag & LINUX_ECHOK)
601
bios->c_lflag |= ECHOK;
602
if (lios->c_lflag & LINUX_ECHONL)
603
bios->c_lflag |= ECHONL;
604
if (lios->c_lflag & LINUX_NOFLSH)
605
bios->c_lflag |= NOFLSH;
606
if (lios->c_lflag & LINUX_TOSTOP)
607
bios->c_lflag |= TOSTOP;
608
if (lios->c_lflag & LINUX_ECHOCTL)
609
bios->c_lflag |= ECHOCTL;
610
if (lios->c_lflag & LINUX_ECHOPRT)
611
bios->c_lflag |= ECHOPRT;
612
if (lios->c_lflag & LINUX_ECHOKE)
613
bios->c_lflag |= ECHOKE;
614
if (lios->c_lflag & LINUX_FLUSHO)
615
bios->c_lflag |= FLUSHO;
616
if (lios->c_lflag & LINUX_PENDIN)
617
bios->c_lflag |= PENDIN;
618
if (lios->c_lflag & LINUX_IEXTEN)
619
bios->c_lflag |= IEXTEN;
620
621
for (i=0; i<NCCS; i++)
622
bios->c_cc[i] = _POSIX_VDISABLE;
623
bios->c_cc[VINTR] = lios->c_cc[LINUX_VINTR];
624
bios->c_cc[VQUIT] = lios->c_cc[LINUX_VQUIT];
625
bios->c_cc[VERASE] = lios->c_cc[LINUX_VERASE];
626
bios->c_cc[VKILL] = lios->c_cc[LINUX_VKILL];
627
bios->c_cc[VEOF] = lios->c_cc[LINUX_VEOF];
628
bios->c_cc[VEOL] = lios->c_cc[LINUX_VEOL];
629
bios->c_cc[VMIN] = lios->c_cc[LINUX_VMIN];
630
bios->c_cc[VTIME] = lios->c_cc[LINUX_VTIME];
631
bios->c_cc[VEOL2] = lios->c_cc[LINUX_VEOL2];
632
bios->c_cc[VSUSP] = lios->c_cc[LINUX_VSUSP];
633
bios->c_cc[VSTART] = lios->c_cc[LINUX_VSTART];
634
bios->c_cc[VSTOP] = lios->c_cc[LINUX_VSTOP];
635
bios->c_cc[VREPRINT] = lios->c_cc[LINUX_VREPRINT];
636
bios->c_cc[VDISCARD] = lios->c_cc[LINUX_VDISCARD];
637
bios->c_cc[VWERASE] = lios->c_cc[LINUX_VWERASE];
638
bios->c_cc[VLNEXT] = lios->c_cc[LINUX_VLNEXT];
639
if (linux_preserve_vstatus)
640
bios->c_cc[VSTATUS] = lios->c_cc[LINUX_VSTATUS];
641
642
for (i=0; i<NCCS; i++) {
643
if (i != VMIN && i != VTIME &&
644
bios->c_cc[i] == LINUX_POSIX_VDISABLE)
645
bios->c_cc[i] = _POSIX_VDISABLE;
646
}
647
648
bios->c_ispeed = bios->c_ospeed =
649
linux_to_bsd_speed(lios->c_cflag & LINUX_CBAUD, sptab);
650
}
651
652
static void
653
linux_to_bsd_termios2(struct linux_termios2 *lios2, struct termios *bios)
654
{
655
linux_to_bsd_termios((struct linux_termios *)lios2, bios);
656
if ((lios2->c_cflag & LINUX_CBAUD) == LINUX_BOTHER)
657
bios->c_ospeed = lios2->c_ospeed;
658
if ((lios2->c_cflag & LINUX_CIBAUD) == LINUX_BOTHER << LINUX_IBSHIFT)
659
bios->c_ispeed = lios2->c_ispeed;
660
}
661
662
static void
663
bsd_to_linux_termio(struct termios *bios, struct linux_termio *lio)
664
{
665
struct linux_termios lios;
666
667
memset(lio, 0, sizeof(*lio));
668
bsd_to_linux_termios(bios, &lios);
669
lio->c_iflag = lios.c_iflag;
670
lio->c_oflag = lios.c_oflag;
671
lio->c_cflag = lios.c_cflag;
672
lio->c_lflag = lios.c_lflag;
673
lio->c_line = lios.c_line;
674
memcpy(lio->c_cc, lios.c_cc, LINUX_NCC);
675
}
676
677
static void
678
linux_to_bsd_termio(struct linux_termio *lio, struct termios *bios)
679
{
680
struct linux_termios lios;
681
int i;
682
683
lios.c_iflag = lio->c_iflag;
684
lios.c_oflag = lio->c_oflag;
685
lios.c_cflag = lio->c_cflag;
686
lios.c_lflag = lio->c_lflag;
687
for (i=LINUX_NCC; i<LINUX_NCCS; i++)
688
lios.c_cc[i] = LINUX_POSIX_VDISABLE;
689
memcpy(lios.c_cc, lio->c_cc, LINUX_NCC);
690
linux_to_bsd_termios(&lios, bios);
691
}
692
693
static int
694
linux_ioctl_termio(struct thread *td, struct linux_ioctl_args *args)
695
{
696
struct termios bios;
697
struct linux_termios lios;
698
struct linux_termios2 lios2;
699
struct linux_termio lio;
700
struct file *fp;
701
int error;
702
703
error = fget(td, args->fd, &cap_ioctl_rights, &fp);
704
if (error != 0)
705
return (error);
706
707
switch (args->cmd & 0xffff) {
708
case LINUX_TCGETS:
709
error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
710
td);
711
if (error)
712
break;
713
bsd_to_linux_termios(&bios, &lios);
714
error = copyout(&lios, (void *)args->arg, sizeof(lios));
715
break;
716
717
case LINUX_TCSETS:
718
error = copyin((void *)args->arg, &lios, sizeof(lios));
719
if (error)
720
break;
721
linux_to_bsd_termios(&lios, &bios);
722
error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
723
td));
724
break;
725
726
case LINUX_TCSETSW:
727
error = copyin((void *)args->arg, &lios, sizeof(lios));
728
if (error)
729
break;
730
linux_to_bsd_termios(&lios, &bios);
731
error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
732
td));
733
break;
734
735
case LINUX_TCSETSF:
736
error = copyin((void *)args->arg, &lios, sizeof(lios));
737
if (error)
738
break;
739
linux_to_bsd_termios(&lios, &bios);
740
error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
741
td));
742
break;
743
744
case LINUX_TCGETA:
745
error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
746
td);
747
if (error)
748
break;
749
bsd_to_linux_termio(&bios, &lio);
750
error = (copyout(&lio, (void *)args->arg, sizeof(lio)));
751
break;
752
753
case LINUX_TCSETA:
754
error = copyin((void *)args->arg, &lio, sizeof(lio));
755
if (error)
756
break;
757
linux_to_bsd_termio(&lio, &bios);
758
error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
759
td));
760
break;
761
762
case LINUX_TCSETAW:
763
error = copyin((void *)args->arg, &lio, sizeof(lio));
764
if (error)
765
break;
766
linux_to_bsd_termio(&lio, &bios);
767
error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
768
td));
769
break;
770
771
case LINUX_TCSETAF:
772
error = copyin((void *)args->arg, &lio, sizeof(lio));
773
if (error)
774
break;
775
linux_to_bsd_termio(&lio, &bios);
776
error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
777
td));
778
break;
779
780
case LINUX_TCSBRK:
781
if (args->arg != 0) {
782
error = (fo_ioctl(fp, TIOCDRAIN, (caddr_t)&bios, td->td_ucred,
783
td));
784
} else {
785
linux_msg(td, "ioctl TCSBRK arg 0 not implemented");
786
error = ENOIOCTL;
787
}
788
break;
789
790
case LINUX_TCXONC: {
791
switch (args->arg) {
792
case LINUX_TCOOFF:
793
args->cmd = TIOCSTOP;
794
break;
795
case LINUX_TCOON:
796
args->cmd = TIOCSTART;
797
break;
798
case LINUX_TCIOFF:
799
case LINUX_TCION: {
800
int c;
801
struct write_args wr;
802
error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios,
803
td->td_ucred, td);
804
if (error)
805
break;
806
fdrop(fp, td);
807
c = (args->arg == LINUX_TCIOFF) ? VSTOP : VSTART;
808
c = bios.c_cc[c];
809
if (c != _POSIX_VDISABLE) {
810
wr.fd = args->fd;
811
wr.buf = &c;
812
wr.nbyte = sizeof(c);
813
return (sys_write(td, &wr));
814
} else
815
return (0);
816
}
817
default:
818
fdrop(fp, td);
819
return (EINVAL);
820
}
821
args->arg = 0;
822
error = (sys_ioctl(td, (struct ioctl_args *)args));
823
break;
824
}
825
826
case LINUX_TCFLSH: {
827
int val;
828
switch (args->arg) {
829
case LINUX_TCIFLUSH:
830
val = FREAD;
831
break;
832
case LINUX_TCOFLUSH:
833
val = FWRITE;
834
break;
835
case LINUX_TCIOFLUSH:
836
val = FREAD | FWRITE;
837
break;
838
default:
839
fdrop(fp, td);
840
return (EINVAL);
841
}
842
error = (fo_ioctl(fp,TIOCFLUSH,(caddr_t)&val,td->td_ucred,td));
843
break;
844
}
845
846
case LINUX_TIOCEXCL:
847
args->cmd = TIOCEXCL;
848
error = (sys_ioctl(td, (struct ioctl_args *)args));
849
break;
850
851
case LINUX_TIOCNXCL:
852
args->cmd = TIOCNXCL;
853
error = (sys_ioctl(td, (struct ioctl_args *)args));
854
break;
855
856
case LINUX_TIOCSCTTY:
857
args->cmd = TIOCSCTTY;
858
error = (sys_ioctl(td, (struct ioctl_args *)args));
859
break;
860
861
case LINUX_TIOCGPGRP:
862
args->cmd = TIOCGPGRP;
863
error = (sys_ioctl(td, (struct ioctl_args *)args));
864
break;
865
866
case LINUX_TIOCSPGRP:
867
args->cmd = TIOCSPGRP;
868
error = (sys_ioctl(td, (struct ioctl_args *)args));
869
break;
870
871
/* LINUX_TIOCOUTQ */
872
/* LINUX_TIOCSTI */
873
874
case LINUX_TIOCGWINSZ:
875
args->cmd = TIOCGWINSZ;
876
error = (sys_ioctl(td, (struct ioctl_args *)args));
877
break;
878
879
case LINUX_TIOCSWINSZ:
880
args->cmd = TIOCSWINSZ;
881
error = (sys_ioctl(td, (struct ioctl_args *)args));
882
break;
883
884
case LINUX_TIOCMGET:
885
args->cmd = TIOCMGET;
886
error = (sys_ioctl(td, (struct ioctl_args *)args));
887
break;
888
889
case LINUX_TIOCMBIS:
890
args->cmd = TIOCMBIS;
891
error = (sys_ioctl(td, (struct ioctl_args *)args));
892
break;
893
894
case LINUX_TIOCMBIC:
895
args->cmd = TIOCMBIC;
896
error = (sys_ioctl(td, (struct ioctl_args *)args));
897
break;
898
899
case LINUX_TIOCMSET:
900
args->cmd = TIOCMSET;
901
error = (sys_ioctl(td, (struct ioctl_args *)args));
902
break;
903
904
/* TIOCGSOFTCAR */
905
/* TIOCSSOFTCAR */
906
907
case LINUX_FIONREAD: /* LINUX_TIOCINQ */
908
args->cmd = FIONREAD;
909
error = (sys_ioctl(td, (struct ioctl_args *)args));
910
break;
911
912
/* LINUX_TIOCLINUX */
913
914
case LINUX_TIOCCONS:
915
args->cmd = TIOCCONS;
916
error = (sys_ioctl(td, (struct ioctl_args *)args));
917
break;
918
919
case LINUX_TIOCGSERIAL: {
920
struct linux_serial_struct lss;
921
922
bzero(&lss, sizeof(lss));
923
lss.type = LINUX_PORT_16550A;
924
lss.flags = 0;
925
lss.close_delay = 0;
926
error = copyout(&lss, (void *)args->arg, sizeof(lss));
927
break;
928
}
929
930
case LINUX_TIOCSSERIAL: {
931
struct linux_serial_struct lss;
932
error = copyin((void *)args->arg, &lss, sizeof(lss));
933
if (error)
934
break;
935
/* XXX - It really helps to have an implementation that
936
* does nothing. NOT!
937
*/
938
error = 0;
939
break;
940
}
941
942
case LINUX_TIOCPKT:
943
args->cmd = TIOCPKT;
944
error = (sys_ioctl(td, (struct ioctl_args *)args));
945
break;
946
947
case LINUX_FIONBIO:
948
args->cmd = FIONBIO;
949
error = (sys_ioctl(td, (struct ioctl_args *)args));
950
break;
951
952
case LINUX_TIOCNOTTY:
953
args->cmd = TIOCNOTTY;
954
error = (sys_ioctl(td, (struct ioctl_args *)args));
955
break;
956
957
case LINUX_TIOCSETD: {
958
int line;
959
switch (args->arg) {
960
case LINUX_N_TTY:
961
line = TTYDISC;
962
break;
963
case LINUX_N_SLIP:
964
line = SLIPDISC;
965
break;
966
case LINUX_N_PPP:
967
line = PPPDISC;
968
break;
969
default:
970
fdrop(fp, td);
971
return (EINVAL);
972
}
973
error = (fo_ioctl(fp, TIOCSETD, (caddr_t)&line, td->td_ucred,
974
td));
975
break;
976
}
977
978
case LINUX_TIOCGETD: {
979
int linux_line;
980
int bsd_line = TTYDISC;
981
error = fo_ioctl(fp, TIOCGETD, (caddr_t)&bsd_line,
982
td->td_ucred, td);
983
if (error)
984
break;
985
switch (bsd_line) {
986
case TTYDISC:
987
linux_line = LINUX_N_TTY;
988
break;
989
case SLIPDISC:
990
linux_line = LINUX_N_SLIP;
991
break;
992
case PPPDISC:
993
linux_line = LINUX_N_PPP;
994
break;
995
default:
996
fdrop(fp, td);
997
return (EINVAL);
998
}
999
error = (copyout(&linux_line, (void *)args->arg, sizeof(int)));
1000
break;
1001
}
1002
1003
/* LINUX_TCSBRKP */
1004
/* LINUX_TIOCTTYGSTRUCT */
1005
1006
case LINUX_FIONCLEX:
1007
args->cmd = FIONCLEX;
1008
error = (sys_ioctl(td, (struct ioctl_args *)args));
1009
break;
1010
1011
case LINUX_FIOCLEX:
1012
args->cmd = FIOCLEX;
1013
error = (sys_ioctl(td, (struct ioctl_args *)args));
1014
break;
1015
1016
case LINUX_FIOASYNC:
1017
args->cmd = FIOASYNC;
1018
error = (sys_ioctl(td, (struct ioctl_args *)args));
1019
break;
1020
1021
/* LINUX_TIOCSERCONFIG */
1022
/* LINUX_TIOCSERGWILD */
1023
/* LINUX_TIOCSERSWILD */
1024
/* LINUX_TIOCGLCKTRMIOS */
1025
/* LINUX_TIOCSLCKTRMIOS */
1026
1027
case LINUX_TIOCSBRK:
1028
args->cmd = TIOCSBRK;
1029
error = (sys_ioctl(td, (struct ioctl_args *)args));
1030
break;
1031
1032
case LINUX_TIOCCBRK:
1033
args->cmd = TIOCCBRK;
1034
error = (sys_ioctl(td, (struct ioctl_args *)args));
1035
break;
1036
1037
case LINUX_TCGETS2:
1038
error = fo_ioctl(fp, TIOCGETA, (caddr_t)&bios, td->td_ucred,
1039
td);
1040
if (error)
1041
break;
1042
bsd_to_linux_termios2(&bios, &lios2);
1043
error = copyout(&lios2, (void *)args->arg, sizeof(lios2));
1044
break;
1045
1046
case LINUX_TCSETS2:
1047
error = copyin((void *)args->arg, &lios2, sizeof(lios2));
1048
if (error)
1049
break;
1050
linux_to_bsd_termios2(&lios2, &bios);
1051
error = (fo_ioctl(fp, TIOCSETA, (caddr_t)&bios, td->td_ucred,
1052
td));
1053
break;
1054
1055
case LINUX_TCSETSW2:
1056
error = copyin((void *)args->arg, &lios2, sizeof(lios2));
1057
if (error)
1058
break;
1059
linux_to_bsd_termios2(&lios2, &bios);
1060
error = (fo_ioctl(fp, TIOCSETAW, (caddr_t)&bios, td->td_ucred,
1061
td));
1062
break;
1063
1064
case LINUX_TCSETSF2:
1065
error = copyin((void *)args->arg, &lios2, sizeof(lios2));
1066
if (error)
1067
break;
1068
linux_to_bsd_termios2(&lios2, &bios);
1069
error = (fo_ioctl(fp, TIOCSETAF, (caddr_t)&bios, td->td_ucred,
1070
td));
1071
break;
1072
1073
case LINUX_TIOCGPTN: {
1074
int nb;
1075
1076
error = fo_ioctl(fp, TIOCGPTN, (caddr_t)&nb, td->td_ucred, td);
1077
if (!error)
1078
error = copyout(&nb, (void *)args->arg,
1079
sizeof(int));
1080
break;
1081
}
1082
case LINUX_TIOCGPTPEER:
1083
linux_msg(td, "unsupported ioctl TIOCGPTPEER");
1084
error = ENOIOCTL;
1085
break;
1086
case LINUX_TIOCSPTLCK:
1087
/*
1088
* Our unlockpt() does nothing. Check that fd refers
1089
* to a pseudo-terminal master device.
1090
*/
1091
args->cmd = TIOCPTMASTER;
1092
error = (sys_ioctl(td, (struct ioctl_args *)args));
1093
break;
1094
default:
1095
error = ENOIOCTL;
1096
break;
1097
}
1098
1099
fdrop(fp, td);
1100
return (error);
1101
}
1102
1103
/*
1104
* CDROM related ioctls
1105
*/
1106
1107
struct linux_cdrom_msf
1108
{
1109
u_char cdmsf_min0;
1110
u_char cdmsf_sec0;
1111
u_char cdmsf_frame0;
1112
u_char cdmsf_min1;
1113
u_char cdmsf_sec1;
1114
u_char cdmsf_frame1;
1115
};
1116
1117
struct linux_cdrom_tochdr
1118
{
1119
u_char cdth_trk0;
1120
u_char cdth_trk1;
1121
};
1122
1123
union linux_cdrom_addr
1124
{
1125
struct {
1126
u_char minute;
1127
u_char second;
1128
u_char frame;
1129
} msf;
1130
int lba;
1131
};
1132
1133
struct linux_cdrom_tocentry
1134
{
1135
u_char cdte_track;
1136
u_char cdte_adr:4;
1137
u_char cdte_ctrl:4;
1138
u_char cdte_format;
1139
union linux_cdrom_addr cdte_addr;
1140
u_char cdte_datamode;
1141
};
1142
1143
struct linux_cdrom_subchnl
1144
{
1145
u_char cdsc_format;
1146
u_char cdsc_audiostatus;
1147
u_char cdsc_adr:4;
1148
u_char cdsc_ctrl:4;
1149
u_char cdsc_trk;
1150
u_char cdsc_ind;
1151
union linux_cdrom_addr cdsc_absaddr;
1152
union linux_cdrom_addr cdsc_reladdr;
1153
};
1154
1155
struct l_cdrom_read_audio {
1156
union linux_cdrom_addr addr;
1157
u_char addr_format;
1158
l_int nframes;
1159
u_char *buf;
1160
};
1161
1162
struct l_dvd_layer {
1163
u_char book_version:4;
1164
u_char book_type:4;
1165
u_char min_rate:4;
1166
u_char disc_size:4;
1167
u_char layer_type:4;
1168
u_char track_path:1;
1169
u_char nlayers:2;
1170
u_char track_density:4;
1171
u_char linear_density:4;
1172
u_char bca:1;
1173
uint32_t start_sector;
1174
uint32_t end_sector;
1175
uint32_t end_sector_l0;
1176
};
1177
1178
struct l_dvd_physical {
1179
u_char type;
1180
u_char layer_num;
1181
struct l_dvd_layer layer[4];
1182
};
1183
1184
struct l_dvd_copyright {
1185
u_char type;
1186
u_char layer_num;
1187
u_char cpst;
1188
u_char rmi;
1189
};
1190
1191
struct l_dvd_disckey {
1192
u_char type;
1193
l_uint agid:2;
1194
u_char value[2048];
1195
};
1196
1197
struct l_dvd_bca {
1198
u_char type;
1199
l_int len;
1200
u_char value[188];
1201
};
1202
1203
struct l_dvd_manufact {
1204
u_char type;
1205
u_char layer_num;
1206
l_int len;
1207
u_char value[2048];
1208
};
1209
1210
typedef union {
1211
u_char type;
1212
struct l_dvd_physical physical;
1213
struct l_dvd_copyright copyright;
1214
struct l_dvd_disckey disckey;
1215
struct l_dvd_bca bca;
1216
struct l_dvd_manufact manufact;
1217
} l_dvd_struct;
1218
1219
typedef u_char l_dvd_key[5];
1220
typedef u_char l_dvd_challenge[10];
1221
1222
struct l_dvd_lu_send_agid {
1223
u_char type;
1224
l_uint agid:2;
1225
};
1226
1227
struct l_dvd_host_send_challenge {
1228
u_char type;
1229
l_uint agid:2;
1230
l_dvd_challenge chal;
1231
};
1232
1233
struct l_dvd_send_key {
1234
u_char type;
1235
l_uint agid:2;
1236
l_dvd_key key;
1237
};
1238
1239
struct l_dvd_lu_send_challenge {
1240
u_char type;
1241
l_uint agid:2;
1242
l_dvd_challenge chal;
1243
};
1244
1245
struct l_dvd_lu_send_title_key {
1246
u_char type;
1247
l_uint agid:2;
1248
l_dvd_key title_key;
1249
l_int lba;
1250
l_uint cpm:1;
1251
l_uint cp_sec:1;
1252
l_uint cgms:2;
1253
};
1254
1255
struct l_dvd_lu_send_asf {
1256
u_char type;
1257
l_uint agid:2;
1258
l_uint asf:1;
1259
};
1260
1261
struct l_dvd_host_send_rpcstate {
1262
u_char type;
1263
u_char pdrc;
1264
};
1265
1266
struct l_dvd_lu_send_rpcstate {
1267
u_char type:2;
1268
u_char vra:3;
1269
u_char ucca:3;
1270
u_char region_mask;
1271
u_char rpc_scheme;
1272
};
1273
1274
typedef union {
1275
u_char type;
1276
struct l_dvd_lu_send_agid lsa;
1277
struct l_dvd_host_send_challenge hsc;
1278
struct l_dvd_send_key lsk;
1279
struct l_dvd_lu_send_challenge lsc;
1280
struct l_dvd_send_key hsk;
1281
struct l_dvd_lu_send_title_key lstk;
1282
struct l_dvd_lu_send_asf lsasf;
1283
struct l_dvd_host_send_rpcstate hrpcs;
1284
struct l_dvd_lu_send_rpcstate lrpcs;
1285
} l_dvd_authinfo;
1286
1287
static void
1288
bsd_to_linux_msf_lba(u_char af, union msf_lba *bp, union linux_cdrom_addr *lp)
1289
{
1290
if (af == CD_LBA_FORMAT)
1291
lp->lba = bp->lba;
1292
else {
1293
lp->msf.minute = bp->msf.minute;
1294
lp->msf.second = bp->msf.second;
1295
lp->msf.frame = bp->msf.frame;
1296
}
1297
}
1298
1299
static void
1300
set_linux_cdrom_addr(union linux_cdrom_addr *addr, int format, int lba)
1301
{
1302
if (format == LINUX_CDROM_MSF) {
1303
addr->msf.frame = lba % 75;
1304
lba /= 75;
1305
lba += 2;
1306
addr->msf.second = lba % 60;
1307
addr->msf.minute = lba / 60;
1308
} else
1309
addr->lba = lba;
1310
}
1311
1312
static int
1313
linux_to_bsd_dvd_struct(l_dvd_struct *lp, struct dvd_struct *bp)
1314
{
1315
bp->format = lp->type;
1316
switch (bp->format) {
1317
case DVD_STRUCT_PHYSICAL:
1318
if (bp->layer_num >= 4)
1319
return (EINVAL);
1320
bp->layer_num = lp->physical.layer_num;
1321
break;
1322
case DVD_STRUCT_COPYRIGHT:
1323
bp->layer_num = lp->copyright.layer_num;
1324
break;
1325
case DVD_STRUCT_DISCKEY:
1326
bp->agid = lp->disckey.agid;
1327
break;
1328
case DVD_STRUCT_BCA:
1329
case DVD_STRUCT_MANUFACT:
1330
break;
1331
default:
1332
return (EINVAL);
1333
}
1334
return (0);
1335
}
1336
1337
static int
1338
bsd_to_linux_dvd_struct(struct dvd_struct *bp, l_dvd_struct *lp)
1339
{
1340
switch (bp->format) {
1341
case DVD_STRUCT_PHYSICAL: {
1342
struct dvd_layer *blp = (struct dvd_layer *)bp->data;
1343
struct l_dvd_layer *llp = &lp->physical.layer[bp->layer_num];
1344
memset(llp, 0, sizeof(*llp));
1345
llp->book_version = blp->book_version;
1346
llp->book_type = blp->book_type;
1347
llp->min_rate = blp->max_rate;
1348
llp->disc_size = blp->disc_size;
1349
llp->layer_type = blp->layer_type;
1350
llp->track_path = blp->track_path;
1351
llp->nlayers = blp->nlayers;
1352
llp->track_density = blp->track_density;
1353
llp->linear_density = blp->linear_density;
1354
llp->bca = blp->bca;
1355
llp->start_sector = blp->start_sector;
1356
llp->end_sector = blp->end_sector;
1357
llp->end_sector_l0 = blp->end_sector_l0;
1358
break;
1359
}
1360
case DVD_STRUCT_COPYRIGHT:
1361
lp->copyright.cpst = bp->cpst;
1362
lp->copyright.rmi = bp->rmi;
1363
break;
1364
case DVD_STRUCT_DISCKEY:
1365
memcpy(lp->disckey.value, bp->data, sizeof(lp->disckey.value));
1366
break;
1367
case DVD_STRUCT_BCA:
1368
lp->bca.len = bp->length;
1369
memcpy(lp->bca.value, bp->data, sizeof(lp->bca.value));
1370
break;
1371
case DVD_STRUCT_MANUFACT:
1372
lp->manufact.len = bp->length;
1373
memcpy(lp->manufact.value, bp->data,
1374
sizeof(lp->manufact.value));
1375
/* lp->manufact.layer_num is unused in Linux (redhat 7.0). */
1376
break;
1377
default:
1378
return (EINVAL);
1379
}
1380
return (0);
1381
}
1382
1383
static int
1384
linux_to_bsd_dvd_authinfo(l_dvd_authinfo *lp, int *bcode,
1385
struct dvd_authinfo *bp)
1386
{
1387
switch (lp->type) {
1388
case LINUX_DVD_LU_SEND_AGID:
1389
*bcode = DVDIOCREPORTKEY;
1390
bp->format = DVD_REPORT_AGID;
1391
bp->agid = lp->lsa.agid;
1392
break;
1393
case LINUX_DVD_HOST_SEND_CHALLENGE:
1394
*bcode = DVDIOCSENDKEY;
1395
bp->format = DVD_SEND_CHALLENGE;
1396
bp->agid = lp->hsc.agid;
1397
memcpy(bp->keychal, lp->hsc.chal, 10);
1398
break;
1399
case LINUX_DVD_LU_SEND_KEY1:
1400
*bcode = DVDIOCREPORTKEY;
1401
bp->format = DVD_REPORT_KEY1;
1402
bp->agid = lp->lsk.agid;
1403
break;
1404
case LINUX_DVD_LU_SEND_CHALLENGE:
1405
*bcode = DVDIOCREPORTKEY;
1406
bp->format = DVD_REPORT_CHALLENGE;
1407
bp->agid = lp->lsc.agid;
1408
break;
1409
case LINUX_DVD_HOST_SEND_KEY2:
1410
*bcode = DVDIOCSENDKEY;
1411
bp->format = DVD_SEND_KEY2;
1412
bp->agid = lp->hsk.agid;
1413
memcpy(bp->keychal, lp->hsk.key, 5);
1414
break;
1415
case LINUX_DVD_LU_SEND_TITLE_KEY:
1416
*bcode = DVDIOCREPORTKEY;
1417
bp->format = DVD_REPORT_TITLE_KEY;
1418
bp->agid = lp->lstk.agid;
1419
bp->lba = lp->lstk.lba;
1420
break;
1421
case LINUX_DVD_LU_SEND_ASF:
1422
*bcode = DVDIOCREPORTKEY;
1423
bp->format = DVD_REPORT_ASF;
1424
bp->agid = lp->lsasf.agid;
1425
break;
1426
case LINUX_DVD_INVALIDATE_AGID:
1427
*bcode = DVDIOCREPORTKEY;
1428
bp->format = DVD_INVALIDATE_AGID;
1429
bp->agid = lp->lsa.agid;
1430
break;
1431
case LINUX_DVD_LU_SEND_RPC_STATE:
1432
*bcode = DVDIOCREPORTKEY;
1433
bp->format = DVD_REPORT_RPC;
1434
break;
1435
case LINUX_DVD_HOST_SEND_RPC_STATE:
1436
*bcode = DVDIOCSENDKEY;
1437
bp->format = DVD_SEND_RPC;
1438
bp->region = lp->hrpcs.pdrc;
1439
break;
1440
default:
1441
return (EINVAL);
1442
}
1443
return (0);
1444
}
1445
1446
static int
1447
bsd_to_linux_dvd_authinfo(struct dvd_authinfo *bp, l_dvd_authinfo *lp)
1448
{
1449
switch (lp->type) {
1450
case LINUX_DVD_LU_SEND_AGID:
1451
lp->lsa.agid = bp->agid;
1452
break;
1453
case LINUX_DVD_HOST_SEND_CHALLENGE:
1454
lp->type = LINUX_DVD_LU_SEND_KEY1;
1455
break;
1456
case LINUX_DVD_LU_SEND_KEY1:
1457
memcpy(lp->lsk.key, bp->keychal, sizeof(lp->lsk.key));
1458
break;
1459
case LINUX_DVD_LU_SEND_CHALLENGE:
1460
memcpy(lp->lsc.chal, bp->keychal, sizeof(lp->lsc.chal));
1461
break;
1462
case LINUX_DVD_HOST_SEND_KEY2:
1463
lp->type = LINUX_DVD_AUTH_ESTABLISHED;
1464
break;
1465
case LINUX_DVD_LU_SEND_TITLE_KEY:
1466
memcpy(lp->lstk.title_key, bp->keychal,
1467
sizeof(lp->lstk.title_key));
1468
lp->lstk.cpm = bp->cpm;
1469
lp->lstk.cp_sec = bp->cp_sec;
1470
lp->lstk.cgms = bp->cgms;
1471
break;
1472
case LINUX_DVD_LU_SEND_ASF:
1473
lp->lsasf.asf = bp->asf;
1474
break;
1475
case LINUX_DVD_INVALIDATE_AGID:
1476
break;
1477
case LINUX_DVD_LU_SEND_RPC_STATE:
1478
lp->lrpcs.type = bp->reg_type;
1479
lp->lrpcs.vra = bp->vend_rsts;
1480
lp->lrpcs.ucca = bp->user_rsts;
1481
lp->lrpcs.region_mask = bp->region;
1482
lp->lrpcs.rpc_scheme = bp->rpc_scheme;
1483
break;
1484
case LINUX_DVD_HOST_SEND_RPC_STATE:
1485
break;
1486
default:
1487
return (EINVAL);
1488
}
1489
return (0);
1490
}
1491
1492
static int
1493
linux_ioctl_cdrom(struct thread *td, struct linux_ioctl_args *args)
1494
{
1495
struct file *fp;
1496
int error;
1497
1498
error = fget(td, args->fd, &cap_ioctl_rights, &fp);
1499
if (error != 0)
1500
return (error);
1501
switch (args->cmd & 0xffff) {
1502
case LINUX_CDROMPAUSE:
1503
args->cmd = CDIOCPAUSE;
1504
error = (sys_ioctl(td, (struct ioctl_args *)args));
1505
break;
1506
1507
case LINUX_CDROMRESUME:
1508
args->cmd = CDIOCRESUME;
1509
error = (sys_ioctl(td, (struct ioctl_args *)args));
1510
break;
1511
1512
case LINUX_CDROMPLAYMSF:
1513
args->cmd = CDIOCPLAYMSF;
1514
error = (sys_ioctl(td, (struct ioctl_args *)args));
1515
break;
1516
1517
case LINUX_CDROMPLAYTRKIND:
1518
args->cmd = CDIOCPLAYTRACKS;
1519
error = (sys_ioctl(td, (struct ioctl_args *)args));
1520
break;
1521
1522
case LINUX_CDROMREADTOCHDR: {
1523
struct ioc_toc_header th;
1524
struct linux_cdrom_tochdr lth;
1525
error = fo_ioctl(fp, CDIOREADTOCHEADER, (caddr_t)&th,
1526
td->td_ucred, td);
1527
if (!error) {
1528
lth.cdth_trk0 = th.starting_track;
1529
lth.cdth_trk1 = th.ending_track;
1530
error = copyout(&lth, (void *)args->arg, sizeof(lth));
1531
}
1532
break;
1533
}
1534
1535
case LINUX_CDROMREADTOCENTRY: {
1536
struct linux_cdrom_tocentry lte;
1537
struct ioc_read_toc_single_entry irtse;
1538
1539
error = copyin((void *)args->arg, &lte, sizeof(lte));
1540
if (error)
1541
break;
1542
irtse.address_format = lte.cdte_format;
1543
irtse.track = lte.cdte_track;
1544
error = fo_ioctl(fp, CDIOREADTOCENTRY, (caddr_t)&irtse,
1545
td->td_ucred, td);
1546
if (!error) {
1547
lte.cdte_ctrl = irtse.entry.control;
1548
lte.cdte_adr = irtse.entry.addr_type;
1549
bsd_to_linux_msf_lba(irtse.address_format,
1550
&irtse.entry.addr, &lte.cdte_addr);
1551
error = copyout(&lte, (void *)args->arg, sizeof(lte));
1552
}
1553
break;
1554
}
1555
1556
case LINUX_CDROMSTOP:
1557
args->cmd = CDIOCSTOP;
1558
error = (sys_ioctl(td, (struct ioctl_args *)args));
1559
break;
1560
1561
case LINUX_CDROMSTART:
1562
args->cmd = CDIOCSTART;
1563
error = (sys_ioctl(td, (struct ioctl_args *)args));
1564
break;
1565
1566
case LINUX_CDROMEJECT:
1567
args->cmd = CDIOCEJECT;
1568
error = (sys_ioctl(td, (struct ioctl_args *)args));
1569
break;
1570
1571
/* LINUX_CDROMVOLCTRL */
1572
1573
case LINUX_CDROMSUBCHNL: {
1574
struct linux_cdrom_subchnl sc;
1575
struct ioc_read_subchannel bsdsc;
1576
struct cd_sub_channel_info bsdinfo;
1577
1578
error = copyin((void *)args->arg, &sc, sizeof(sc));
1579
if (error)
1580
break;
1581
1582
/*
1583
* Invoke the native ioctl and bounce the returned data through
1584
* the userspace buffer. This works because the Linux structure
1585
* is the same size as our structures for the subchannel header
1586
* and position data.
1587
*/
1588
bsdsc.address_format = CD_LBA_FORMAT;
1589
bsdsc.data_format = CD_CURRENT_POSITION;
1590
bsdsc.track = 0;
1591
bsdsc.data_len = sizeof(sc);
1592
bsdsc.data = (void *)args->arg;
1593
error = fo_ioctl(fp, CDIOCREADSUBCHANNEL, (caddr_t)&bsdsc,
1594
td->td_ucred, td);
1595
if (error)
1596
break;
1597
error = copyin((void *)args->arg, &bsdinfo, sizeof(bsdinfo));
1598
if (error)
1599
break;
1600
sc.cdsc_audiostatus = bsdinfo.header.audio_status;
1601
sc.cdsc_adr = bsdinfo.what.position.addr_type;
1602
sc.cdsc_ctrl = bsdinfo.what.position.control;
1603
sc.cdsc_trk = bsdinfo.what.position.track_number;
1604
sc.cdsc_ind = bsdinfo.what.position.index_number;
1605
set_linux_cdrom_addr(&sc.cdsc_absaddr, sc.cdsc_format,
1606
bsdinfo.what.position.absaddr.lba);
1607
set_linux_cdrom_addr(&sc.cdsc_reladdr, sc.cdsc_format,
1608
bsdinfo.what.position.reladdr.lba);
1609
error = copyout(&sc, (void *)args->arg, sizeof(sc));
1610
break;
1611
}
1612
1613
/* LINUX_CDROMREADMODE2 */
1614
/* LINUX_CDROMREADMODE1 */
1615
/* LINUX_CDROMREADAUDIO */
1616
/* LINUX_CDROMEJECT_SW */
1617
/* LINUX_CDROMMULTISESSION */
1618
/* LINUX_CDROM_GET_UPC */
1619
1620
case LINUX_CDROMRESET:
1621
args->cmd = CDIOCRESET;
1622
error = (sys_ioctl(td, (struct ioctl_args *)args));
1623
break;
1624
1625
/* LINUX_CDROMVOLREAD */
1626
/* LINUX_CDROMREADRAW */
1627
/* LINUX_CDROMREADCOOKED */
1628
/* LINUX_CDROMSEEK */
1629
/* LINUX_CDROMPLAYBLK */
1630
/* LINUX_CDROMREADALL */
1631
/* LINUX_CDROMCLOSETRAY */
1632
/* LINUX_CDROMLOADFROMSLOT */
1633
/* LINUX_CDROMGETSPINDOWN */
1634
/* LINUX_CDROMSETSPINDOWN */
1635
/* LINUX_CDROM_SET_OPTIONS */
1636
/* LINUX_CDROM_CLEAR_OPTIONS */
1637
/* LINUX_CDROM_SELECT_SPEED */
1638
/* LINUX_CDROM_SELECT_DISC */
1639
/* LINUX_CDROM_MEDIA_CHANGED */
1640
/* LINUX_CDROM_DRIVE_STATUS */
1641
/* LINUX_CDROM_DISC_STATUS */
1642
/* LINUX_CDROM_CHANGER_NSLOTS */
1643
/* LINUX_CDROM_LOCKDOOR */
1644
/* LINUX_CDROM_DEBUG */
1645
/* LINUX_CDROM_GET_CAPABILITY */
1646
/* LINUX_CDROMAUDIOBUFSIZ */
1647
1648
case LINUX_DVD_READ_STRUCT: {
1649
l_dvd_struct *lds;
1650
struct dvd_struct *bds;
1651
1652
lds = malloc(sizeof(*lds), M_LINUX, M_WAITOK);
1653
bds = malloc(sizeof(*bds), M_LINUX, M_WAITOK);
1654
error = copyin((void *)args->arg, lds, sizeof(*lds));
1655
if (error)
1656
goto out;
1657
error = linux_to_bsd_dvd_struct(lds, bds);
1658
if (error)
1659
goto out;
1660
error = fo_ioctl(fp, DVDIOCREADSTRUCTURE, (caddr_t)bds,
1661
td->td_ucred, td);
1662
if (error)
1663
goto out;
1664
error = bsd_to_linux_dvd_struct(bds, lds);
1665
if (error)
1666
goto out;
1667
error = copyout(lds, (void *)args->arg, sizeof(*lds));
1668
out:
1669
free(bds, M_LINUX);
1670
free(lds, M_LINUX);
1671
break;
1672
}
1673
1674
/* LINUX_DVD_WRITE_STRUCT */
1675
1676
case LINUX_DVD_AUTH: {
1677
l_dvd_authinfo lda;
1678
struct dvd_authinfo bda;
1679
int bcode;
1680
1681
error = copyin((void *)args->arg, &lda, sizeof(lda));
1682
if (error)
1683
break;
1684
error = linux_to_bsd_dvd_authinfo(&lda, &bcode, &bda);
1685
if (error)
1686
break;
1687
error = fo_ioctl(fp, bcode, (caddr_t)&bda, td->td_ucred,
1688
td);
1689
if (error) {
1690
if (lda.type == LINUX_DVD_HOST_SEND_KEY2) {
1691
lda.type = LINUX_DVD_AUTH_FAILURE;
1692
(void)copyout(&lda, (void *)args->arg,
1693
sizeof(lda));
1694
}
1695
break;
1696
}
1697
error = bsd_to_linux_dvd_authinfo(&bda, &lda);
1698
if (error)
1699
break;
1700
error = copyout(&lda, (void *)args->arg, sizeof(lda));
1701
break;
1702
}
1703
1704
case LINUX_SCSI_GET_BUS_NUMBER:
1705
{
1706
struct sg_scsi_id id;
1707
1708
error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id,
1709
td->td_ucred, td);
1710
if (error)
1711
break;
1712
error = copyout(&id.channel, (void *)args->arg, sizeof(int));
1713
break;
1714
}
1715
1716
case LINUX_SCSI_GET_IDLUN:
1717
{
1718
struct sg_scsi_id id;
1719
struct scsi_idlun idl;
1720
1721
error = fo_ioctl(fp, SG_GET_SCSI_ID, (caddr_t)&id,
1722
td->td_ucred, td);
1723
if (error)
1724
break;
1725
idl.dev_id = (id.scsi_id & 0xff) + ((id.lun & 0xff) << 8) +
1726
((id.channel & 0xff) << 16) + ((id.host_no & 0xff) << 24);
1727
idl.host_unique_id = id.host_no;
1728
error = copyout(&idl, (void *)args->arg, sizeof(idl));
1729
break;
1730
}
1731
1732
/* LINUX_CDROM_SEND_PACKET */
1733
/* LINUX_CDROM_NEXT_WRITABLE */
1734
/* LINUX_CDROM_LAST_WRITTEN */
1735
1736
default:
1737
error = ENOIOCTL;
1738
break;
1739
}
1740
1741
fdrop(fp, td);
1742
return (error);
1743
}
1744
1745
static int
1746
linux_ioctl_vfat(struct thread *td, struct linux_ioctl_args *args)
1747
{
1748
1749
return (ENOTTY);
1750
}
1751
1752
/*
1753
* Sound related ioctls
1754
*/
1755
1756
struct linux_old_mixer_info {
1757
char id[16];
1758
char name[32];
1759
};
1760
1761
static uint32_t dirbits[4] = { IOC_VOID, IOC_IN, IOC_OUT, IOC_INOUT };
1762
1763
#define SETDIR(c) (((c) & ~IOC_DIRMASK) | dirbits[args->cmd >> 30])
1764
1765
static int
1766
linux_ioctl_sound(struct thread *td, struct linux_ioctl_args *args)
1767
{
1768
1769
switch (args->cmd & 0xffff) {
1770
case LINUX_SOUND_MIXER_WRITE_VOLUME:
1771
args->cmd = SETDIR(SOUND_MIXER_WRITE_VOLUME);
1772
return (sys_ioctl(td, (struct ioctl_args *)args));
1773
1774
case LINUX_SOUND_MIXER_WRITE_BASS:
1775
args->cmd = SETDIR(SOUND_MIXER_WRITE_BASS);
1776
return (sys_ioctl(td, (struct ioctl_args *)args));
1777
1778
case LINUX_SOUND_MIXER_WRITE_TREBLE:
1779
args->cmd = SETDIR(SOUND_MIXER_WRITE_TREBLE);
1780
return (sys_ioctl(td, (struct ioctl_args *)args));
1781
1782
case LINUX_SOUND_MIXER_WRITE_SYNTH:
1783
args->cmd = SETDIR(SOUND_MIXER_WRITE_SYNTH);
1784
return (sys_ioctl(td, (struct ioctl_args *)args));
1785
1786
case LINUX_SOUND_MIXER_WRITE_PCM:
1787
args->cmd = SETDIR(SOUND_MIXER_WRITE_PCM);
1788
return (sys_ioctl(td, (struct ioctl_args *)args));
1789
1790
case LINUX_SOUND_MIXER_WRITE_SPEAKER:
1791
args->cmd = SETDIR(SOUND_MIXER_WRITE_SPEAKER);
1792
return (sys_ioctl(td, (struct ioctl_args *)args));
1793
1794
case LINUX_SOUND_MIXER_WRITE_LINE:
1795
args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE);
1796
return (sys_ioctl(td, (struct ioctl_args *)args));
1797
1798
case LINUX_SOUND_MIXER_WRITE_MIC:
1799
args->cmd = SETDIR(SOUND_MIXER_WRITE_MIC);
1800
return (sys_ioctl(td, (struct ioctl_args *)args));
1801
1802
case LINUX_SOUND_MIXER_WRITE_CD:
1803
args->cmd = SETDIR(SOUND_MIXER_WRITE_CD);
1804
return (sys_ioctl(td, (struct ioctl_args *)args));
1805
1806
case LINUX_SOUND_MIXER_WRITE_IMIX:
1807
args->cmd = SETDIR(SOUND_MIXER_WRITE_IMIX);
1808
return (sys_ioctl(td, (struct ioctl_args *)args));
1809
1810
case LINUX_SOUND_MIXER_WRITE_ALTPCM:
1811
args->cmd = SETDIR(SOUND_MIXER_WRITE_ALTPCM);
1812
return (sys_ioctl(td, (struct ioctl_args *)args));
1813
1814
case LINUX_SOUND_MIXER_WRITE_RECLEV:
1815
args->cmd = SETDIR(SOUND_MIXER_WRITE_RECLEV);
1816
return (sys_ioctl(td, (struct ioctl_args *)args));
1817
1818
case LINUX_SOUND_MIXER_WRITE_IGAIN:
1819
args->cmd = SETDIR(SOUND_MIXER_WRITE_IGAIN);
1820
return (sys_ioctl(td, (struct ioctl_args *)args));
1821
1822
case LINUX_SOUND_MIXER_WRITE_OGAIN:
1823
args->cmd = SETDIR(SOUND_MIXER_WRITE_OGAIN);
1824
return (sys_ioctl(td, (struct ioctl_args *)args));
1825
1826
case LINUX_SOUND_MIXER_WRITE_LINE1:
1827
args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE1);
1828
return (sys_ioctl(td, (struct ioctl_args *)args));
1829
1830
case LINUX_SOUND_MIXER_WRITE_LINE2:
1831
args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE2);
1832
return (sys_ioctl(td, (struct ioctl_args *)args));
1833
1834
case LINUX_SOUND_MIXER_WRITE_LINE3:
1835
args->cmd = SETDIR(SOUND_MIXER_WRITE_LINE3);
1836
return (sys_ioctl(td, (struct ioctl_args *)args));
1837
1838
case LINUX_SOUND_MIXER_WRITE_MONITOR:
1839
args->cmd = SETDIR(SOUND_MIXER_WRITE_MONITOR);
1840
return (sys_ioctl(td, (struct ioctl_args *)args));
1841
1842
case LINUX_SOUND_MIXER_INFO: {
1843
/* Key on encoded length */
1844
switch ((args->cmd >> 16) & 0x1fff) {
1845
case 0x005c: { /* SOUND_MIXER_INFO */
1846
args->cmd = SOUND_MIXER_INFO;
1847
return (sys_ioctl(td, (struct ioctl_args *)args));
1848
}
1849
case 0x0030: { /* SOUND_OLD_MIXER_INFO */
1850
struct linux_old_mixer_info info;
1851
bzero(&info, sizeof(info));
1852
strncpy(info.id, "OSS", sizeof(info.id) - 1);
1853
strncpy(info.name, "FreeBSD OSS Mixer",
1854
sizeof(info.name) - 1);
1855
return (copyout(&info, (void *)args->arg,
1856
sizeof(info)));
1857
}
1858
default:
1859
return (ENOIOCTL);
1860
}
1861
break;
1862
}
1863
1864
case LINUX_OSS_GETVERSION: {
1865
int version = linux_get_oss_version(td);
1866
return (copyout(&version, (void *)args->arg, sizeof(int)));
1867
}
1868
1869
case LINUX_SOUND_MIXER_READ_STEREODEVS:
1870
args->cmd = SOUND_MIXER_READ_STEREODEVS;
1871
return (sys_ioctl(td, (struct ioctl_args *)args));
1872
1873
case LINUX_SOUND_MIXER_READ_CAPS:
1874
args->cmd = SOUND_MIXER_READ_CAPS;
1875
return (sys_ioctl(td, (struct ioctl_args *)args));
1876
1877
case LINUX_SOUND_MIXER_READ_RECMASK:
1878
args->cmd = SOUND_MIXER_READ_RECMASK;
1879
return (sys_ioctl(td, (struct ioctl_args *)args));
1880
1881
case LINUX_SOUND_MIXER_READ_DEVMASK:
1882
args->cmd = SOUND_MIXER_READ_DEVMASK;
1883
return (sys_ioctl(td, (struct ioctl_args *)args));
1884
1885
case LINUX_SOUND_MIXER_WRITE_RECSRC:
1886
args->cmd = SETDIR(SOUND_MIXER_WRITE_RECSRC);
1887
return (sys_ioctl(td, (struct ioctl_args *)args));
1888
1889
case LINUX_SNDCTL_DSP_RESET:
1890
args->cmd = SNDCTL_DSP_RESET;
1891
return (sys_ioctl(td, (struct ioctl_args *)args));
1892
1893
case LINUX_SNDCTL_DSP_SYNC:
1894
args->cmd = SNDCTL_DSP_SYNC;
1895
return (sys_ioctl(td, (struct ioctl_args *)args));
1896
1897
case LINUX_SNDCTL_DSP_SPEED:
1898
args->cmd = SNDCTL_DSP_SPEED;
1899
return (sys_ioctl(td, (struct ioctl_args *)args));
1900
1901
case LINUX_SNDCTL_DSP_STEREO:
1902
args->cmd = SNDCTL_DSP_STEREO;
1903
return (sys_ioctl(td, (struct ioctl_args *)args));
1904
1905
case LINUX_SNDCTL_DSP_GETBLKSIZE: /* LINUX_SNDCTL_DSP_SETBLKSIZE */
1906
args->cmd = SNDCTL_DSP_GETBLKSIZE;
1907
return (sys_ioctl(td, (struct ioctl_args *)args));
1908
1909
case LINUX_SNDCTL_DSP_SETFMT:
1910
args->cmd = SNDCTL_DSP_SETFMT;
1911
return (sys_ioctl(td, (struct ioctl_args *)args));
1912
1913
case LINUX_SOUND_PCM_WRITE_CHANNELS:
1914
args->cmd = SOUND_PCM_WRITE_CHANNELS;
1915
return (sys_ioctl(td, (struct ioctl_args *)args));
1916
1917
case LINUX_SOUND_PCM_WRITE_FILTER:
1918
args->cmd = SOUND_PCM_WRITE_FILTER;
1919
return (sys_ioctl(td, (struct ioctl_args *)args));
1920
1921
case LINUX_SNDCTL_DSP_POST:
1922
args->cmd = SNDCTL_DSP_POST;
1923
return (sys_ioctl(td, (struct ioctl_args *)args));
1924
1925
case LINUX_SNDCTL_DSP_SUBDIVIDE:
1926
args->cmd = SNDCTL_DSP_SUBDIVIDE;
1927
return (sys_ioctl(td, (struct ioctl_args *)args));
1928
1929
case LINUX_SNDCTL_DSP_SETFRAGMENT:
1930
args->cmd = SNDCTL_DSP_SETFRAGMENT;
1931
return (sys_ioctl(td, (struct ioctl_args *)args));
1932
1933
case LINUX_SNDCTL_DSP_GETFMTS:
1934
args->cmd = SNDCTL_DSP_GETFMTS;
1935
return (sys_ioctl(td, (struct ioctl_args *)args));
1936
1937
case LINUX_SNDCTL_DSP_GETOSPACE:
1938
args->cmd = SNDCTL_DSP_GETOSPACE;
1939
return (sys_ioctl(td, (struct ioctl_args *)args));
1940
1941
case LINUX_SNDCTL_DSP_GETISPACE:
1942
args->cmd = SNDCTL_DSP_GETISPACE;
1943
return (sys_ioctl(td, (struct ioctl_args *)args));
1944
1945
case LINUX_SNDCTL_DSP_NONBLOCK:
1946
args->cmd = SNDCTL_DSP_NONBLOCK;
1947
return (sys_ioctl(td, (struct ioctl_args *)args));
1948
1949
case LINUX_SNDCTL_DSP_GETCAPS:
1950
args->cmd = SNDCTL_DSP_GETCAPS;
1951
return (sys_ioctl(td, (struct ioctl_args *)args));
1952
1953
case LINUX_SNDCTL_DSP_SETTRIGGER: /* LINUX_SNDCTL_GETTRIGGER */
1954
args->cmd = SNDCTL_DSP_SETTRIGGER;
1955
return (sys_ioctl(td, (struct ioctl_args *)args));
1956
1957
case LINUX_SNDCTL_DSP_GETIPTR:
1958
args->cmd = SNDCTL_DSP_GETIPTR;
1959
return (sys_ioctl(td, (struct ioctl_args *)args));
1960
1961
case LINUX_SNDCTL_DSP_GETOPTR:
1962
args->cmd = SNDCTL_DSP_GETOPTR;
1963
return (sys_ioctl(td, (struct ioctl_args *)args));
1964
1965
case LINUX_SNDCTL_DSP_SETDUPLEX:
1966
args->cmd = SNDCTL_DSP_SETDUPLEX;
1967
return (sys_ioctl(td, (struct ioctl_args *)args));
1968
1969
case LINUX_SNDCTL_DSP_GETODELAY:
1970
args->cmd = SNDCTL_DSP_GETODELAY;
1971
return (sys_ioctl(td, (struct ioctl_args *)args));
1972
1973
case LINUX_SNDCTL_SEQ_RESET:
1974
args->cmd = SNDCTL_SEQ_RESET;
1975
return (sys_ioctl(td, (struct ioctl_args *)args));
1976
1977
case LINUX_SNDCTL_SEQ_SYNC:
1978
args->cmd = SNDCTL_SEQ_SYNC;
1979
return (sys_ioctl(td, (struct ioctl_args *)args));
1980
1981
case LINUX_SNDCTL_SYNTH_INFO:
1982
args->cmd = SNDCTL_SYNTH_INFO;
1983
return (sys_ioctl(td, (struct ioctl_args *)args));
1984
1985
case LINUX_SNDCTL_SEQ_CTRLRATE:
1986
args->cmd = SNDCTL_SEQ_CTRLRATE;
1987
return (sys_ioctl(td, (struct ioctl_args *)args));
1988
1989
case LINUX_SNDCTL_SEQ_GETOUTCOUNT:
1990
args->cmd = SNDCTL_SEQ_GETOUTCOUNT;
1991
return (sys_ioctl(td, (struct ioctl_args *)args));
1992
1993
case LINUX_SNDCTL_SEQ_GETINCOUNT:
1994
args->cmd = SNDCTL_SEQ_GETINCOUNT;
1995
return (sys_ioctl(td, (struct ioctl_args *)args));
1996
1997
case LINUX_SNDCTL_SEQ_PERCMODE:
1998
args->cmd = SNDCTL_SEQ_PERCMODE;
1999
return (sys_ioctl(td, (struct ioctl_args *)args));
2000
2001
case LINUX_SNDCTL_FM_LOAD_INSTR:
2002
args->cmd = SNDCTL_FM_LOAD_INSTR;
2003
return (sys_ioctl(td, (struct ioctl_args *)args));
2004
2005
case LINUX_SNDCTL_SEQ_TESTMIDI:
2006
args->cmd = SNDCTL_SEQ_TESTMIDI;
2007
return (sys_ioctl(td, (struct ioctl_args *)args));
2008
2009
case LINUX_SNDCTL_SEQ_RESETSAMPLES:
2010
args->cmd = SNDCTL_SEQ_RESETSAMPLES;
2011
return (sys_ioctl(td, (struct ioctl_args *)args));
2012
2013
case LINUX_SNDCTL_SEQ_NRSYNTHS:
2014
args->cmd = SNDCTL_SEQ_NRSYNTHS;
2015
return (sys_ioctl(td, (struct ioctl_args *)args));
2016
2017
case LINUX_SNDCTL_SEQ_NRMIDIS:
2018
args->cmd = SNDCTL_SEQ_NRMIDIS;
2019
return (sys_ioctl(td, (struct ioctl_args *)args));
2020
2021
case LINUX_SNDCTL_MIDI_INFO:
2022
args->cmd = SNDCTL_MIDI_INFO;
2023
return (sys_ioctl(td, (struct ioctl_args *)args));
2024
2025
case LINUX_SNDCTL_SEQ_TRESHOLD:
2026
args->cmd = SNDCTL_SEQ_TRESHOLD;
2027
return (sys_ioctl(td, (struct ioctl_args *)args));
2028
2029
case LINUX_SNDCTL_SYNTH_MEMAVL:
2030
args->cmd = SNDCTL_SYNTH_MEMAVL;
2031
return (sys_ioctl(td, (struct ioctl_args *)args));
2032
}
2033
2034
return (ENOIOCTL);
2035
}
2036
2037
/*
2038
* Console related ioctls
2039
*/
2040
2041
static int
2042
linux_ioctl_console(struct thread *td, struct linux_ioctl_args *args)
2043
{
2044
struct file *fp;
2045
int error;
2046
2047
error = fget(td, args->fd, &cap_ioctl_rights, &fp);
2048
if (error != 0)
2049
return (error);
2050
switch (args->cmd & 0xffff) {
2051
case LINUX_KIOCSOUND:
2052
args->cmd = KIOCSOUND;
2053
error = (sys_ioctl(td, (struct ioctl_args *)args));
2054
break;
2055
2056
case LINUX_KDMKTONE:
2057
args->cmd = KDMKTONE;
2058
error = (sys_ioctl(td, (struct ioctl_args *)args));
2059
break;
2060
2061
case LINUX_KDGETLED:
2062
args->cmd = KDGETLED;
2063
error = (sys_ioctl(td, (struct ioctl_args *)args));
2064
break;
2065
2066
case LINUX_KDSETLED:
2067
args->cmd = KDSETLED;
2068
error = (sys_ioctl(td, (struct ioctl_args *)args));
2069
break;
2070
2071
case LINUX_KDSETMODE:
2072
args->cmd = KDSETMODE;
2073
error = (sys_ioctl(td, (struct ioctl_args *)args));
2074
break;
2075
2076
case LINUX_KDGETMODE:
2077
args->cmd = KDGETMODE;
2078
error = (sys_ioctl(td, (struct ioctl_args *)args));
2079
break;
2080
2081
case LINUX_KDGKBMODE:
2082
args->cmd = KDGKBMODE;
2083
error = (sys_ioctl(td, (struct ioctl_args *)args));
2084
break;
2085
2086
case LINUX_KDSKBMODE: {
2087
int kbdmode;
2088
switch (args->arg) {
2089
case LINUX_KBD_RAW:
2090
kbdmode = K_RAW;
2091
break;
2092
case LINUX_KBD_XLATE:
2093
kbdmode = K_XLATE;
2094
break;
2095
case LINUX_KBD_MEDIUMRAW:
2096
kbdmode = K_RAW;
2097
break;
2098
default:
2099
fdrop(fp, td);
2100
return (EINVAL);
2101
}
2102
error = (fo_ioctl(fp, KDSKBMODE, (caddr_t)&kbdmode,
2103
td->td_ucred, td));
2104
break;
2105
}
2106
2107
case LINUX_VT_OPENQRY:
2108
args->cmd = VT_OPENQRY;
2109
error = (sys_ioctl(td, (struct ioctl_args *)args));
2110
break;
2111
2112
case LINUX_VT_GETMODE:
2113
args->cmd = VT_GETMODE;
2114
error = (sys_ioctl(td, (struct ioctl_args *)args));
2115
break;
2116
2117
case LINUX_VT_SETMODE: {
2118
struct vt_mode mode;
2119
if ((error = copyin((void *)args->arg, &mode, sizeof(mode))))
2120
break;
2121
if (LINUX_SIG_VALID(mode.relsig))
2122
mode.relsig = linux_to_bsd_signal(mode.relsig);
2123
else
2124
mode.relsig = 0;
2125
if (LINUX_SIG_VALID(mode.acqsig))
2126
mode.acqsig = linux_to_bsd_signal(mode.acqsig);
2127
else
2128
mode.acqsig = 0;
2129
/* XXX. Linux ignores frsig and set it to 0. */
2130
mode.frsig = 0;
2131
if ((error = copyout(&mode, (void *)args->arg, sizeof(mode))))
2132
break;
2133
args->cmd = VT_SETMODE;
2134
error = (sys_ioctl(td, (struct ioctl_args *)args));
2135
break;
2136
}
2137
2138
case LINUX_VT_GETSTATE:
2139
args->cmd = VT_GETACTIVE;
2140
error = (sys_ioctl(td, (struct ioctl_args *)args));
2141
break;
2142
2143
case LINUX_VT_RELDISP:
2144
args->cmd = VT_RELDISP;
2145
error = (sys_ioctl(td, (struct ioctl_args *)args));
2146
break;
2147
2148
case LINUX_VT_ACTIVATE:
2149
args->cmd = VT_ACTIVATE;
2150
error = (sys_ioctl(td, (struct ioctl_args *)args));
2151
break;
2152
2153
case LINUX_VT_WAITACTIVE:
2154
args->cmd = VT_WAITACTIVE;
2155
error = (sys_ioctl(td, (struct ioctl_args *)args));
2156
break;
2157
2158
default:
2159
error = ENOIOCTL;
2160
break;
2161
}
2162
2163
fdrop(fp, td);
2164
return (error);
2165
}
2166
2167
/*
2168
* Implement the SIOCGIFNAME ioctl
2169
*/
2170
2171
static int
2172
linux_ioctl_ifname(struct thread *td, struct l_ifreq *uifr)
2173
{
2174
struct l_ifreq ifr;
2175
int error, ret;
2176
2177
error = copyin(uifr, &ifr, sizeof(ifr));
2178
if (error != 0)
2179
return (error);
2180
ret = ifname_bsd_to_linux_idx(ifr.ifr_index, ifr.ifr_name,
2181
LINUX_IFNAMSIZ);
2182
if (ret > 0)
2183
return (copyout(&ifr, uifr, sizeof(ifr)));
2184
else
2185
return (ENODEV);
2186
}
2187
2188
/*
2189
* Implement the SIOCGIFCONF ioctl
2190
*/
2191
static u_int
2192
linux_ifconf_ifaddr_cb(void *arg, struct ifaddr *ifa, u_int count)
2193
{
2194
#ifdef COMPAT_LINUX32
2195
struct l_ifconf *ifc;
2196
#else
2197
struct ifconf *ifc;
2198
#endif
2199
2200
ifc = arg;
2201
ifc->ifc_len += sizeof(struct l_ifreq);
2202
return (1);
2203
}
2204
2205
static int
2206
linux_ifconf_ifnet_cb(if_t ifp, void *arg)
2207
{
2208
2209
if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb, arg);
2210
return (0);
2211
}
2212
2213
struct linux_ifconfig_ifaddr_cb2_s {
2214
struct l_ifreq ifr;
2215
struct sbuf *sb;
2216
size_t max_len;
2217
size_t valid_len;
2218
};
2219
2220
static u_int
2221
linux_ifconf_ifaddr_cb2(void *arg, struct ifaddr *ifa, u_int len)
2222
{
2223
struct linux_ifconfig_ifaddr_cb2_s *cbs = arg;
2224
struct sockaddr *sa = ifa->ifa_addr;
2225
2226
cbs->ifr.ifr_addr.sa_family = LINUX_AF_INET;
2227
memcpy(cbs->ifr.ifr_addr.sa_data, sa->sa_data,
2228
sizeof(cbs->ifr.ifr_addr.sa_data));
2229
sbuf_bcat(cbs->sb, &cbs->ifr, sizeof(cbs->ifr));
2230
cbs->max_len += sizeof(cbs->ifr);
2231
2232
if (sbuf_error(cbs->sb) == 0)
2233
cbs->valid_len = sbuf_len(cbs->sb);
2234
return (1);
2235
}
2236
2237
static int
2238
linux_ifconf_ifnet_cb2(if_t ifp, void *arg)
2239
{
2240
struct linux_ifconfig_ifaddr_cb2_s *cbs = arg;
2241
2242
bzero(&cbs->ifr, sizeof(cbs->ifr));
2243
ifname_bsd_to_linux_ifp(ifp, cbs->ifr.ifr_name,
2244
sizeof(cbs->ifr.ifr_name));
2245
2246
/* Walk the address list */
2247
if_foreach_addr_type(ifp, AF_INET, linux_ifconf_ifaddr_cb2, cbs);
2248
return (0);
2249
}
2250
2251
static int
2252
linux_ifconf(struct thread *td, struct ifconf *uifc)
2253
{
2254
struct linux_ifconfig_ifaddr_cb2_s cbs;
2255
struct epoch_tracker et;
2256
#ifdef COMPAT_LINUX32
2257
struct l_ifconf ifc;
2258
#else
2259
struct ifconf ifc;
2260
#endif
2261
struct sbuf *sb;
2262
int error, full;
2263
2264
error = copyin(uifc, &ifc, sizeof(ifc));
2265
if (error != 0)
2266
return (error);
2267
2268
/* handle the 'request buffer size' case */
2269
if (PTRIN(ifc.ifc_buf) == NULL) {
2270
ifc.ifc_len = 0;
2271
NET_EPOCH_ENTER(et);
2272
if_foreach(linux_ifconf_ifnet_cb, &ifc);
2273
NET_EPOCH_EXIT(et);
2274
return (copyout(&ifc, uifc, sizeof(ifc)));
2275
}
2276
if (ifc.ifc_len <= 0)
2277
return (EINVAL);
2278
2279
full = 0;
2280
cbs.max_len = maxphys - 1;
2281
2282
again:
2283
if (ifc.ifc_len <= cbs.max_len) {
2284
cbs.max_len = ifc.ifc_len;
2285
full = 1;
2286
}
2287
cbs.sb = sb = sbuf_new(NULL, NULL, cbs.max_len + 1, SBUF_FIXEDLEN);
2288
cbs.max_len = 0;
2289
cbs.valid_len = 0;
2290
2291
/* Return all AF_INET addresses of all interfaces */
2292
NET_EPOCH_ENTER(et);
2293
if_foreach(linux_ifconf_ifnet_cb2, &cbs);
2294
NET_EPOCH_EXIT(et);
2295
2296
if (cbs.valid_len != cbs.max_len && !full) {
2297
sbuf_delete(sb);
2298
goto again;
2299
}
2300
2301
ifc.ifc_len = cbs.valid_len;
2302
sbuf_finish(sb);
2303
error = copyout(sbuf_data(sb), PTRIN(ifc.ifc_buf), ifc.ifc_len);
2304
if (error == 0)
2305
error = copyout(&ifc, uifc, sizeof(ifc));
2306
sbuf_delete(sb);
2307
2308
return (error);
2309
}
2310
2311
static int
2312
linux_ioctl_socket_ifreq(struct thread *td, int fd, u_int cmd,
2313
struct l_ifreq *uifr)
2314
{
2315
struct l_ifreq lifr;
2316
struct ifreq bifr;
2317
size_t ifrusiz;
2318
int error, temp_flags;
2319
2320
switch (cmd) {
2321
case LINUX_SIOCGIFINDEX:
2322
cmd = SIOCGIFINDEX;
2323
break;
2324
case LINUX_SIOCGIFFLAGS:
2325
cmd = SIOCGIFFLAGS;
2326
break;
2327
case LINUX_SIOCGIFADDR:
2328
cmd = SIOCGIFADDR;
2329
break;
2330
case LINUX_SIOCSIFADDR:
2331
cmd = SIOCSIFADDR;
2332
break;
2333
case LINUX_SIOCGIFDSTADDR:
2334
cmd = SIOCGIFDSTADDR;
2335
break;
2336
case LINUX_SIOCGIFBRDADDR:
2337
cmd = SIOCGIFBRDADDR;
2338
break;
2339
case LINUX_SIOCGIFNETMASK:
2340
cmd = SIOCGIFNETMASK;
2341
break;
2342
case LINUX_SIOCSIFNETMASK:
2343
cmd = SIOCSIFNETMASK;
2344
break;
2345
case LINUX_SIOCGIFMTU:
2346
cmd = SIOCGIFMTU;
2347
break;
2348
case LINUX_SIOCSIFMTU:
2349
cmd = SIOCSIFMTU;
2350
break;
2351
case LINUX_SIOCGIFHWADDR:
2352
cmd = SIOCGHWADDR;
2353
break;
2354
case LINUX_SIOCGIFMETRIC:
2355
cmd = SIOCGIFMETRIC;
2356
break;
2357
case LINUX_SIOCSIFMETRIC:
2358
cmd = SIOCSIFMETRIC;
2359
break;
2360
/*
2361
* XXX This is slightly bogus, but these ioctls are currently
2362
* XXX only used by the aironet (if_an) network driver.
2363
*/
2364
case LINUX_SIOCDEVPRIVATE:
2365
cmd = SIOCGPRIVATE_0;
2366
break;
2367
case LINUX_SIOCDEVPRIVATE+1:
2368
cmd = SIOCGPRIVATE_1;
2369
break;
2370
default:
2371
LINUX_RATELIMIT_MSG_OPT2(
2372
"ioctl_socket_ifreq fd=%d, cmd=0x%x is not implemented",
2373
fd, cmd);
2374
return (ENOIOCTL);
2375
}
2376
2377
error = copyin(uifr, &lifr, sizeof(lifr));
2378
if (error != 0)
2379
return (error);
2380
bzero(&bifr, sizeof(bifr));
2381
2382
/*
2383
* The size of Linux enum ifr_ifru is bigger than
2384
* the FreeBSD size due to the struct ifmap.
2385
*/
2386
ifrusiz = (sizeof(lifr) > sizeof(bifr) ? sizeof(bifr) :
2387
sizeof(lifr)) - offsetof(struct l_ifreq, ifr_ifru);
2388
bcopy(&lifr.ifr_ifru, &bifr.ifr_ifru, ifrusiz);
2389
2390
error = ifname_linux_to_bsd(td, lifr.ifr_name, bifr.ifr_name);
2391
if (error != 0)
2392
return (error);
2393
2394
/* Translate in values. */
2395
switch (cmd) {
2396
case SIOCGIFINDEX:
2397
bifr.ifr_index = lifr.ifr_index;
2398
break;
2399
case SIOCSIFADDR:
2400
case SIOCSIFNETMASK:
2401
bifr.ifr_addr.sa_len = sizeof(struct sockaddr);
2402
bifr.ifr_addr.sa_family =
2403
linux_to_bsd_domain(lifr.ifr_addr.sa_family);
2404
break;
2405
default:
2406
break;
2407
}
2408
2409
error = kern_ioctl(td, fd, cmd, (caddr_t)&bifr);
2410
if (error != 0)
2411
return (error);
2412
bzero(&lifr.ifr_ifru, sizeof(lifr.ifr_ifru));
2413
2414
/* Translate out values. */
2415
switch (cmd) {
2416
case SIOCGIFINDEX:
2417
lifr.ifr_index = bifr.ifr_index;
2418
break;
2419
case SIOCGIFFLAGS:
2420
temp_flags = bifr.ifr_flags | (bifr.ifr_flagshigh << 16);
2421
lifr.ifr_flags = bsd_to_linux_ifflags(temp_flags);
2422
break;
2423
case SIOCGIFADDR:
2424
case SIOCSIFADDR:
2425
case SIOCGIFDSTADDR:
2426
case SIOCGIFBRDADDR:
2427
case SIOCGIFNETMASK:
2428
bcopy(&bifr.ifr_addr, &lifr.ifr_addr, sizeof(bifr.ifr_addr));
2429
lifr.ifr_addr.sa_family =
2430
bsd_to_linux_domain(bifr.ifr_addr.sa_family);
2431
break;
2432
case SIOCGHWADDR:
2433
bcopy(&bifr.ifr_addr, &lifr.ifr_hwaddr, sizeof(bifr.ifr_addr));
2434
lifr.ifr_hwaddr.sa_family = LINUX_ARPHRD_ETHER;
2435
break;
2436
default:
2437
bcopy(&bifr.ifr_ifru, &lifr.ifr_ifru, ifrusiz);
2438
break;
2439
}
2440
2441
return (copyout(&lifr, uifr, sizeof(lifr)));
2442
}
2443
2444
/*
2445
* Socket related ioctls
2446
*/
2447
2448
static int
2449
linux_ioctl_socket(struct thread *td, struct linux_ioctl_args *args)
2450
{
2451
struct file *fp;
2452
int error, type;
2453
2454
error = fget(td, args->fd, &cap_ioctl_rights, &fp);
2455
if (error != 0)
2456
return (error);
2457
type = fp->f_type;
2458
fdrop(fp, td);
2459
2460
CURVNET_SET(TD_TO_VNET(td));
2461
2462
if (type != DTYPE_SOCKET) {
2463
/* not a socket - probably a tap / vmnet device */
2464
switch (args->cmd) {
2465
case LINUX_SIOCGIFADDR:
2466
case LINUX_SIOCSIFADDR:
2467
case LINUX_SIOCGIFFLAGS:
2468
error = linux_ioctl_special(td, args);
2469
break;
2470
default:
2471
error = ENOIOCTL;
2472
break;
2473
}
2474
CURVNET_RESTORE();
2475
return (error);
2476
}
2477
2478
switch (args->cmd) {
2479
case LINUX_FIOSETOWN:
2480
args->cmd = FIOSETOWN;
2481
error = sys_ioctl(td, (struct ioctl_args *)args);
2482
break;
2483
2484
case LINUX_SIOCSPGRP:
2485
args->cmd = SIOCSPGRP;
2486
error = sys_ioctl(td, (struct ioctl_args *)args);
2487
break;
2488
2489
case LINUX_FIOGETOWN:
2490
args->cmd = FIOGETOWN;
2491
error = sys_ioctl(td, (struct ioctl_args *)args);
2492
break;
2493
2494
case LINUX_SIOCGPGRP:
2495
args->cmd = SIOCGPGRP;
2496
error = sys_ioctl(td, (struct ioctl_args *)args);
2497
break;
2498
2499
case LINUX_SIOCATMARK:
2500
args->cmd = SIOCATMARK;
2501
error = sys_ioctl(td, (struct ioctl_args *)args);
2502
break;
2503
2504
/* LINUX_SIOCGSTAMP */
2505
2506
case LINUX_SIOCGIFNAME:
2507
error = linux_ioctl_ifname(td, (struct l_ifreq *)args->arg);
2508
break;
2509
2510
case LINUX_SIOCGIFCONF:
2511
error = linux_ifconf(td, (struct ifconf *)args->arg);
2512
break;
2513
2514
case LINUX_SIOCADDMULTI:
2515
args->cmd = SIOCADDMULTI;
2516
error = sys_ioctl(td, (struct ioctl_args *)args);
2517
break;
2518
2519
case LINUX_SIOCDELMULTI:
2520
args->cmd = SIOCDELMULTI;
2521
error = sys_ioctl(td, (struct ioctl_args *)args);
2522
break;
2523
2524
case LINUX_SIOCGIFCOUNT:
2525
error = 0;
2526
break;
2527
2528
default:
2529
error = linux_ioctl_socket_ifreq(td, args->fd, args->cmd,
2530
PTRIN(args->arg));
2531
break;
2532
}
2533
2534
CURVNET_RESTORE();
2535
return (error);
2536
}
2537
2538
/*
2539
* Device private ioctl handler
2540
*/
2541
static int
2542
linux_ioctl_private(struct thread *td, struct linux_ioctl_args *args)
2543
{
2544
struct file *fp;
2545
int error, type;
2546
2547
error = fget(td, args->fd, &cap_ioctl_rights, &fp);
2548
if (error != 0)
2549
return (error);
2550
type = fp->f_type;
2551
fdrop(fp, td);
2552
if (type == DTYPE_SOCKET)
2553
return (linux_ioctl_socket(td, args));
2554
return (ENOIOCTL);
2555
}
2556
2557
/*
2558
* DRM ioctl handler (sys/dev/drm)
2559
*/
2560
static int
2561
linux_ioctl_drm(struct thread *td, struct linux_ioctl_args *args)
2562
{
2563
args->cmd = SETDIR(args->cmd);
2564
return (sys_ioctl(td, (struct ioctl_args *)args));
2565
}
2566
2567
#ifdef COMPAT_LINUX32
2568
static int
2569
linux_ioctl_sg_io(struct thread *td, struct linux_ioctl_args *args)
2570
{
2571
struct sg_io_hdr io;
2572
struct sg_io_hdr32 io32;
2573
struct file *fp;
2574
int error;
2575
2576
error = fget(td, args->fd, &cap_ioctl_rights, &fp);
2577
if (error != 0) {
2578
printf("sg_linux_ioctl: fget returned %d\n", error);
2579
return (error);
2580
}
2581
2582
if ((error = copyin((void *)args->arg, &io32, sizeof(io32))) != 0)
2583
goto out;
2584
2585
CP(io32, io, interface_id);
2586
CP(io32, io, dxfer_direction);
2587
CP(io32, io, cmd_len);
2588
CP(io32, io, mx_sb_len);
2589
CP(io32, io, iovec_count);
2590
CP(io32, io, dxfer_len);
2591
PTRIN_CP(io32, io, dxferp);
2592
PTRIN_CP(io32, io, cmdp);
2593
PTRIN_CP(io32, io, sbp);
2594
CP(io32, io, timeout);
2595
CP(io32, io, flags);
2596
CP(io32, io, pack_id);
2597
PTRIN_CP(io32, io, usr_ptr);
2598
CP(io32, io, status);
2599
CP(io32, io, masked_status);
2600
CP(io32, io, msg_status);
2601
CP(io32, io, sb_len_wr);
2602
CP(io32, io, host_status);
2603
CP(io32, io, driver_status);
2604
CP(io32, io, resid);
2605
CP(io32, io, duration);
2606
CP(io32, io, info);
2607
2608
if ((error = fo_ioctl(fp, SG_IO, (caddr_t)&io, td->td_ucred, td)) != 0)
2609
goto out;
2610
2611
CP(io, io32, interface_id);
2612
CP(io, io32, dxfer_direction);
2613
CP(io, io32, cmd_len);
2614
CP(io, io32, mx_sb_len);
2615
CP(io, io32, iovec_count);
2616
CP(io, io32, dxfer_len);
2617
PTROUT_CP(io, io32, dxferp);
2618
PTROUT_CP(io, io32, cmdp);
2619
PTROUT_CP(io, io32, sbp);
2620
CP(io, io32, timeout);
2621
CP(io, io32, flags);
2622
CP(io, io32, pack_id);
2623
PTROUT_CP(io, io32, usr_ptr);
2624
CP(io, io32, status);
2625
CP(io, io32, masked_status);
2626
CP(io, io32, msg_status);
2627
CP(io, io32, sb_len_wr);
2628
CP(io, io32, host_status);
2629
CP(io, io32, driver_status);
2630
CP(io, io32, resid);
2631
CP(io, io32, duration);
2632
CP(io, io32, info);
2633
2634
error = copyout(&io32, (void *)args->arg, sizeof(io32));
2635
2636
out:
2637
fdrop(fp, td);
2638
return (error);
2639
}
2640
#endif
2641
2642
static int
2643
linux_ioctl_sg(struct thread *td, struct linux_ioctl_args *args)
2644
{
2645
2646
switch (args->cmd) {
2647
case LINUX_SG_GET_VERSION_NUM:
2648
args->cmd = SG_GET_VERSION_NUM;
2649
break;
2650
case LINUX_SG_SET_TIMEOUT:
2651
args->cmd = SG_SET_TIMEOUT;
2652
break;
2653
case LINUX_SG_GET_TIMEOUT:
2654
args->cmd = SG_GET_TIMEOUT;
2655
break;
2656
case LINUX_SG_IO:
2657
args->cmd = SG_IO;
2658
#ifdef COMPAT_LINUX32
2659
return (linux_ioctl_sg_io(td, args));
2660
#endif
2661
break;
2662
case LINUX_SG_GET_RESERVED_SIZE:
2663
args->cmd = SG_GET_RESERVED_SIZE;
2664
break;
2665
case LINUX_SG_GET_SCSI_ID:
2666
args->cmd = SG_GET_SCSI_ID;
2667
break;
2668
case LINUX_SG_GET_SG_TABLESIZE:
2669
args->cmd = SG_GET_SG_TABLESIZE;
2670
break;
2671
default:
2672
return (ENODEV);
2673
}
2674
return (sys_ioctl(td, (struct ioctl_args *)args));
2675
}
2676
2677
/*
2678
* Video4Linux (V4L) ioctl handler
2679
*/
2680
static int
2681
linux_to_bsd_v4l_tuner(struct l_video_tuner *lvt, struct video_tuner *vt)
2682
{
2683
vt->tuner = lvt->tuner;
2684
strlcpy(vt->name, lvt->name, LINUX_VIDEO_TUNER_NAME_SIZE);
2685
vt->rangelow = lvt->rangelow; /* possible long size conversion */
2686
vt->rangehigh = lvt->rangehigh; /* possible long size conversion */
2687
vt->flags = lvt->flags;
2688
vt->mode = lvt->mode;
2689
vt->signal = lvt->signal;
2690
return (0);
2691
}
2692
2693
static int
2694
bsd_to_linux_v4l_tuner(struct video_tuner *vt, struct l_video_tuner *lvt)
2695
{
2696
lvt->tuner = vt->tuner;
2697
strlcpy(lvt->name, vt->name, LINUX_VIDEO_TUNER_NAME_SIZE);
2698
lvt->rangelow = vt->rangelow; /* possible long size conversion */
2699
lvt->rangehigh = vt->rangehigh; /* possible long size conversion */
2700
lvt->flags = vt->flags;
2701
lvt->mode = vt->mode;
2702
lvt->signal = vt->signal;
2703
return (0);
2704
}
2705
2706
#ifdef COMPAT_LINUX_V4L_CLIPLIST
2707
static int
2708
linux_to_bsd_v4l_clip(struct l_video_clip *lvc, struct video_clip *vc)
2709
{
2710
vc->x = lvc->x;
2711
vc->y = lvc->y;
2712
vc->width = lvc->width;
2713
vc->height = lvc->height;
2714
vc->next = PTRIN(lvc->next); /* possible pointer size conversion */
2715
return (0);
2716
}
2717
#endif
2718
2719
static int
2720
linux_to_bsd_v4l_window(struct l_video_window *lvw, struct video_window *vw)
2721
{
2722
vw->x = lvw->x;
2723
vw->y = lvw->y;
2724
vw->width = lvw->width;
2725
vw->height = lvw->height;
2726
vw->chromakey = lvw->chromakey;
2727
vw->flags = lvw->flags;
2728
vw->clips = PTRIN(lvw->clips); /* possible pointer size conversion */
2729
vw->clipcount = lvw->clipcount;
2730
return (0);
2731
}
2732
2733
static int
2734
bsd_to_linux_v4l_window(struct video_window *vw, struct l_video_window *lvw)
2735
{
2736
memset(lvw, 0, sizeof(*lvw));
2737
2738
lvw->x = vw->x;
2739
lvw->y = vw->y;
2740
lvw->width = vw->width;
2741
lvw->height = vw->height;
2742
lvw->chromakey = vw->chromakey;
2743
lvw->flags = vw->flags;
2744
lvw->clips = PTROUT(vw->clips); /* possible pointer size conversion */
2745
lvw->clipcount = vw->clipcount;
2746
return (0);
2747
}
2748
2749
static int
2750
linux_to_bsd_v4l_buffer(struct l_video_buffer *lvb, struct video_buffer *vb)
2751
{
2752
vb->base = PTRIN(lvb->base); /* possible pointer size conversion */
2753
vb->height = lvb->height;
2754
vb->width = lvb->width;
2755
vb->depth = lvb->depth;
2756
vb->bytesperline = lvb->bytesperline;
2757
return (0);
2758
}
2759
2760
static int
2761
bsd_to_linux_v4l_buffer(struct video_buffer *vb, struct l_video_buffer *lvb)
2762
{
2763
lvb->base = PTROUT(vb->base); /* possible pointer size conversion */
2764
lvb->height = vb->height;
2765
lvb->width = vb->width;
2766
lvb->depth = vb->depth;
2767
lvb->bytesperline = vb->bytesperline;
2768
return (0);
2769
}
2770
2771
static int
2772
linux_to_bsd_v4l_code(struct l_video_code *lvc, struct video_code *vc)
2773
{
2774
strlcpy(vc->loadwhat, lvc->loadwhat, LINUX_VIDEO_CODE_LOADWHAT_SIZE);
2775
vc->datasize = lvc->datasize;
2776
vc->data = PTRIN(lvc->data); /* possible pointer size conversion */
2777
return (0);
2778
}
2779
2780
#ifdef COMPAT_LINUX_V4L_CLIPLIST
2781
static int
2782
linux_v4l_clip_copy(void *lvc, struct video_clip **ppvc)
2783
{
2784
int error;
2785
struct video_clip vclip;
2786
struct l_video_clip l_vclip;
2787
2788
error = copyin(lvc, &l_vclip, sizeof(l_vclip));
2789
if (error) return (error);
2790
linux_to_bsd_v4l_clip(&l_vclip, &vclip);
2791
/* XXX: If there can be no concurrency: s/M_NOWAIT/M_WAITOK/ */
2792
if ((*ppvc = malloc(sizeof(**ppvc), M_LINUX, M_NOWAIT)) == NULL)
2793
return (ENOMEM); /* XXX: Linux has no ENOMEM here. */
2794
memcpy(*ppvc, &vclip, sizeof(vclip));
2795
(*ppvc)->next = NULL;
2796
return (0);
2797
}
2798
2799
static int
2800
linux_v4l_cliplist_free(struct video_window *vw)
2801
{
2802
struct video_clip **ppvc;
2803
struct video_clip **ppvc_next;
2804
2805
for (ppvc = &(vw->clips); *ppvc != NULL; ppvc = ppvc_next) {
2806
ppvc_next = &((*ppvc)->next);
2807
free(*ppvc, M_LINUX);
2808
}
2809
vw->clips = NULL;
2810
2811
return (0);
2812
}
2813
2814
static int
2815
linux_v4l_cliplist_copy(struct l_video_window *lvw, struct video_window *vw)
2816
{
2817
int error;
2818
int clipcount;
2819
void *plvc;
2820
struct video_clip **ppvc;
2821
2822
/*
2823
* XXX: The cliplist is used to pass in a list of clipping
2824
* rectangles or, if clipcount == VIDEO_CLIP_BITMAP, a
2825
* clipping bitmap. Some Linux apps, however, appear to
2826
* leave cliplist and clips uninitialized. In any case,
2827
* the cliplist is not used by pwc(4), at the time of
2828
* writing, FreeBSD's only V4L driver. When a driver
2829
* that uses the cliplist is developed, this code may
2830
* need re-examiniation.
2831
*/
2832
error = 0;
2833
clipcount = vw->clipcount;
2834
if (clipcount == VIDEO_CLIP_BITMAP) {
2835
/*
2836
* In this case, the pointer (clips) is overloaded
2837
* to be a "void *" to a bitmap, therefore there
2838
* is no struct video_clip to copy now.
2839
*/
2840
} else if (clipcount > 0 && clipcount <= 16384) {
2841
/*
2842
* Clips points to list of clip rectangles, so
2843
* copy the list.
2844
*
2845
* XXX: Upper limit of 16384 was used here to try to
2846
* avoid cases when clipcount and clips pointer
2847
* are uninitialized and therefore have high random
2848
* values, as is the case in the Linux Skype
2849
* application. The value 16384 was chosen as that
2850
* is what is used in the Linux stradis(4) MPEG
2851
* decoder driver, the only place we found an
2852
* example of cliplist use.
2853
*/
2854
plvc = PTRIN(lvw->clips);
2855
vw->clips = NULL;
2856
ppvc = &(vw->clips);
2857
while (clipcount-- > 0) {
2858
if (plvc == NULL) {
2859
error = EFAULT;
2860
break;
2861
} else {
2862
error = linux_v4l_clip_copy(plvc, ppvc);
2863
if (error) {
2864
linux_v4l_cliplist_free(vw);
2865
break;
2866
}
2867
}
2868
ppvc = &((*ppvc)->next);
2869
plvc = PTRIN(((struct l_video_clip *) plvc)->next);
2870
}
2871
} else {
2872
/*
2873
* clipcount == 0 or negative (but not VIDEO_CLIP_BITMAP)
2874
* Force cliplist to null.
2875
*/
2876
vw->clipcount = 0;
2877
vw->clips = NULL;
2878
}
2879
return (error);
2880
}
2881
#endif
2882
2883
static int
2884
linux_ioctl_v4l(struct thread *td, struct linux_ioctl_args *args)
2885
{
2886
struct file *fp;
2887
int error;
2888
struct video_tuner vtun;
2889
struct video_window vwin;
2890
struct video_buffer vbuf;
2891
struct video_code vcode;
2892
struct l_video_tuner l_vtun;
2893
struct l_video_window l_vwin;
2894
struct l_video_buffer l_vbuf;
2895
struct l_video_code l_vcode;
2896
2897
switch (args->cmd & 0xffff) {
2898
case LINUX_VIDIOCGCAP: args->cmd = VIDIOCGCAP; break;
2899
case LINUX_VIDIOCGCHAN: args->cmd = VIDIOCGCHAN; break;
2900
case LINUX_VIDIOCSCHAN: args->cmd = VIDIOCSCHAN; break;
2901
2902
case LINUX_VIDIOCGTUNER:
2903
error = fget(td, args->fd,
2904
&cap_ioctl_rights, &fp);
2905
if (error != 0)
2906
return (error);
2907
error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
2908
if (error) {
2909
fdrop(fp, td);
2910
return (error);
2911
}
2912
linux_to_bsd_v4l_tuner(&l_vtun, &vtun);
2913
error = fo_ioctl(fp, VIDIOCGTUNER, &vtun, td->td_ucred, td);
2914
if (!error) {
2915
bsd_to_linux_v4l_tuner(&vtun, &l_vtun);
2916
error = copyout(&l_vtun, (void *) args->arg,
2917
sizeof(l_vtun));
2918
}
2919
fdrop(fp, td);
2920
return (error);
2921
2922
case LINUX_VIDIOCSTUNER:
2923
error = fget(td, args->fd,
2924
&cap_ioctl_rights, &fp);
2925
if (error != 0)
2926
return (error);
2927
error = copyin((void *) args->arg, &l_vtun, sizeof(l_vtun));
2928
if (error) {
2929
fdrop(fp, td);
2930
return (error);
2931
}
2932
linux_to_bsd_v4l_tuner(&l_vtun, &vtun);
2933
error = fo_ioctl(fp, VIDIOCSTUNER, &vtun, td->td_ucred, td);
2934
fdrop(fp, td);
2935
return (error);
2936
2937
case LINUX_VIDIOCGPICT: args->cmd = VIDIOCGPICT; break;
2938
case LINUX_VIDIOCSPICT: args->cmd = VIDIOCSPICT; break;
2939
case LINUX_VIDIOCCAPTURE: args->cmd = VIDIOCCAPTURE; break;
2940
2941
case LINUX_VIDIOCGWIN:
2942
error = fget(td, args->fd,
2943
&cap_ioctl_rights, &fp);
2944
if (error != 0)
2945
return (error);
2946
error = fo_ioctl(fp, VIDIOCGWIN, &vwin, td->td_ucred, td);
2947
if (!error) {
2948
bsd_to_linux_v4l_window(&vwin, &l_vwin);
2949
error = copyout(&l_vwin, (void *) args->arg,
2950
sizeof(l_vwin));
2951
}
2952
fdrop(fp, td);
2953
return (error);
2954
2955
case LINUX_VIDIOCSWIN:
2956
error = fget(td, args->fd,
2957
&cap_ioctl_rights, &fp);
2958
if (error != 0)
2959
return (error);
2960
error = copyin((void *) args->arg, &l_vwin, sizeof(l_vwin));
2961
if (error) {
2962
fdrop(fp, td);
2963
return (error);
2964
}
2965
linux_to_bsd_v4l_window(&l_vwin, &vwin);
2966
#ifdef COMPAT_LINUX_V4L_CLIPLIST
2967
error = linux_v4l_cliplist_copy(&l_vwin, &vwin);
2968
if (error) {
2969
fdrop(fp, td);
2970
return (error);
2971
}
2972
#endif
2973
error = fo_ioctl(fp, VIDIOCSWIN, &vwin, td->td_ucred, td);
2974
fdrop(fp, td);
2975
#ifdef COMPAT_LINUX_V4L_CLIPLIST
2976
linux_v4l_cliplist_free(&vwin);
2977
#endif
2978
return (error);
2979
2980
case LINUX_VIDIOCGFBUF:
2981
error = fget(td, args->fd,
2982
&cap_ioctl_rights, &fp);
2983
if (error != 0)
2984
return (error);
2985
error = fo_ioctl(fp, VIDIOCGFBUF, &vbuf, td->td_ucred, td);
2986
if (!error) {
2987
bsd_to_linux_v4l_buffer(&vbuf, &l_vbuf);
2988
error = copyout(&l_vbuf, (void *) args->arg,
2989
sizeof(l_vbuf));
2990
}
2991
fdrop(fp, td);
2992
return (error);
2993
2994
case LINUX_VIDIOCSFBUF:
2995
error = fget(td, args->fd,
2996
&cap_ioctl_rights, &fp);
2997
if (error != 0)
2998
return (error);
2999
error = copyin((void *) args->arg, &l_vbuf, sizeof(l_vbuf));
3000
if (error) {
3001
fdrop(fp, td);
3002
return (error);
3003
}
3004
linux_to_bsd_v4l_buffer(&l_vbuf, &vbuf);
3005
error = fo_ioctl(fp, VIDIOCSFBUF, &vbuf, td->td_ucred, td);
3006
fdrop(fp, td);
3007
return (error);
3008
3009
case LINUX_VIDIOCKEY: args->cmd = VIDIOCKEY; break;
3010
case LINUX_VIDIOCGFREQ: args->cmd = VIDIOCGFREQ; break;
3011
case LINUX_VIDIOCSFREQ: args->cmd = VIDIOCSFREQ; break;
3012
case LINUX_VIDIOCGAUDIO: args->cmd = VIDIOCGAUDIO; break;
3013
case LINUX_VIDIOCSAUDIO: args->cmd = VIDIOCSAUDIO; break;
3014
case LINUX_VIDIOCSYNC: args->cmd = VIDIOCSYNC; break;
3015
case LINUX_VIDIOCMCAPTURE: args->cmd = VIDIOCMCAPTURE; break;
3016
case LINUX_VIDIOCGMBUF: args->cmd = VIDIOCGMBUF; break;
3017
case LINUX_VIDIOCGUNIT: args->cmd = VIDIOCGUNIT; break;
3018
case LINUX_VIDIOCGCAPTURE: args->cmd = VIDIOCGCAPTURE; break;
3019
case LINUX_VIDIOCSCAPTURE: args->cmd = VIDIOCSCAPTURE; break;
3020
case LINUX_VIDIOCSPLAYMODE: args->cmd = VIDIOCSPLAYMODE; break;
3021
case LINUX_VIDIOCSWRITEMODE: args->cmd = VIDIOCSWRITEMODE; break;
3022
case LINUX_VIDIOCGPLAYINFO: args->cmd = VIDIOCGPLAYINFO; break;
3023
3024
case LINUX_VIDIOCSMICROCODE:
3025
error = fget(td, args->fd,
3026
&cap_ioctl_rights, &fp);
3027
if (error != 0)
3028
return (error);
3029
error = copyin((void *) args->arg, &l_vcode, sizeof(l_vcode));
3030
if (error) {
3031
fdrop(fp, td);
3032
return (error);
3033
}
3034
linux_to_bsd_v4l_code(&l_vcode, &vcode);
3035
error = fo_ioctl(fp, VIDIOCSMICROCODE, &vcode, td->td_ucred, td);
3036
fdrop(fp, td);
3037
return (error);
3038
3039
case LINUX_VIDIOCGVBIFMT: args->cmd = VIDIOCGVBIFMT; break;
3040
case LINUX_VIDIOCSVBIFMT: args->cmd = VIDIOCSVBIFMT; break;
3041
default: return (ENOIOCTL);
3042
}
3043
3044
error = sys_ioctl(td, (struct ioctl_args *)args);
3045
return (error);
3046
}
3047
3048
/*
3049
* Special ioctl handler
3050
*/
3051
static int
3052
linux_ioctl_special(struct thread *td, struct linux_ioctl_args *args)
3053
{
3054
int error;
3055
3056
switch (args->cmd) {
3057
case LINUX_SIOCGIFADDR:
3058
args->cmd = SIOCGIFADDR;
3059
error = sys_ioctl(td, (struct ioctl_args *)args);
3060
break;
3061
case LINUX_SIOCSIFADDR:
3062
args->cmd = SIOCSIFADDR;
3063
error = sys_ioctl(td, (struct ioctl_args *)args);
3064
break;
3065
case LINUX_SIOCGIFFLAGS:
3066
args->cmd = SIOCGIFFLAGS;
3067
error = sys_ioctl(td, (struct ioctl_args *)args);
3068
break;
3069
default:
3070
error = ENOIOCTL;
3071
}
3072
3073
return (error);
3074
}
3075
3076
static int
3077
linux_to_bsd_v4l2_standard(struct l_v4l2_standard *lvstd, struct v4l2_standard *vstd)
3078
{
3079
vstd->index = lvstd->index;
3080
vstd->id = lvstd->id;
3081
CTASSERT(sizeof(vstd->name) == sizeof(lvstd->name));
3082
memcpy(vstd->name, lvstd->name, sizeof(vstd->name));
3083
vstd->frameperiod = lvstd->frameperiod;
3084
vstd->framelines = lvstd->framelines;
3085
CTASSERT(sizeof(vstd->reserved) == sizeof(lvstd->reserved));
3086
memcpy(vstd->reserved, lvstd->reserved, sizeof(vstd->reserved));
3087
return (0);
3088
}
3089
3090
static int
3091
bsd_to_linux_v4l2_standard(struct v4l2_standard *vstd, struct l_v4l2_standard *lvstd)
3092
{
3093
lvstd->index = vstd->index;
3094
lvstd->id = vstd->id;
3095
CTASSERT(sizeof(vstd->name) == sizeof(lvstd->name));
3096
memcpy(lvstd->name, vstd->name, sizeof(lvstd->name));
3097
lvstd->frameperiod = vstd->frameperiod;
3098
lvstd->framelines = vstd->framelines;
3099
CTASSERT(sizeof(vstd->reserved) == sizeof(lvstd->reserved));
3100
memcpy(lvstd->reserved, vstd->reserved, sizeof(lvstd->reserved));
3101
return (0);
3102
}
3103
3104
static int
3105
linux_to_bsd_v4l2_buffer(struct l_v4l2_buffer *lvb, struct v4l2_buffer *vb)
3106
{
3107
vb->index = lvb->index;
3108
vb->type = lvb->type;
3109
vb->bytesused = lvb->bytesused;
3110
vb->flags = lvb->flags;
3111
vb->field = lvb->field;
3112
vb->timestamp.tv_sec = lvb->timestamp.tv_sec;
3113
vb->timestamp.tv_usec = lvb->timestamp.tv_usec;
3114
memcpy(&vb->timecode, &lvb->timecode, sizeof (lvb->timecode));
3115
vb->sequence = lvb->sequence;
3116
vb->memory = lvb->memory;
3117
if (lvb->memory == V4L2_MEMORY_USERPTR)
3118
/* possible pointer size conversion */
3119
vb->m.userptr = (unsigned long)PTRIN(lvb->m.userptr);
3120
else
3121
vb->m.offset = lvb->m.offset;
3122
vb->length = lvb->length;
3123
vb->input = lvb->input;
3124
vb->reserved = lvb->reserved;
3125
return (0);
3126
}
3127
3128
static int
3129
bsd_to_linux_v4l2_buffer(struct v4l2_buffer *vb, struct l_v4l2_buffer *lvb)
3130
{
3131
lvb->index = vb->index;
3132
lvb->type = vb->type;
3133
lvb->bytesused = vb->bytesused;
3134
lvb->flags = vb->flags;
3135
lvb->field = vb->field;
3136
lvb->timestamp.tv_sec = vb->timestamp.tv_sec;
3137
lvb->timestamp.tv_usec = vb->timestamp.tv_usec;
3138
memcpy(&lvb->timecode, &vb->timecode, sizeof (vb->timecode));
3139
lvb->sequence = vb->sequence;
3140
lvb->memory = vb->memory;
3141
if (vb->memory == V4L2_MEMORY_USERPTR)
3142
/* possible pointer size conversion */
3143
lvb->m.userptr = PTROUT(vb->m.userptr);
3144
else
3145
lvb->m.offset = vb->m.offset;
3146
lvb->length = vb->length;
3147
lvb->input = vb->input;
3148
lvb->reserved = vb->reserved;
3149
return (0);
3150
}
3151
3152
static int
3153
linux_to_bsd_v4l2_format(struct l_v4l2_format *lvf, struct v4l2_format *vf)
3154
{
3155
vf->type = lvf->type;
3156
if (lvf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY
3157
#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
3158
|| lvf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
3159
#endif
3160
)
3161
/*
3162
* XXX TODO - needs 32 -> 64 bit conversion:
3163
* (unused by webcams?)
3164
*/
3165
return (EINVAL);
3166
memcpy(&vf->fmt, &lvf->fmt, sizeof(vf->fmt));
3167
return (0);
3168
}
3169
3170
static int
3171
bsd_to_linux_v4l2_format(struct v4l2_format *vf, struct l_v4l2_format *lvf)
3172
{
3173
lvf->type = vf->type;
3174
if (vf->type == V4L2_BUF_TYPE_VIDEO_OVERLAY
3175
#ifdef V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
3176
|| vf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY
3177
#endif
3178
)
3179
/*
3180
* XXX TODO - needs 32 -> 64 bit conversion:
3181
* (unused by webcams?)
3182
*/
3183
return (EINVAL);
3184
memcpy(&lvf->fmt, &vf->fmt, sizeof(vf->fmt));
3185
return (0);
3186
}
3187
static int
3188
linux_ioctl_v4l2(struct thread *td, struct linux_ioctl_args *args)
3189
{
3190
struct file *fp;
3191
int error;
3192
struct v4l2_format vformat;
3193
struct l_v4l2_format l_vformat;
3194
struct v4l2_standard vstd;
3195
struct l_v4l2_standard l_vstd;
3196
struct l_v4l2_buffer l_vbuf;
3197
struct v4l2_buffer vbuf;
3198
struct v4l2_input vinp;
3199
3200
switch (args->cmd & 0xffff) {
3201
case LINUX_VIDIOC_RESERVED:
3202
case LINUX_VIDIOC_LOG_STATUS:
3203
if ((args->cmd & IOC_DIRMASK) != LINUX_IOC_VOID)
3204
return (ENOIOCTL);
3205
args->cmd = (args->cmd & 0xffff) | IOC_VOID;
3206
break;
3207
3208
case LINUX_VIDIOC_OVERLAY:
3209
case LINUX_VIDIOC_STREAMON:
3210
case LINUX_VIDIOC_STREAMOFF:
3211
case LINUX_VIDIOC_S_STD:
3212
case LINUX_VIDIOC_S_TUNER:
3213
case LINUX_VIDIOC_S_AUDIO:
3214
case LINUX_VIDIOC_S_AUDOUT:
3215
case LINUX_VIDIOC_S_MODULATOR:
3216
case LINUX_VIDIOC_S_FREQUENCY:
3217
case LINUX_VIDIOC_S_CROP:
3218
case LINUX_VIDIOC_S_JPEGCOMP:
3219
case LINUX_VIDIOC_S_PRIORITY:
3220
case LINUX_VIDIOC_DBG_S_REGISTER:
3221
case LINUX_VIDIOC_S_HW_FREQ_SEEK:
3222
case LINUX_VIDIOC_SUBSCRIBE_EVENT:
3223
case LINUX_VIDIOC_UNSUBSCRIBE_EVENT:
3224
args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_IN;
3225
break;
3226
3227
case LINUX_VIDIOC_QUERYCAP:
3228
case LINUX_VIDIOC_G_STD:
3229
case LINUX_VIDIOC_G_AUDIO:
3230
case LINUX_VIDIOC_G_INPUT:
3231
case LINUX_VIDIOC_G_OUTPUT:
3232
case LINUX_VIDIOC_G_AUDOUT:
3233
case LINUX_VIDIOC_G_JPEGCOMP:
3234
case LINUX_VIDIOC_QUERYSTD:
3235
case LINUX_VIDIOC_G_PRIORITY:
3236
case LINUX_VIDIOC_QUERY_DV_PRESET:
3237
args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_OUT;
3238
break;
3239
3240
case LINUX_VIDIOC_ENUM_FMT:
3241
case LINUX_VIDIOC_REQBUFS:
3242
case LINUX_VIDIOC_G_PARM:
3243
case LINUX_VIDIOC_S_PARM:
3244
case LINUX_VIDIOC_G_CTRL:
3245
case LINUX_VIDIOC_S_CTRL:
3246
case LINUX_VIDIOC_G_TUNER:
3247
case LINUX_VIDIOC_QUERYCTRL:
3248
case LINUX_VIDIOC_QUERYMENU:
3249
case LINUX_VIDIOC_S_INPUT:
3250
case LINUX_VIDIOC_S_OUTPUT:
3251
case LINUX_VIDIOC_ENUMOUTPUT:
3252
case LINUX_VIDIOC_G_MODULATOR:
3253
case LINUX_VIDIOC_G_FREQUENCY:
3254
case LINUX_VIDIOC_CROPCAP:
3255
case LINUX_VIDIOC_G_CROP:
3256
case LINUX_VIDIOC_ENUMAUDIO:
3257
case LINUX_VIDIOC_ENUMAUDOUT:
3258
case LINUX_VIDIOC_G_SLICED_VBI_CAP:
3259
#ifdef VIDIOC_ENUM_FRAMESIZES
3260
case LINUX_VIDIOC_ENUM_FRAMESIZES:
3261
case LINUX_VIDIOC_ENUM_FRAMEINTERVALS:
3262
case LINUX_VIDIOC_ENCODER_CMD:
3263
case LINUX_VIDIOC_TRY_ENCODER_CMD:
3264
#endif
3265
case LINUX_VIDIOC_DBG_G_REGISTER:
3266
case LINUX_VIDIOC_DBG_G_CHIP_IDENT:
3267
case LINUX_VIDIOC_ENUM_DV_PRESETS:
3268
case LINUX_VIDIOC_S_DV_PRESET:
3269
case LINUX_VIDIOC_G_DV_PRESET:
3270
case LINUX_VIDIOC_S_DV_TIMINGS:
3271
case LINUX_VIDIOC_G_DV_TIMINGS:
3272
args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT;
3273
break;
3274
3275
case LINUX_VIDIOC_G_FMT:
3276
case LINUX_VIDIOC_S_FMT:
3277
case LINUX_VIDIOC_TRY_FMT:
3278
error = copyin((void *)args->arg, &l_vformat, sizeof(l_vformat));
3279
if (error)
3280
return (error);
3281
error = fget(td, args->fd,
3282
&cap_ioctl_rights, &fp);
3283
if (error)
3284
return (error);
3285
if (linux_to_bsd_v4l2_format(&l_vformat, &vformat) != 0)
3286
error = EINVAL;
3287
else if ((args->cmd & 0xffff) == LINUX_VIDIOC_G_FMT)
3288
error = fo_ioctl(fp, VIDIOC_G_FMT, &vformat,
3289
td->td_ucred, td);
3290
else if ((args->cmd & 0xffff) == LINUX_VIDIOC_S_FMT)
3291
error = fo_ioctl(fp, VIDIOC_S_FMT, &vformat,
3292
td->td_ucred, td);
3293
else
3294
error = fo_ioctl(fp, VIDIOC_TRY_FMT, &vformat,
3295
td->td_ucred, td);
3296
bsd_to_linux_v4l2_format(&vformat, &l_vformat);
3297
if (error == 0)
3298
error = copyout(&l_vformat, (void *)args->arg,
3299
sizeof(l_vformat));
3300
fdrop(fp, td);
3301
return (error);
3302
3303
case LINUX_VIDIOC_ENUMSTD:
3304
error = copyin((void *)args->arg, &l_vstd, sizeof(l_vstd));
3305
if (error)
3306
return (error);
3307
linux_to_bsd_v4l2_standard(&l_vstd, &vstd);
3308
error = fget(td, args->fd,
3309
&cap_ioctl_rights, &fp);
3310
if (error)
3311
return (error);
3312
error = fo_ioctl(fp, VIDIOC_ENUMSTD, (caddr_t)&vstd,
3313
td->td_ucred, td);
3314
if (error) {
3315
fdrop(fp, td);
3316
return (error);
3317
}
3318
bsd_to_linux_v4l2_standard(&vstd, &l_vstd);
3319
error = copyout(&l_vstd, (void *)args->arg, sizeof(l_vstd));
3320
fdrop(fp, td);
3321
return (error);
3322
3323
case LINUX_VIDIOC_ENUMINPUT:
3324
/*
3325
* The Linux struct l_v4l2_input differs only in size,
3326
* it has no padding at the end.
3327
*/
3328
error = copyin((void *)args->arg, &vinp,
3329
sizeof(struct l_v4l2_input));
3330
if (error != 0)
3331
return (error);
3332
error = fget(td, args->fd,
3333
&cap_ioctl_rights, &fp);
3334
if (error != 0)
3335
return (error);
3336
error = fo_ioctl(fp, VIDIOC_ENUMINPUT, (caddr_t)&vinp,
3337
td->td_ucred, td);
3338
if (error) {
3339
fdrop(fp, td);
3340
return (error);
3341
}
3342
error = copyout(&vinp, (void *)args->arg,
3343
sizeof(struct l_v4l2_input));
3344
fdrop(fp, td);
3345
return (error);
3346
3347
case LINUX_VIDIOC_QUERYBUF:
3348
case LINUX_VIDIOC_QBUF:
3349
case LINUX_VIDIOC_DQBUF:
3350
error = copyin((void *)args->arg, &l_vbuf, sizeof(l_vbuf));
3351
if (error)
3352
return (error);
3353
error = fget(td, args->fd,
3354
&cap_ioctl_rights, &fp);
3355
if (error)
3356
return (error);
3357
linux_to_bsd_v4l2_buffer(&l_vbuf, &vbuf);
3358
if ((args->cmd & 0xffff) == LINUX_VIDIOC_QUERYBUF)
3359
error = fo_ioctl(fp, VIDIOC_QUERYBUF, &vbuf,
3360
td->td_ucred, td);
3361
else if ((args->cmd & 0xffff) == LINUX_VIDIOC_QBUF)
3362
error = fo_ioctl(fp, VIDIOC_QBUF, &vbuf,
3363
td->td_ucred, td);
3364
else
3365
error = fo_ioctl(fp, VIDIOC_DQBUF, &vbuf,
3366
td->td_ucred, td);
3367
bsd_to_linux_v4l2_buffer(&vbuf, &l_vbuf);
3368
if (error == 0)
3369
error = copyout(&l_vbuf, (void *)args->arg,
3370
sizeof(l_vbuf));
3371
fdrop(fp, td);
3372
return (error);
3373
3374
/*
3375
* XXX TODO - these need 32 -> 64 bit conversion:
3376
* (are any of them needed for webcams?)
3377
*/
3378
case LINUX_VIDIOC_G_FBUF:
3379
case LINUX_VIDIOC_S_FBUF:
3380
3381
case LINUX_VIDIOC_G_EXT_CTRLS:
3382
case LINUX_VIDIOC_S_EXT_CTRLS:
3383
case LINUX_VIDIOC_TRY_EXT_CTRLS:
3384
3385
case LINUX_VIDIOC_DQEVENT:
3386
3387
default: return (ENOIOCTL);
3388
}
3389
3390
error = sys_ioctl(td, (struct ioctl_args *)args);
3391
return (error);
3392
}
3393
3394
/*
3395
* Support for emulators/linux-libusb. This port uses FBSD_LUSB* macros
3396
* instead of USB* ones. This lets us to provide correct values for cmd.
3397
* 0xffffffe0 -- 0xffffffff range seemed to be the least collision-prone.
3398
*/
3399
static int
3400
linux_ioctl_fbsd_usb(struct thread *td, struct linux_ioctl_args *args)
3401
{
3402
int error;
3403
3404
error = 0;
3405
switch (args->cmd) {
3406
case FBSD_LUSB_DEVICEENUMERATE:
3407
args->cmd = USB_DEVICEENUMERATE;
3408
break;
3409
case FBSD_LUSB_DEV_QUIRK_ADD:
3410
args->cmd = USB_DEV_QUIRK_ADD;
3411
break;
3412
case FBSD_LUSB_DEV_QUIRK_GET:
3413
args->cmd = USB_DEV_QUIRK_GET;
3414
break;
3415
case FBSD_LUSB_DEV_QUIRK_REMOVE:
3416
args->cmd = USB_DEV_QUIRK_REMOVE;
3417
break;
3418
case FBSD_LUSB_DO_REQUEST:
3419
args->cmd = USB_DO_REQUEST;
3420
break;
3421
case FBSD_LUSB_FS_CLEAR_STALL_SYNC:
3422
args->cmd = USB_FS_CLEAR_STALL_SYNC;
3423
break;
3424
case FBSD_LUSB_FS_CLOSE:
3425
args->cmd = USB_FS_CLOSE;
3426
break;
3427
case FBSD_LUSB_FS_COMPLETE:
3428
args->cmd = USB_FS_COMPLETE;
3429
break;
3430
case FBSD_LUSB_FS_INIT:
3431
args->cmd = USB_FS_INIT;
3432
break;
3433
case FBSD_LUSB_FS_OPEN:
3434
args->cmd = USB_FS_OPEN;
3435
break;
3436
case FBSD_LUSB_FS_START:
3437
args->cmd = USB_FS_START;
3438
break;
3439
case FBSD_LUSB_FS_STOP:
3440
args->cmd = USB_FS_STOP;
3441
break;
3442
case FBSD_LUSB_FS_UNINIT:
3443
args->cmd = USB_FS_UNINIT;
3444
break;
3445
case FBSD_LUSB_GET_CONFIG:
3446
args->cmd = USB_GET_CONFIG;
3447
break;
3448
case FBSD_LUSB_GET_DEVICEINFO:
3449
args->cmd = USB_GET_DEVICEINFO;
3450
break;
3451
case FBSD_LUSB_GET_DEVICE_DESC:
3452
args->cmd = USB_GET_DEVICE_DESC;
3453
break;
3454
case FBSD_LUSB_GET_FULL_DESC:
3455
args->cmd = USB_GET_FULL_DESC;
3456
break;
3457
case FBSD_LUSB_GET_IFACE_DRIVER:
3458
args->cmd = USB_GET_IFACE_DRIVER;
3459
break;
3460
case FBSD_LUSB_GET_PLUGTIME:
3461
args->cmd = USB_GET_PLUGTIME;
3462
break;
3463
case FBSD_LUSB_GET_POWER_MODE:
3464
args->cmd = USB_GET_POWER_MODE;
3465
break;
3466
case FBSD_LUSB_GET_REPORT_DESC:
3467
args->cmd = USB_GET_REPORT_DESC;
3468
break;
3469
case FBSD_LUSB_GET_REPORT_ID:
3470
args->cmd = USB_GET_REPORT_ID;
3471
break;
3472
case FBSD_LUSB_GET_TEMPLATE:
3473
args->cmd = USB_GET_TEMPLATE;
3474
break;
3475
case FBSD_LUSB_IFACE_DRIVER_ACTIVE:
3476
args->cmd = USB_IFACE_DRIVER_ACTIVE;
3477
break;
3478
case FBSD_LUSB_IFACE_DRIVER_DETACH:
3479
args->cmd = USB_IFACE_DRIVER_DETACH;
3480
break;
3481
case FBSD_LUSB_QUIRK_NAME_GET:
3482
args->cmd = USB_QUIRK_NAME_GET;
3483
break;
3484
case FBSD_LUSB_READ_DIR:
3485
args->cmd = USB_READ_DIR;
3486
break;
3487
case FBSD_LUSB_SET_ALTINTERFACE:
3488
args->cmd = USB_SET_ALTINTERFACE;
3489
break;
3490
case FBSD_LUSB_SET_CONFIG:
3491
args->cmd = USB_SET_CONFIG;
3492
break;
3493
case FBSD_LUSB_SET_IMMED:
3494
args->cmd = USB_SET_IMMED;
3495
break;
3496
case FBSD_LUSB_SET_POWER_MODE:
3497
args->cmd = USB_SET_POWER_MODE;
3498
break;
3499
case FBSD_LUSB_SET_TEMPLATE:
3500
args->cmd = USB_SET_TEMPLATE;
3501
break;
3502
case FBSD_LUSB_FS_OPEN_STREAM:
3503
args->cmd = USB_FS_OPEN_STREAM;
3504
break;
3505
case FBSD_LUSB_GET_DEV_PORT_PATH:
3506
args->cmd = USB_GET_DEV_PORT_PATH;
3507
break;
3508
case FBSD_LUSB_GET_POWER_USAGE:
3509
args->cmd = USB_GET_POWER_USAGE;
3510
break;
3511
case FBSD_LUSB_DEVICESTATS:
3512
args->cmd = USB_DEVICESTATS;
3513
break;
3514
default:
3515
error = ENOIOCTL;
3516
}
3517
if (error != ENOIOCTL)
3518
error = sys_ioctl(td, (struct ioctl_args *)args);
3519
return (error);
3520
}
3521
3522
/*
3523
* Some evdev ioctls must be translated.
3524
* - EVIOCGMTSLOTS is a IOC_READ ioctl on Linux although it has input data
3525
* (must be IOC_INOUT on FreeBSD).
3526
* - On Linux, EVIOCGRAB, EVIOCREVOKE and EVIOCRMFF are defined as _IOW with
3527
* an int argument. You don't pass an int pointer to the ioctl(), however,
3528
* but just the int directly. On FreeBSD, they are defined as _IOWINT for
3529
* this to work.
3530
*/
3531
static int
3532
linux_ioctl_evdev(struct thread *td, struct linux_ioctl_args *args)
3533
{
3534
struct file *fp;
3535
clockid_t clock;
3536
int error;
3537
3538
args->cmd = SETDIR(args->cmd);
3539
3540
switch (args->cmd) {
3541
case (EVIOCGRAB & ~IOC_DIRMASK) | IOC_IN:
3542
args->cmd = EVIOCGRAB;
3543
break;
3544
case (EVIOCREVOKE & ~IOC_DIRMASK) | IOC_IN:
3545
args->cmd = EVIOCREVOKE;
3546
break;
3547
case (EVIOCRMFF & ~IOC_DIRMASK) | IOC_IN:
3548
args->cmd = EVIOCRMFF;
3549
break;
3550
case EVIOCSCLOCKID: {
3551
error = copyin(PTRIN(args->arg), &clock, sizeof(clock));
3552
if (error != 0)
3553
return (error);
3554
if (clock & ~(LINUX_IOCTL_EVDEV_CLK))
3555
return (EINVAL);
3556
error = linux_to_native_clockid(&clock, clock);
3557
if (error != 0)
3558
return (error);
3559
3560
error = fget(td, args->fd,
3561
&cap_ioctl_rights, &fp);
3562
if (error != 0)
3563
return (error);
3564
3565
error = fo_ioctl(fp, EVIOCSCLOCKID, &clock, td->td_ucred, td);
3566
fdrop(fp, td);
3567
return (error);
3568
}
3569
default:
3570
break;
3571
}
3572
3573
if (IOCBASECMD(args->cmd) ==
3574
((EVIOCGMTSLOTS(0) & ~IOC_DIRMASK) | IOC_OUT))
3575
args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT;
3576
3577
return (sys_ioctl(td, (struct ioctl_args *)args));
3578
}
3579
3580
static int
3581
linux_ioctl_kcov(struct thread *td, struct linux_ioctl_args *args)
3582
{
3583
int error;
3584
3585
error = 0;
3586
switch (args->cmd & 0xffff) {
3587
case LINUX_KCOV_INIT_TRACE:
3588
args->cmd = KIOSETBUFSIZE;
3589
break;
3590
case LINUX_KCOV_ENABLE:
3591
args->cmd = KIOENABLE;
3592
if (args->arg == 0)
3593
args->arg = KCOV_MODE_TRACE_PC;
3594
else if (args->arg == 1)
3595
args->arg = KCOV_MODE_TRACE_CMP;
3596
else
3597
error = EINVAL;
3598
break;
3599
case LINUX_KCOV_DISABLE:
3600
args->cmd = KIODISABLE;
3601
break;
3602
default:
3603
error = ENOTTY;
3604
break;
3605
}
3606
3607
if (error == 0)
3608
error = sys_ioctl(td, (struct ioctl_args *)args);
3609
return (error);
3610
}
3611
3612
#ifndef COMPAT_LINUX32
3613
static int
3614
linux_ioctl_nvme(struct thread *td, struct linux_ioctl_args *args)
3615
{
3616
3617
/*
3618
* The NVMe drivers for namespace and controller implement these
3619
* commands using their native format. All the others are not
3620
* implemented yet.
3621
*/
3622
switch (args->cmd & 0xffff) {
3623
case LINUX_NVME_IOCTL_ID:
3624
args->cmd = NVME_IOCTL_ID;
3625
break;
3626
case LINUX_NVME_IOCTL_RESET:
3627
args->cmd = NVME_IOCTL_RESET;
3628
break;
3629
case LINUX_NVME_IOCTL_ADMIN_CMD:
3630
args->cmd = NVME_IOCTL_ADMIN_CMD;
3631
break;
3632
case LINUX_NVME_IOCTL_IO_CMD:
3633
args->cmd = NVME_IOCTL_IO_CMD;
3634
break;
3635
default:
3636
return (ENODEV);
3637
}
3638
return (sys_ioctl(td, (struct ioctl_args *)args));
3639
}
3640
#endif
3641
3642
static int
3643
linux_ioctl_hidraw(struct thread *td, struct linux_ioctl_args *args)
3644
{
3645
int len = (args->cmd & 0x3fff0000) >> 16;
3646
if (len > 8192)
3647
return (EINVAL);
3648
3649
switch (args->cmd & 0xffff) {
3650
case LINUX_HIDIOCGRDESCSIZE:
3651
args->cmd = HIDIOCGRDESCSIZE;
3652
break;
3653
case LINUX_HIDIOCGRDESC:
3654
args->cmd = HIDIOCGRDESC;
3655
break;
3656
case LINUX_HIDIOCGRAWINFO:
3657
args->cmd = HIDIOCGRAWINFO;
3658
break;
3659
case LINUX_HIDIOCGRAWNAME:
3660
args->cmd = HIDIOCGRAWNAME(len);
3661
break;
3662
case LINUX_HIDIOCGRAWPHYS:
3663
args->cmd = HIDIOCGRAWPHYS(len);
3664
break;
3665
case LINUX_HIDIOCSFEATURE:
3666
args->cmd = HIDIOCSFEATURE(len);
3667
break;
3668
case LINUX_HIDIOCGFEATURE:
3669
args->cmd = HIDIOCGFEATURE(len);
3670
break;
3671
case LINUX_HIDIOCGRAWUNIQ:
3672
args->cmd = HIDIOCGRAWUNIQ(len);
3673
break;
3674
case LINUX_HIDIOCSINPUT:
3675
args->cmd = HIDIOCSINPUT(len);
3676
break;
3677
case LINUX_HIDIOCGINPUT:
3678
args->cmd = HIDIOCGINPUT(len);
3679
break;
3680
case LINUX_HIDIOCSOUTPUT:
3681
args->cmd = HIDIOCSOUTPUT(len);
3682
break;
3683
case LINUX_HIDIOCGOUTPUT:
3684
args->cmd = HIDIOCGOUTPUT(len);
3685
break;
3686
}
3687
3688
return (sys_ioctl(td, (struct ioctl_args *)args));
3689
}
3690
3691
/*
3692
* main ioctl syscall function
3693
*/
3694
3695
static int
3696
linux_ioctl_fallback(struct thread *td, struct linux_ioctl_args *args)
3697
{
3698
struct file *fp;
3699
struct linux_ioctl_handler_element *he;
3700
int error, cmd;
3701
3702
error = fget(td, args->fd, &cap_ioctl_rights, &fp);
3703
if (error != 0)
3704
return (error);
3705
if ((fp->f_flag & (FREAD|FWRITE)) == 0) {
3706
fdrop(fp, td);
3707
return (EBADF);
3708
}
3709
3710
/* Iterate over the ioctl handlers */
3711
cmd = args->cmd & 0xffff;
3712
sx_slock(&linux_ioctl_sx);
3713
mtx_lock(&Giant);
3714
#ifdef COMPAT_LINUX32
3715
TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) {
3716
if (cmd >= he->low && cmd <= he->high) {
3717
error = (*he->func)(td, args);
3718
if (error != ENOIOCTL) {
3719
mtx_unlock(&Giant);
3720
sx_sunlock(&linux_ioctl_sx);
3721
fdrop(fp, td);
3722
return (error);
3723
}
3724
}
3725
}
3726
#endif
3727
TAILQ_FOREACH(he, &linux_ioctl_handlers, list) {
3728
if (cmd >= he->low && cmd <= he->high) {
3729
error = (*he->func)(td, args);
3730
if (error != ENOIOCTL) {
3731
mtx_unlock(&Giant);
3732
sx_sunlock(&linux_ioctl_sx);
3733
fdrop(fp, td);
3734
return (error);
3735
}
3736
}
3737
}
3738
mtx_unlock(&Giant);
3739
sx_sunlock(&linux_ioctl_sx);
3740
fdrop(fp, td);
3741
3742
switch (args->cmd & 0xffff) {
3743
case LINUX_BTRFS_IOC_CLONE:
3744
case LINUX_F2FS_IOC_GET_FEATURES:
3745
case LINUX_FS_IOC_FIEMAP:
3746
return (ENOTSUP);
3747
3748
default:
3749
linux_msg(td, "%s fd=%d, cmd=0x%x ('%c',%d) is not implemented",
3750
__func__, args->fd, args->cmd,
3751
(int)(args->cmd & 0xff00) >> 8, (int)(args->cmd & 0xff));
3752
break;
3753
}
3754
3755
return (EINVAL);
3756
}
3757
3758
int
3759
linux_ioctl(struct thread *td, struct linux_ioctl_args *args)
3760
{
3761
struct linux_ioctl_handler *handler;
3762
int error, cmd, i;
3763
3764
cmd = args->cmd & 0xffff;
3765
3766
/*
3767
* array of ioctls known at compilation time. Elides a lot of work on
3768
* each call compared to the list variant. Everything frequently used
3769
* should be moved here.
3770
*
3771
* Arguably the magic creating the list should create an array instead.
3772
*
3773
* For now just a linear scan.
3774
*/
3775
for (i = 0; i < nitems(linux_ioctls); i++) {
3776
handler = &linux_ioctls[i];
3777
if (cmd >= handler->low && cmd <= handler->high) {
3778
error = (*handler->func)(td, args);
3779
if (error != ENOIOCTL) {
3780
return (error);
3781
}
3782
}
3783
}
3784
return (linux_ioctl_fallback(td, args));
3785
}
3786
3787
int
3788
linux_ioctl_register_handler(struct linux_ioctl_handler *h)
3789
{
3790
struct linux_ioctl_handler_element *he, *cur;
3791
3792
if (h == NULL || h->func == NULL)
3793
return (EINVAL);
3794
3795
/*
3796
* Reuse the element if the handler is already on the list, otherwise
3797
* create a new element.
3798
*/
3799
sx_xlock(&linux_ioctl_sx);
3800
TAILQ_FOREACH(he, &linux_ioctl_handlers, list) {
3801
if (he->func == h->func)
3802
break;
3803
}
3804
if (he == NULL) {
3805
he = malloc(sizeof(*he),
3806
M_LINUX, M_WAITOK);
3807
he->func = h->func;
3808
} else
3809
TAILQ_REMOVE(&linux_ioctl_handlers, he, list);
3810
3811
/* Initialize range information. */
3812
he->low = h->low;
3813
he->high = h->high;
3814
he->span = h->high - h->low + 1;
3815
3816
/* Add the element to the list, sorted on span. */
3817
TAILQ_FOREACH(cur, &linux_ioctl_handlers, list) {
3818
if (cur->span > he->span) {
3819
TAILQ_INSERT_BEFORE(cur, he, list);
3820
sx_xunlock(&linux_ioctl_sx);
3821
return (0);
3822
}
3823
}
3824
TAILQ_INSERT_TAIL(&linux_ioctl_handlers, he, list);
3825
sx_xunlock(&linux_ioctl_sx);
3826
3827
return (0);
3828
}
3829
3830
int
3831
linux_ioctl_unregister_handler(struct linux_ioctl_handler *h)
3832
{
3833
struct linux_ioctl_handler_element *he;
3834
3835
if (h == NULL || h->func == NULL)
3836
return (EINVAL);
3837
3838
sx_xlock(&linux_ioctl_sx);
3839
TAILQ_FOREACH(he, &linux_ioctl_handlers, list) {
3840
if (he->func == h->func) {
3841
TAILQ_REMOVE(&linux_ioctl_handlers, he, list);
3842
sx_xunlock(&linux_ioctl_sx);
3843
free(he, M_LINUX);
3844
return (0);
3845
}
3846
}
3847
sx_xunlock(&linux_ioctl_sx);
3848
3849
return (EINVAL);
3850
}
3851
3852
#ifdef COMPAT_LINUX32
3853
int
3854
linux32_ioctl_register_handler(struct linux_ioctl_handler *h)
3855
{
3856
struct linux_ioctl_handler_element *he, *cur;
3857
3858
if (h == NULL || h->func == NULL)
3859
return (EINVAL);
3860
3861
/*
3862
* Reuse the element if the handler is already on the list, otherwise
3863
* create a new element.
3864
*/
3865
sx_xlock(&linux_ioctl_sx);
3866
TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) {
3867
if (he->func == h->func)
3868
break;
3869
}
3870
if (he == NULL) {
3871
he = malloc(sizeof(*he), M_LINUX, M_WAITOK);
3872
he->func = h->func;
3873
} else
3874
TAILQ_REMOVE(&linux32_ioctl_handlers, he, list);
3875
3876
/* Initialize range information. */
3877
he->low = h->low;
3878
he->high = h->high;
3879
he->span = h->high - h->low + 1;
3880
3881
/* Add the element to the list, sorted on span. */
3882
TAILQ_FOREACH(cur, &linux32_ioctl_handlers, list) {
3883
if (cur->span > he->span) {
3884
TAILQ_INSERT_BEFORE(cur, he, list);
3885
sx_xunlock(&linux_ioctl_sx);
3886
return (0);
3887
}
3888
}
3889
TAILQ_INSERT_TAIL(&linux32_ioctl_handlers, he, list);
3890
sx_xunlock(&linux_ioctl_sx);
3891
3892
return (0);
3893
}
3894
3895
int
3896
linux32_ioctl_unregister_handler(struct linux_ioctl_handler *h)
3897
{
3898
struct linux_ioctl_handler_element *he;
3899
3900
if (h == NULL || h->func == NULL)
3901
return (EINVAL);
3902
3903
sx_xlock(&linux_ioctl_sx);
3904
TAILQ_FOREACH(he, &linux32_ioctl_handlers, list) {
3905
if (he->func == h->func) {
3906
TAILQ_REMOVE(&linux32_ioctl_handlers, he, list);
3907
sx_xunlock(&linux_ioctl_sx);
3908
free(he, M_LINUX);
3909
return (0);
3910
}
3911
}
3912
sx_xunlock(&linux_ioctl_sx);
3913
3914
return (EINVAL);
3915
}
3916
#endif
3917
3918