Blame view
drivers/char/ppdev.c
20.5 KB
1da177e4c
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
/* * linux/drivers/char/ppdev.c * * This is the code behind /dev/parport* -- it allows a user-space * application to use the parport subsystem. * * Copyright (C) 1998-2000, 2002 Tim Waugh <tim@cyberelk.net> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * A /dev/parportx device node represents an arbitrary device * on port 'x'. The following operations are possible: * * open do nothing, set up default IEEE 1284 protocol to be COMPAT * close release port and unregister device (if necessary) * ioctl * EXCL register device exclusively (may fail) * CLAIM (register device first time) parport_claim_or_block * RELEASE parport_release * SETMODE set the IEEE 1284 protocol to use for read/write * SETPHASE set the IEEE 1284 phase of a particular mode. Not to be * confused with ioctl(fd, SETPHASER, &stun). ;-) * DATADIR data_forward / data_reverse * WDATA write_data * RDATA read_data * WCONTROL write_control * RCONTROL read_control * FCONTROL frob_control * RSTATUS read_status * NEGOT parport_negotiate * YIELD parport_yield_blocking * WCTLONIRQ on interrupt, set control lines * CLRIRQ clear (and return) interrupt count * SETTIME sets device timeout (struct timeval) * GETTIME gets device timeout (struct timeval) * GETMODES gets hardware supported modes (unsigned int) * GETMODE gets the current IEEE1284 mode * GETPHASE gets the current IEEE1284 phase * GETFLAGS gets current (user-visible) flags * SETFLAGS sets current (user-visible) flags * read/write read or write in current IEEE 1284 protocol * select wait for interrupt (in readfds) * * Changes: * Added SETTIME/GETTIME ioctl, Fred Barnes, 1999. * * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 2000/08/25 * - On error, copy_from_user and copy_to_user do not return -EFAULT, * They return the positive number of bytes *not* copied due to address * space errors. * * Added GETMODES/GETMODE/GETPHASE ioctls, Fred Barnes <frmb2@ukc.ac.uk>, 03/01/2001. * Added GETFLAGS/SETFLAGS ioctls, Fred Barnes, 04/2001 */ #include <linux/module.h> #include <linux/init.h> |
174cd4b1e
|
61 |
#include <linux/sched/signal.h> |
1da177e4c
|
62 |
#include <linux/device.h> |
1da177e4c
|
63 64 65 66 |
#include <linux/ioctl.h> #include <linux/parport.h> #include <linux/ctype.h> #include <linux/poll.h> |
5a0e3ad6a
|
67 |
#include <linux/slab.h> |
e6a678462
|
68 |
#include <linux/major.h> |
1da177e4c
|
69 |
#include <linux/ppdev.h> |
613655fa3
|
70 |
#include <linux/mutex.h> |
6d535d3e6
|
71 |
#include <linux/uaccess.h> |
17a3596f2
|
72 |
#include <linux/compat.h> |
1da177e4c
|
73 74 75 76 77 |
#define PP_VERSION "ppdev: user-space parallel port driver" #define CHRDEV "ppdev" struct pp_struct { |
d85c1a2d1
|
78 |
struct pardevice *pdev; |
1da177e4c
|
79 80 81 82 83 84 85 86 |
wait_queue_head_t irq_wait; atomic_t irqc; unsigned int flags; int irqresponse; unsigned char irqctl; struct ieee1284_info state; struct ieee1284_info saved_state; long default_inactivity; |
9a69645dd
|
87 |
int index; |
1da177e4c
|
88 |
}; |
dd5c472a6
|
89 90 |
/* should we use PARDEVICE_MAX here? */ static struct device *devices[PARPORT_MAX]; |
9a69645dd
|
91 |
static DEFINE_IDA(ida_index); |
1da177e4c
|
92 93 94 95 96 97 98 99 |
/* pp_struct.flags bitfields */ #define PP_CLAIMED (1<<0) #define PP_EXCL (1<<1) /* Other constants */ #define PP_INTERRUPT_TIMEOUT (10 * HZ) /* 10s */ #define PP_BUFFER_SIZE 1024 #define PARDEVICE_MAX 8 |
613655fa3
|
100 |
static DEFINE_MUTEX(pp_do_mutex); |
3b9ab374a
|
101 102 103 104 105 106 |
/* define fixed sized ioctl cmd for y2038 migration */ #define PPGETTIME32 _IOR(PP_IOCTL, 0x95, s32[2]) #define PPSETTIME32 _IOW(PP_IOCTL, 0x96, s32[2]) #define PPGETTIME64 _IOR(PP_IOCTL, 0x95, s64[2]) #define PPSETTIME64 _IOW(PP_IOCTL, 0x96, s64[2]) |
783ea44db
|
107 |
static inline void pp_enable_irq(struct pp_struct *pp) |
1da177e4c
|
108 109 |
{ struct parport *port = pp->pdev->port; |
27f3b8a3b
|
110 |
|
783ea44db
|
111 |
port->ops->enable_irq(port); |
1da177e4c
|
112 |
} |
d85c1a2d1
|
113 |
static ssize_t pp_read(struct file *file, char __user *buf, size_t count, |
a7c71c07a
|
114 |
loff_t *ppos) |
1da177e4c
|
115 |
{ |
496ad9aa8
|
116 |
unsigned int minor = iminor(file_inode(file)); |
1da177e4c
|
117 |
struct pp_struct *pp = file->private_data; |
d85c1a2d1
|
118 |
char *kbuffer; |
1da177e4c
|
119 120 121 122 123 124 |
ssize_t bytes_read = 0; struct parport *pport; int mode; if (!(pp->flags & PP_CLAIMED)) { /* Don't have the port claimed */ |
81fc401e4
|
125 126 |
pr_debug(CHRDEV "%x: claim the port first ", minor); |
1da177e4c
|
127 128 129 130 131 132 133 134 |
return -EINVAL; } /* Trivial case. */ if (count == 0) return 0; kbuffer = kmalloc(min_t(size_t, count, PP_BUFFER_SIZE), GFP_KERNEL); |
83e80605c
|
135 |
if (!kbuffer) |
1da177e4c
|
136 |
return -ENOMEM; |
1da177e4c
|
137 138 |
pport = pp->pdev->port; mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); |
783ea44db
|
139 |
parport_set_timeout(pp->pdev, |
a7c71c07a
|
140 141 142 |
(file->f_flags & O_NONBLOCK) ? PARPORT_INACTIVITY_O_NONBLOCK : pp->default_inactivity); |
1da177e4c
|
143 144 145 146 147 148 149 150 |
while (bytes_read == 0) { ssize_t need = min_t(unsigned long, count, PP_BUFFER_SIZE); if (mode == IEEE1284_MODE_EPP) { /* various specials for EPP mode */ int flags = 0; size_t (*fn)(struct parport *, void *, size_t, int); |
83e80605c
|
151 |
if (pp->flags & PP_W91284PIC) |
1da177e4c
|
152 |
flags |= PARPORT_W91284PIC; |
83e80605c
|
153 |
if (pp->flags & PP_FASTREAD) |
1da177e4c
|
154 |
flags |= PARPORT_EPP_FAST; |
83e80605c
|
155 |
if (pport->ieee1284.mode & IEEE1284_ADDR) |
1da177e4c
|
156 |
fn = pport->ops->epp_read_addr; |
83e80605c
|
157 |
else |
1da177e4c
|
158 |
fn = pport->ops->epp_read_data; |
1da177e4c
|
159 160 |
bytes_read = (*fn)(pport, kbuffer, need, flags); } else { |
783ea44db
|
161 |
bytes_read = parport_read(pport, kbuffer, need); |
1da177e4c
|
162 163 164 165 166 167 168 169 170 |
} if (bytes_read != 0) break; if (file->f_flags & O_NONBLOCK) { bytes_read = -EAGAIN; break; } |
783ea44db
|
171 |
if (signal_pending(current)) { |
1da177e4c
|
172 173 174 175 176 177 |
bytes_read = -ERESTARTSYS; break; } cond_resched(); } |
783ea44db
|
178 |
parport_set_timeout(pp->pdev, pp->default_inactivity); |
1da177e4c
|
179 |
|
783ea44db
|
180 |
if (bytes_read > 0 && copy_to_user(buf, kbuffer, bytes_read)) |
1da177e4c
|
181 |
bytes_read = -EFAULT; |
783ea44db
|
182 183 |
kfree(kbuffer); pp_enable_irq(pp); |
1da177e4c
|
184 185 |
return bytes_read; } |
d85c1a2d1
|
186 |
static ssize_t pp_write(struct file *file, const char __user *buf, |
a7c71c07a
|
187 |
size_t count, loff_t *ppos) |
1da177e4c
|
188 |
{ |
496ad9aa8
|
189 |
unsigned int minor = iminor(file_inode(file)); |
1da177e4c
|
190 |
struct pp_struct *pp = file->private_data; |
d85c1a2d1
|
191 |
char *kbuffer; |
1da177e4c
|
192 193 194 195 196 197 198 |
ssize_t bytes_written = 0; ssize_t wrote; int mode; struct parport *pport; if (!(pp->flags & PP_CLAIMED)) { /* Don't have the port claimed */ |
81fc401e4
|
199 200 |
pr_debug(CHRDEV "%x: claim the port first ", minor); |
1da177e4c
|
201 202 203 204 |
return -EINVAL; } kbuffer = kmalloc(min_t(size_t, count, PP_BUFFER_SIZE), GFP_KERNEL); |
83e80605c
|
205 |
if (!kbuffer) |
1da177e4c
|
206 |
return -ENOMEM; |
83e80605c
|
207 |
|
1da177e4c
|
208 209 |
pport = pp->pdev->port; mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); |
783ea44db
|
210 |
parport_set_timeout(pp->pdev, |
a7c71c07a
|
211 212 213 |
(file->f_flags & O_NONBLOCK) ? PARPORT_INACTIVITY_O_NONBLOCK : pp->default_inactivity); |
1da177e4c
|
214 215 216 |
while (bytes_written < count) { ssize_t n = min_t(unsigned long, count - bytes_written, PP_BUFFER_SIZE); |
783ea44db
|
217 |
if (copy_from_user(kbuffer, buf + bytes_written, n)) { |
1da177e4c
|
218 219 220 221 222 223 224 |
bytes_written = -EFAULT; break; } if ((pp->flags & PP_FASTWRITE) && (mode == IEEE1284_MODE_EPP)) { /* do a fast EPP write */ if (pport->ieee1284.mode & IEEE1284_ADDR) { |
783ea44db
|
225 |
wrote = pport->ops->epp_write_addr(pport, |
1da177e4c
|
226 227 |
kbuffer, n, PARPORT_EPP_FAST); } else { |
783ea44db
|
228 |
wrote = pport->ops->epp_write_data(pport, |
1da177e4c
|
229 230 231 |
kbuffer, n, PARPORT_EPP_FAST); } } else { |
783ea44db
|
232 |
wrote = parport_write(pp->pdev->port, kbuffer, n); |
1da177e4c
|
233 234 235 |
} if (wrote <= 0) { |
83e80605c
|
236 |
if (!bytes_written) |
1da177e4c
|
237 |
bytes_written = wrote; |
1da177e4c
|
238 239 240 241 242 243 244 245 246 247 |
break; } bytes_written += wrote; if (file->f_flags & O_NONBLOCK) { if (!bytes_written) bytes_written = -EAGAIN; break; } |
783ea44db
|
248 |
if (signal_pending(current)) |
1da177e4c
|
249 |
break; |
1da177e4c
|
250 251 252 |
cond_resched(); } |
783ea44db
|
253 |
parport_set_timeout(pp->pdev, pp->default_inactivity); |
1da177e4c
|
254 |
|
783ea44db
|
255 256 |
kfree(kbuffer); pp_enable_irq(pp); |
1da177e4c
|
257 258 |
return bytes_written; } |
783ea44db
|
259 |
static void pp_irq(void *private) |
1da177e4c
|
260 |
{ |
5712cb3d8
|
261 |
struct pp_struct *pp = private; |
1da177e4c
|
262 263 |
if (pp->irqresponse) { |
783ea44db
|
264 |
parport_write_control(pp->pdev->port, pp->irqctl); |
1da177e4c
|
265 266 |
pp->irqresponse = 0; } |
783ea44db
|
267 268 |
atomic_inc(&pp->irqc); wake_up_interruptible(&pp->irq_wait); |
1da177e4c
|
269 |
} |
783ea44db
|
270 |
static int register_device(int minor, struct pp_struct *pp) |
1da177e4c
|
271 272 |
{ struct parport *port; |
d85c1a2d1
|
273 |
struct pardevice *pdev = NULL; |
1da177e4c
|
274 |
char *name; |
8b7d3a9d9
|
275 |
struct pardev_cb ppdev_cb; |
9a69645dd
|
276 |
int rc = 0, index; |
1da177e4c
|
277 |
|
87575437d
|
278 |
name = kasprintf(GFP_KERNEL, CHRDEV "%x", minor); |
1da177e4c
|
279 280 |
if (name == NULL) return -ENOMEM; |
783ea44db
|
281 |
port = parport_find_number(minor); |
1da177e4c
|
282 |
if (!port) { |
826a4c657
|
283 284 |
pr_warn("%s: no associated port! ", name); |
0fa2c8eb2
|
285 286 |
rc = -ENXIO; goto err; |
1da177e4c
|
287 |
} |
9a69645dd
|
288 |
index = ida_simple_get(&ida_index, 0, 0, GFP_KERNEL); |
8b7d3a9d9
|
289 290 291 292 |
memset(&ppdev_cb, 0, sizeof(ppdev_cb)); ppdev_cb.irq_func = pp_irq; ppdev_cb.flags = (pp->flags & PP_EXCL) ? PARPORT_FLAG_EXCL : 0; ppdev_cb.private = pp; |
9a69645dd
|
293 |
pdev = parport_register_dev_model(port, name, &ppdev_cb, index); |
783ea44db
|
294 |
parport_put_port(port); |
1da177e4c
|
295 296 |
if (!pdev) { |
826a4c657
|
297 298 |
pr_warn("%s: failed to register device! ", name); |
0fa2c8eb2
|
299 |
rc = -ENXIO; |
9a69645dd
|
300 |
ida_simple_remove(&ida_index, index); |
0fa2c8eb2
|
301 |
goto err; |
1da177e4c
|
302 303 304 |
} pp->pdev = pdev; |
9a69645dd
|
305 |
pp->index = index; |
396ec3dea
|
306 307 |
dev_dbg(&pdev->dev, "registered pardevice "); |
0fa2c8eb2
|
308 309 310 |
err: kfree(name); return rc; |
1da177e4c
|
311 |
} |
783ea44db
|
312 |
static enum ieee1284_phase init_phase(int mode) |
1da177e4c
|
313 314 315 316 317 318 319 320 321 |
{ switch (mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR)) { case IEEE1284_MODE_NIBBLE: case IEEE1284_MODE_BYTE: return IEEE1284_PH_REV_IDLE; } return IEEE1284_PH_FWD_IDLE; } |
3b9ab374a
|
322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 |
static int pp_set_timeout(struct pardevice *pdev, long tv_sec, int tv_usec) { long to_jiffies; if ((tv_sec < 0) || (tv_usec < 0)) return -EINVAL; to_jiffies = usecs_to_jiffies(tv_usec); to_jiffies += tv_sec * HZ; if (to_jiffies <= 0) return -EINVAL; pdev->timeout = to_jiffies; return 0; } |
6d535d3e6
|
337 |
static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
1da177e4c
|
338 |
{ |
496ad9aa8
|
339 |
unsigned int minor = iminor(file_inode(file)); |
1da177e4c
|
340 |
struct pp_struct *pp = file->private_data; |
d85c1a2d1
|
341 |
struct parport *port; |
1da177e4c
|
342 343 344 345 346 347 348 349 350 351 |
void __user *argp = (void __user *)arg; /* First handle the cases that don't take arguments. */ switch (cmd) { case PPCLAIM: { struct ieee1284_info *info; int ret; if (pp->flags & PP_CLAIMED) { |
396ec3dea
|
352 353 |
dev_dbg(&pp->pdev->dev, "you've already got it! "); |
1da177e4c
|
354 355 356 357 358 |
return -EINVAL; } /* Deferred device registration. */ if (!pp->pdev) { |
783ea44db
|
359 |
int err = register_device(minor, pp); |
27f3b8a3b
|
360 |
|
83e80605c
|
361 |
if (err) |
1da177e4c
|
362 |
return err; |
1da177e4c
|
363 |
} |
783ea44db
|
364 |
ret = parport_claim_or_block(pp->pdev); |
1da177e4c
|
365 366 367 368 369 370 371 |
if (ret < 0) return ret; pp->flags |= PP_CLAIMED; /* For interrupt-reporting to work, we need to be * informed of each interrupt. */ |
783ea44db
|
372 |
pp_enable_irq(pp); |
1da177e4c
|
373 374 375 376 377 378 379 |
/* We may need to fix up the state machine. */ info = &pp->pdev->port->ieee1284; pp->saved_state.mode = info->mode; pp->saved_state.phase = info->phase; info->mode = pp->state.mode; info->phase = pp->state.phase; |
783ea44db
|
380 381 |
pp->default_inactivity = parport_set_timeout(pp->pdev, 0); parport_set_timeout(pp->pdev, pp->default_inactivity); |
1da177e4c
|
382 383 384 385 386 |
return 0; } case PPEXCL: if (pp->pdev) { |
396ec3dea
|
387 388 389 |
dev_dbg(&pp->pdev->dev, "too late for PPEXCL; already registered "); |
1da177e4c
|
390 391 392 393 394 395 396 397 398 399 400 401 402 403 |
if (pp->flags & PP_EXCL) /* But it's not really an error. */ return 0; /* There's no chance of making the driver happy. */ return -EINVAL; } /* Just remember to register the device exclusively * when we finally do the registration. */ pp->flags |= PP_EXCL; return 0; case PPSETMODE: { int mode; |
27f3b8a3b
|
404 |
|
783ea44db
|
405 |
if (copy_from_user(&mode, argp, sizeof(mode))) |
1da177e4c
|
406 407 408 |
return -EFAULT; /* FIXME: validate mode */ pp->state.mode = mode; |
783ea44db
|
409 |
pp->state.phase = init_phase(mode); |
1da177e4c
|
410 411 412 413 414 415 416 417 418 419 420 |
if (pp->flags & PP_CLAIMED) { pp->pdev->port->ieee1284.mode = mode; pp->pdev->port->ieee1284.phase = pp->state.phase; } return 0; } case PPGETMODE: { int mode; |
83e80605c
|
421 |
if (pp->flags & PP_CLAIMED) |
1da177e4c
|
422 |
mode = pp->pdev->port->ieee1284.mode; |
83e80605c
|
423 |
else |
1da177e4c
|
424 |
mode = pp->state.mode; |
83e80605c
|
425 426 |
if (copy_to_user(argp, &mode, sizeof(mode))) |
1da177e4c
|
427 |
return -EFAULT; |
1da177e4c
|
428 429 430 431 432 |
return 0; } case PPSETPHASE: { int phase; |
27f3b8a3b
|
433 |
|
83e80605c
|
434 |
if (copy_from_user(&phase, argp, sizeof(phase))) |
1da177e4c
|
435 |
return -EFAULT; |
83e80605c
|
436 |
|
1da177e4c
|
437 438 |
/* FIXME: validate phase */ pp->state.phase = phase; |
83e80605c
|
439 |
if (pp->flags & PP_CLAIMED) |
1da177e4c
|
440 |
pp->pdev->port->ieee1284.phase = phase; |
1da177e4c
|
441 442 443 444 445 446 |
return 0; } case PPGETPHASE: { int phase; |
83e80605c
|
447 |
if (pp->flags & PP_CLAIMED) |
1da177e4c
|
448 |
phase = pp->pdev->port->ieee1284.phase; |
83e80605c
|
449 |
else |
1da177e4c
|
450 |
phase = pp->state.phase; |
83e80605c
|
451 |
if (copy_to_user(argp, &phase, sizeof(phase))) |
1da177e4c
|
452 |
return -EFAULT; |
1da177e4c
|
453 454 455 456 457 |
return 0; } case PPGETMODES: { unsigned int modes; |
783ea44db
|
458 |
port = parport_find_number(minor); |
1da177e4c
|
459 460 461 462 |
if (!port) return -ENODEV; modes = port->modes; |
d98808a25
|
463 |
parport_put_port(port); |
83e80605c
|
464 |
if (copy_to_user(argp, &modes, sizeof(modes))) |
1da177e4c
|
465 |
return -EFAULT; |
1da177e4c
|
466 467 468 469 470 |
return 0; } case PPSETFLAGS: { int uflags; |
83e80605c
|
471 |
if (copy_from_user(&uflags, argp, sizeof(uflags))) |
1da177e4c
|
472 |
return -EFAULT; |
1da177e4c
|
473 474 475 476 477 478 479 480 481 |
pp->flags &= ~PP_FLAGMASK; pp->flags |= (uflags & PP_FLAGMASK); return 0; } case PPGETFLAGS: { int uflags; uflags = pp->flags & PP_FLAGMASK; |
83e80605c
|
482 |
if (copy_to_user(argp, &uflags, sizeof(uflags))) |
1da177e4c
|
483 |
return -EFAULT; |
1da177e4c
|
484 485 486 487 488 489 490 |
return 0; } } /* end switch() */ /* Everything else requires the port to be claimed, so check * that now. */ if ((pp->flags & PP_CLAIMED) == 0) { |
81fc401e4
|
491 492 |
pr_debug(CHRDEV "%x: claim the port first ", minor); |
1da177e4c
|
493 494 495 496 497 498 499 500 501 |
return -EINVAL; } port = pp->pdev->port; switch (cmd) { struct ieee1284_info *info; unsigned char reg; unsigned char mask; int mode; |
3b9ab374a
|
502 503 504 |
s32 time32[2]; s64 time64[2]; struct timespec64 ts; |
1da177e4c
|
505 |
int ret; |
1da177e4c
|
506 507 |
case PPRSTATUS: |
783ea44db
|
508 509 |
reg = parport_read_status(port); if (copy_to_user(argp, ®, sizeof(reg))) |
1da177e4c
|
510 511 512 |
return -EFAULT; return 0; case PPRDATA: |
783ea44db
|
513 514 |
reg = parport_read_data(port); if (copy_to_user(argp, ®, sizeof(reg))) |
1da177e4c
|
515 516 517 |
return -EFAULT; return 0; case PPRCONTROL: |
783ea44db
|
518 519 |
reg = parport_read_control(port); if (copy_to_user(argp, ®, sizeof(reg))) |
1da177e4c
|
520 521 522 |
return -EFAULT; return 0; case PPYIELD: |
783ea44db
|
523 |
parport_yield_blocking(pp->pdev); |
1da177e4c
|
524 525 526 527 528 529 530 531 532 |
return 0; case PPRELEASE: /* Save the state machine's state. */ info = &pp->pdev->port->ieee1284; pp->state.mode = info->mode; pp->state.phase = info->phase; info->mode = pp->saved_state.mode; info->phase = pp->saved_state.phase; |
783ea44db
|
533 |
parport_release(pp->pdev); |
1da177e4c
|
534 535 536 537 |
pp->flags &= ~PP_CLAIMED; return 0; case PPWCONTROL: |
783ea44db
|
538 |
if (copy_from_user(®, argp, sizeof(reg))) |
1da177e4c
|
539 |
return -EFAULT; |
783ea44db
|
540 |
parport_write_control(port, reg); |
1da177e4c
|
541 542 543 |
return 0; case PPWDATA: |
783ea44db
|
544 |
if (copy_from_user(®, argp, sizeof(reg))) |
1da177e4c
|
545 |
return -EFAULT; |
783ea44db
|
546 |
parport_write_data(port, reg); |
1da177e4c
|
547 548 549 |
return 0; case PPFCONTROL: |
783ea44db
|
550 |
if (copy_from_user(&mask, argp, |
a7c71c07a
|
551 |
sizeof(mask))) |
1da177e4c
|
552 |
return -EFAULT; |
783ea44db
|
553 |
if (copy_from_user(®, 1 + (unsigned char __user *) arg, |
a7c71c07a
|
554 |
sizeof(reg))) |
1da177e4c
|
555 |
return -EFAULT; |
783ea44db
|
556 |
parport_frob_control(port, mask, reg); |
1da177e4c
|
557 558 559 |
return 0; case PPDATADIR: |
783ea44db
|
560 |
if (copy_from_user(&mode, argp, sizeof(mode))) |
1da177e4c
|
561 562 |
return -EFAULT; if (mode) |
783ea44db
|
563 |
port->ops->data_reverse(port); |
1da177e4c
|
564 |
else |
783ea44db
|
565 |
port->ops->data_forward(port); |
1da177e4c
|
566 567 568 |
return 0; case PPNEGOT: |
783ea44db
|
569 |
if (copy_from_user(&mode, argp, sizeof(mode))) |
1da177e4c
|
570 |
return -EFAULT; |
783ea44db
|
571 |
switch ((ret = parport_negotiate(port, mode))) { |
1da177e4c
|
572 573 574 575 576 577 578 579 |
case 0: break; case -1: /* handshake failed, peripheral not IEEE 1284 */ ret = -EIO; break; case 1: /* handshake succeeded, peripheral rejected mode */ ret = -ENXIO; break; } |
783ea44db
|
580 |
pp_enable_irq(pp); |
1da177e4c
|
581 582 583 |
return ret; case PPWCTLONIRQ: |
783ea44db
|
584 |
if (copy_from_user(®, argp, sizeof(reg))) |
1da177e4c
|
585 586 587 588 589 590 591 592 593 |
return -EFAULT; /* Remember what to set the control lines to, for next * time we get an interrupt. */ pp->irqctl = reg; pp->irqresponse = 1; return 0; case PPCLRIRQ: |
783ea44db
|
594 595 |
ret = atomic_read(&pp->irqc); if (copy_to_user(argp, &ret, sizeof(ret))) |
1da177e4c
|
596 |
return -EFAULT; |
783ea44db
|
597 |
atomic_sub(ret, &pp->irqc); |
1da177e4c
|
598 |
return 0; |
3b9ab374a
|
599 600 |
case PPSETTIME32: if (copy_from_user(time32, argp, sizeof(time32))) |
1da177e4c
|
601 |
return -EFAULT; |
3b9ab374a
|
602 603 604 605 606 607 608 609 610 611 612 613 614 615 |
return pp_set_timeout(pp->pdev, time32[0], time32[1]); case PPSETTIME64: if (copy_from_user(time64, argp, sizeof(time64))) return -EFAULT; return pp_set_timeout(pp->pdev, time64[0], time64[1]); case PPGETTIME32: jiffies_to_timespec64(pp->pdev->timeout, &ts); time32[0] = ts.tv_sec; time32[1] = ts.tv_nsec / NSEC_PER_USEC; if ((time32[0] < 0) || (time32[1] < 0)) |
1da177e4c
|
616 |
return -EINVAL; |
3b9ab374a
|
617 618 619 |
if (copy_to_user(argp, time32, sizeof(time32))) return -EFAULT; |
1da177e4c
|
620 |
return 0; |
3b9ab374a
|
621 622 623 624 625 626 627 628 |
case PPGETTIME64: jiffies_to_timespec64(pp->pdev->timeout, &ts); time64[0] = ts.tv_sec; time64[1] = ts.tv_nsec / NSEC_PER_USEC; if ((time64[0] < 0) || (time64[1] < 0)) return -EINVAL; if (copy_to_user(argp, time64, sizeof(time64))) |
1da177e4c
|
629 |
return -EFAULT; |
3b9ab374a
|
630 |
|
1da177e4c
|
631 632 633 |
return 0; default: |
396ec3dea
|
634 635 |
dev_dbg(&pp->pdev->dev, "What? (cmd=0x%x) ", cmd); |
1da177e4c
|
636 637 638 639 640 641 |
return -EINVAL; } /* Keep the compiler happy */ return 0; } |
6d535d3e6
|
642 643 644 |
static long pp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { long ret; |
27f3b8a3b
|
645 |
|
613655fa3
|
646 |
mutex_lock(&pp_do_mutex); |
6d535d3e6
|
647 |
ret = pp_do_ioctl(file, cmd, arg); |
613655fa3
|
648 |
mutex_unlock(&pp_do_mutex); |
6d535d3e6
|
649 650 |
return ret; } |
17a3596f2
|
651 652 |
#ifdef CONFIG_COMPAT static long pp_compat_ioctl(struct file *file, unsigned int cmd, |
a7c71c07a
|
653 |
unsigned long arg) |
17a3596f2
|
654 655 656 657 |
{ return pp_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); } #endif |
d85c1a2d1
|
658 |
static int pp_open(struct inode *inode, struct file *file) |
1da177e4c
|
659 660 661 662 663 664 |
{ unsigned int minor = iminor(inode); struct pp_struct *pp; if (minor >= PARPORT_MAX) return -ENXIO; |
783ea44db
|
665 |
pp = kmalloc(sizeof(struct pp_struct), GFP_KERNEL); |
1da177e4c
|
666 667 668 669 |
if (!pp) return -ENOMEM; pp->state.mode = IEEE1284_MODE_COMPAT; |
783ea44db
|
670 |
pp->state.phase = init_phase(pp->state.mode); |
1da177e4c
|
671 672 |
pp->flags = 0; pp->irqresponse = 0; |
783ea44db
|
673 674 |
atomic_set(&pp->irqc, 0); init_waitqueue_head(&pp->irq_wait); |
1da177e4c
|
675 676 677 678 679 680 681 682 683 684 |
/* Defer the actual device registration until the first claim. * That way, we know whether or not the driver wants to have * exclusive access to the port (PPEXCL). */ pp->pdev = NULL; file->private_data = pp; return 0; } |
d85c1a2d1
|
685 |
static int pp_release(struct inode *inode, struct file *file) |
1da177e4c
|
686 687 688 689 690 691 692 693 |
{ unsigned int minor = iminor(inode); struct pp_struct *pp = file->private_data; int compat_negot; compat_negot = 0; if (!(pp->flags & PP_CLAIMED) && pp->pdev && (pp->state.mode != IEEE1284_MODE_COMPAT)) { |
3c8db5843
|
694 |
struct ieee1284_info *info; |
1da177e4c
|
695 696 |
/* parport released, but not in compatibility mode */ |
783ea44db
|
697 |
parport_claim_or_block(pp->pdev); |
1da177e4c
|
698 699 700 701 702 703 704 705 706 707 708 709 |
pp->flags |= PP_CLAIMED; info = &pp->pdev->port->ieee1284; pp->saved_state.mode = info->mode; pp->saved_state.phase = info->phase; info->mode = pp->state.mode; info->phase = pp->state.phase; compat_negot = 1; } else if ((pp->flags & PP_CLAIMED) && pp->pdev && (pp->pdev->port->ieee1284.mode != IEEE1284_MODE_COMPAT)) { compat_negot = 2; } if (compat_negot) { |
783ea44db
|
710 |
parport_negotiate(pp->pdev->port, IEEE1284_MODE_COMPAT); |
396ec3dea
|
711 712 713 |
dev_dbg(&pp->pdev->dev, "negotiated back to compatibility mode because user-space forgot "); |
1da177e4c
|
714 715 716 717 718 719 720 721 722 723 |
} if (pp->flags & PP_CLAIMED) { struct ieee1284_info *info; info = &pp->pdev->port->ieee1284; pp->state.mode = info->mode; pp->state.phase = info->phase; info->mode = pp->saved_state.mode; info->phase = pp->saved_state.phase; |
783ea44db
|
724 |
parport_release(pp->pdev); |
1da177e4c
|
725 |
if (compat_negot != 1) { |
81fc401e4
|
726 |
pr_debug(CHRDEV "%x: released pardevice " |
1da177e4c
|
727 728 729 730 731 732 |
"because user-space forgot ", minor); } } if (pp->pdev) { |
783ea44db
|
733 |
parport_unregister_device(pp->pdev); |
9a69645dd
|
734 |
ida_simple_remove(&ida_index, pp->index); |
1da177e4c
|
735 |
pp->pdev = NULL; |
81fc401e4
|
736 737 |
pr_debug(CHRDEV "%x: unregistered pardevice ", minor); |
1da177e4c
|
738 |
} |
783ea44db
|
739 |
kfree(pp); |
1da177e4c
|
740 741 742 743 744 |
return 0; } /* No kernel lock held - fine */ |
afc9a42b7
|
745 |
static __poll_t pp_poll(struct file *file, poll_table *wait) |
1da177e4c
|
746 747 |
{ struct pp_struct *pp = file->private_data; |
afc9a42b7
|
748 |
__poll_t mask = 0; |
1da177e4c
|
749 |
|
783ea44db
|
750 751 |
poll_wait(file, &pp->irq_wait, wait); if (atomic_read(&pp->irqc)) |
a9a08845e
|
752 |
mask |= EPOLLIN | EPOLLRDNORM; |
1da177e4c
|
753 754 755 |
return mask; } |
ca8eca688
|
756 |
static struct class *ppdev_class; |
1da177e4c
|
757 |
|
62322d255
|
758 |
static const struct file_operations pp_fops = { |
1da177e4c
|
759 760 761 762 763 |
.owner = THIS_MODULE, .llseek = no_llseek, .read = pp_read, .write = pp_write, .poll = pp_poll, |
6d535d3e6
|
764 |
.unlocked_ioctl = pp_ioctl, |
17a3596f2
|
765 766 767 |
#ifdef CONFIG_COMPAT .compat_ioctl = pp_compat_ioctl, #endif |
1da177e4c
|
768 769 770 771 772 773 |
.open = pp_open, .release = pp_release, }; static void pp_attach(struct parport *port) { |
dd5c472a6
|
774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 |
struct device *ret; if (devices[port->number]) return; ret = device_create(ppdev_class, port->dev, MKDEV(PP_MAJOR, port->number), NULL, "parport%d", port->number); if (IS_ERR(ret)) { pr_err("Failed to create device parport%d ", port->number); return; } devices[port->number] = ret; |
1da177e4c
|
789 790 791 792 |
} static void pp_detach(struct parport *port) { |
dd5c472a6
|
793 794 |
if (!devices[port->number]) return; |
04880edae
|
795 |
device_destroy(ppdev_class, MKDEV(PP_MAJOR, port->number)); |
dd5c472a6
|
796 |
devices[port->number] = NULL; |
1da177e4c
|
797 |
} |
8b7d3a9d9
|
798 799 800 801 802 803 804 805 806 807 |
static int pp_probe(struct pardevice *par_dev) { struct device_driver *drv = par_dev->dev.driver; int len = strlen(drv->name); if (strncmp(par_dev->name, drv->name, len)) return -ENODEV; return 0; } |
1da177e4c
|
808 809 |
static struct parport_driver pp_driver = { .name = CHRDEV, |
8b7d3a9d9
|
810 811 |
.probe = pp_probe, .match_port = pp_attach, |
1da177e4c
|
812 |
.detach = pp_detach, |
8b7d3a9d9
|
813 |
.devmodel = true, |
1da177e4c
|
814 |
}; |
783ea44db
|
815 |
static int __init ppdev_init(void) |
1da177e4c
|
816 |
{ |
8ab5e4c15
|
817 |
int err = 0; |
1da177e4c
|
818 |
|
783ea44db
|
819 |
if (register_chrdev(PP_MAJOR, CHRDEV, &pp_fops)) { |
826a4c657
|
820 821 |
pr_warn(CHRDEV ": unable to get major %d ", PP_MAJOR); |
1da177e4c
|
822 823 |
return -EIO; } |
ca8eca688
|
824 |
ppdev_class = class_create(THIS_MODULE, CHRDEV); |
1da177e4c
|
825 826 827 828 |
if (IS_ERR(ppdev_class)) { err = PTR_ERR(ppdev_class); goto out_chrdev; } |
9a32bb39d
|
829 830 |
err = parport_register_driver(&pp_driver); if (err < 0) { |
826a4c657
|
831 832 |
pr_warn(CHRDEV ": unable to register with parport "); |
1da177e4c
|
833 834 |
goto out_class; } |
826a4c657
|
835 836 |
pr_info(PP_VERSION " "); |
1da177e4c
|
837 838 839 |
goto out; out_class: |
ca8eca688
|
840 |
class_destroy(ppdev_class); |
1da177e4c
|
841 842 843 844 845 |
out_chrdev: unregister_chrdev(PP_MAJOR, CHRDEV); out: return err; } |
783ea44db
|
846 |
static void __exit ppdev_cleanup(void) |
1da177e4c
|
847 |
{ |
1da177e4c
|
848 |
/* Clean up all parport stuff */ |
1da177e4c
|
849 |
parport_unregister_driver(&pp_driver); |
ca8eca688
|
850 |
class_destroy(ppdev_class); |
783ea44db
|
851 |
unregister_chrdev(PP_MAJOR, CHRDEV); |
1da177e4c
|
852 853 854 855 856 857 858 |
} module_init(ppdev_init); module_exit(ppdev_cleanup); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(PP_MAJOR); |