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