blob: 7e256848d29a3d765778cae87575aa423caf7c89 [file] [log] [blame]
Jordan Crouse29f66af2011-11-17 13:39:20 -07001/* Copyright (c) 2011, Code Aurora Forum. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/fb.h>
14#include <linux/slab.h>
15#include <linux/module.h>
16#include <linux/list.h>
17#include <linux/file.h>
18#include <linux/sched.h>
19#include <linux/fs.h>
20#include <linux/wait.h>
21#include <linux/uaccess.h>
22#include <linux/anon_inodes.h>
23#include <linux/miscdevice.h>
24#include <linux/genlock.h>
25
26/* Lock states - can either be unlocked, held as an exclusive write lock or a
27 * shared read lock
28 */
29
30#define _UNLOCKED 0
31#define _RDLOCK GENLOCK_RDLOCK
32#define _WRLOCK GENLOCK_WRLOCK
33
Naomi Luisb558aed2011-12-12 12:07:48 -080034#define GENLOCK_LOG_ERR(fmt, args...) \
35pr_err("genlock: %s: " fmt, __func__, ##args)
36
Jordan Crouse29f66af2011-11-17 13:39:20 -070037struct genlock {
38 struct list_head active; /* List of handles holding lock */
39 spinlock_t lock; /* Spinlock to protect the lock internals */
40 wait_queue_head_t queue; /* Holding pen for processes pending lock */
41 struct file *file; /* File structure for exported lock */
42 int state; /* Current state of the lock */
Jordan Crouse4a2879b2011-12-01 11:52:59 -070043 struct kref refcount;
Jordan Crouse29f66af2011-11-17 13:39:20 -070044};
45
46struct genlock_handle {
47 struct genlock *lock; /* Lock currently attached to the handle */
48 struct list_head entry; /* List node for attaching to a lock */
49 struct file *file; /* File structure associated with handle */
50 int active; /* Number of times the active lock has been
51 taken */
52};
53
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070054/*
55 * Create a spinlock to protect against a race condition when a lock gets
56 * released while another process tries to attach it
57 */
58
59static DEFINE_SPINLOCK(genlock_file_lock);
60
Jordan Crouse4a2879b2011-12-01 11:52:59 -070061static void genlock_destroy(struct kref *kref)
62{
63 struct genlock *lock = container_of(kref, struct genlock,
64 refcount);
65
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070066 /*
67 * Clear the private data for the file descriptor in case the fd is
68 * still active after the lock gets released
69 */
70
71 spin_lock(&genlock_file_lock);
72 if (lock->file)
73 lock->file->private_data = NULL;
74 spin_unlock(&genlock_file_lock);
75
Jordan Crouse4a2879b2011-12-01 11:52:59 -070076 kfree(lock);
77}
78
Jordan Crouse29f66af2011-11-17 13:39:20 -070079/*
80 * Release the genlock object. Called when all the references to
81 * the genlock file descriptor are released
82 */
83
84static int genlock_release(struct inode *inodep, struct file *file)
85{
Jordan Crouse03fbfbc2011-12-16 14:28:28 -070086 struct genlock *lock = file->private_data;
87 /*
88 * Clear the refrence back to this file structure to avoid
89 * somehow reusing the lock after the file has been destroyed
90 */
91
92 if (lock)
93 lock->file = NULL;
94
Jordan Crouse29f66af2011-11-17 13:39:20 -070095 return 0;
96}
97
98static const struct file_operations genlock_fops = {
99 .release = genlock_release,
100};
101
102/**
103 * genlock_create_lock - Create a new lock
104 * @handle - genlock handle to attach the lock to
105 *
106 * Returns: a pointer to the genlock
107 */
108
109struct genlock *genlock_create_lock(struct genlock_handle *handle)
110{
111 struct genlock *lock;
112
Naomi Luisb558aed2011-12-12 12:07:48 -0800113 if (handle->lock != NULL) {
114 GENLOCK_LOG_ERR("Handle already has a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700115 return ERR_PTR(-EINVAL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800116 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700117
118 lock = kzalloc(sizeof(*lock), GFP_KERNEL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800119 if (lock == NULL) {
120 GENLOCK_LOG_ERR("Unable to allocate memory for a lock\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700121 return ERR_PTR(-ENOMEM);
Naomi Luisb558aed2011-12-12 12:07:48 -0800122 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700123
124 INIT_LIST_HEAD(&lock->active);
125 init_waitqueue_head(&lock->queue);
126 spin_lock_init(&lock->lock);
127
128 lock->state = _UNLOCKED;
129
130 /*
131 * Create an anonyonmous inode for the object that can exported to
132 * other processes
133 */
134
135 lock->file = anon_inode_getfile("genlock", &genlock_fops,
136 lock, O_RDWR);
137
138 /* Attach the new lock to the handle */
139 handle->lock = lock;
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700140 kref_init(&lock->refcount);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700141
142 return lock;
143}
144EXPORT_SYMBOL(genlock_create_lock);
145
146/*
147 * Get a file descriptor reference to a lock suitable for sharing with
148 * other processes
149 */
150
151static int genlock_get_fd(struct genlock *lock)
152{
153 int ret;
154
Naomi Luisb558aed2011-12-12 12:07:48 -0800155 if (!lock->file) {
156 GENLOCK_LOG_ERR("No file attached to the lock\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700157 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800158 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700159
160 ret = get_unused_fd_flags(0);
161 if (ret < 0)
162 return ret;
163 fd_install(ret, lock->file);
164 return ret;
165}
166
167/**
168 * genlock_attach_lock - Attach an existing lock to a handle
169 * @handle - Pointer to a genlock handle to attach the lock to
170 * @fd - file descriptor for the exported lock
171 *
172 * Returns: A pointer to the attached lock structure
173 */
174
175struct genlock *genlock_attach_lock(struct genlock_handle *handle, int fd)
176{
177 struct file *file;
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700178 struct genlock *lock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700179
Naomi Luisb558aed2011-12-12 12:07:48 -0800180 if (handle->lock != NULL) {
181 GENLOCK_LOG_ERR("Handle already has a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700182 return ERR_PTR(-EINVAL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800183 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700184
185 file = fget(fd);
Naomi Luisb558aed2011-12-12 12:07:48 -0800186 if (file == NULL) {
187 GENLOCK_LOG_ERR("Bad file descriptor\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700188 return ERR_PTR(-EBADF);
Naomi Luisb558aed2011-12-12 12:07:48 -0800189 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700190
Jordan Crouse03fbfbc2011-12-16 14:28:28 -0700191 /*
192 * take a spinlock to avoid a race condition if the lock is
193 * released and then attached
194 */
195
196 spin_lock(&genlock_file_lock);
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700197 lock = file->private_data;
Jordan Crouse03fbfbc2011-12-16 14:28:28 -0700198 spin_unlock(&genlock_file_lock);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700199
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700200 fput(file);
201
Naomi Luisb558aed2011-12-12 12:07:48 -0800202 if (lock == NULL) {
203 GENLOCK_LOG_ERR("File descriptor is invalid\n");
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700204 return ERR_PTR(-EINVAL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800205 }
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700206
207 handle->lock = lock;
208 kref_get(&lock->refcount);
209
210 return lock;
Jordan Crouse29f66af2011-11-17 13:39:20 -0700211}
212EXPORT_SYMBOL(genlock_attach_lock);
213
214/* Helper function that returns 1 if the specified handle holds the lock */
215
216static int handle_has_lock(struct genlock *lock, struct genlock_handle *handle)
217{
218 struct genlock_handle *h;
219
220 list_for_each_entry(h, &lock->active, entry) {
221 if (h == handle)
222 return 1;
223 }
224
225 return 0;
226}
227
228/* If the lock just became available, signal the next entity waiting for it */
229
230static void _genlock_signal(struct genlock *lock)
231{
232 if (list_empty(&lock->active)) {
233 /* If the list is empty, then the lock is free */
234 lock->state = _UNLOCKED;
235 /* Wake up the first process sitting in the queue */
236 wake_up(&lock->queue);
237 }
238}
239
240/* Attempt to release the handle's ownership of the lock */
241
242static int _genlock_unlock(struct genlock *lock, struct genlock_handle *handle)
243{
244 int ret = -EINVAL;
245 unsigned long irqflags;
246
247 spin_lock_irqsave(&lock->lock, irqflags);
248
Naomi Luisb558aed2011-12-12 12:07:48 -0800249 if (lock->state == _UNLOCKED) {
250 GENLOCK_LOG_ERR("Trying to unlock an unlocked handle\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700251 goto done;
Naomi Luisb558aed2011-12-12 12:07:48 -0800252 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700253
254 /* Make sure this handle is an owner of the lock */
Naomi Luisb558aed2011-12-12 12:07:48 -0800255 if (!handle_has_lock(lock, handle)) {
256 GENLOCK_LOG_ERR("handle does not have lock attached to it\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700257 goto done;
Naomi Luisb558aed2011-12-12 12:07:48 -0800258 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700259 /* If the handle holds no more references to the lock then
260 release it (maybe) */
261
262 if (--handle->active == 0) {
263 list_del(&handle->entry);
264 _genlock_signal(lock);
265 }
266
267 ret = 0;
268
269done:
270 spin_unlock_irqrestore(&lock->lock, irqflags);
271 return ret;
272}
273
274/* Attempt to acquire the lock for the handle */
275
276static int _genlock_lock(struct genlock *lock, struct genlock_handle *handle,
277 int op, int flags, uint32_t timeout)
278{
279 unsigned long irqflags;
280 int ret = 0;
281 unsigned int ticks = msecs_to_jiffies(timeout);
282
283 spin_lock_irqsave(&lock->lock, irqflags);
284
285 /* Sanity check - no blocking locks in a debug context. Even if it
286 * succeed to not block, the mere idea is too dangerous to continue
287 */
288
289 if (in_interrupt() && !(flags & GENLOCK_NOBLOCK))
290 BUG();
291
292 /* Fast path - the lock is unlocked, so go do the needful */
293
294 if (lock->state == _UNLOCKED)
295 goto dolock;
296
297 if (handle_has_lock(lock, handle)) {
298
299 /*
300 * If the handle already holds the lock and the type matches,
301 * then just increment the active pointer. This allows the
302 * handle to do recursive locks
303 */
304
305 if (lock->state == op) {
306 handle->active++;
307 goto done;
308 }
309
310 /*
311 * If the handle holds a write lock then the owner can switch
312 * to a read lock if they want. Do the transition atomically
313 * then wake up any pending waiters in case they want a read
314 * lock too.
315 */
316
317 if (op == _RDLOCK && handle->active == 1) {
318 lock->state = _RDLOCK;
319 wake_up(&lock->queue);
320 goto done;
321 }
322
323 /*
324 * Otherwise the user tried to turn a read into a write, and we
325 * don't allow that.
326 */
Naomi Luisb558aed2011-12-12 12:07:48 -0800327 GENLOCK_LOG_ERR("Trying to upgrade a read lock to a write"
328 "lock\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700329 ret = -EINVAL;
330 goto done;
331 }
332
333 /*
334 * If we request a read and the lock is held by a read, then go
335 * ahead and share the lock
336 */
337
338 if (op == GENLOCK_RDLOCK && lock->state == _RDLOCK)
339 goto dolock;
340
341 /* Treat timeout 0 just like a NOBLOCK flag and return if the
342 lock cannot be aquired without blocking */
343
344 if (flags & GENLOCK_NOBLOCK || timeout == 0) {
345 ret = -EAGAIN;
346 goto done;
347 }
348
349 /* Wait while the lock remains in an incompatible state */
350
351 while (lock->state != _UNLOCKED) {
352 unsigned int elapsed;
353
354 spin_unlock_irqrestore(&lock->lock, irqflags);
355
356 elapsed = wait_event_interruptible_timeout(lock->queue,
357 lock->state == _UNLOCKED, ticks);
358
359 spin_lock_irqsave(&lock->lock, irqflags);
360
361 if (elapsed <= 0) {
362 ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
363 goto done;
364 }
365
366 ticks = elapsed;
367 }
368
369dolock:
370 /* We can now get the lock, add ourselves to the list of owners */
371
372 list_add_tail(&handle->entry, &lock->active);
373 lock->state = op;
374 handle->active = 1;
375
376done:
377 spin_unlock_irqrestore(&lock->lock, irqflags);
378 return ret;
379
380}
381
382/**
383 * genlock_lock - Acquire or release a lock
384 * @handle - pointer to the genlock handle that is requesting the lock
385 * @op - the operation to perform (RDLOCK, WRLOCK, UNLOCK)
386 * @flags - flags to control the operation
387 * @timeout - optional timeout to wait for the lock to come free
388 *
389 * Returns: 0 on success or error code on failure
390 */
391
392int genlock_lock(struct genlock_handle *handle, int op, int flags,
393 uint32_t timeout)
394{
395 struct genlock *lock = handle->lock;
396 int ret = 0;
397
Naomi Luisb558aed2011-12-12 12:07:48 -0800398 if (lock == NULL) {
399 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700400 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800401 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700402
403 switch (op) {
404 case GENLOCK_UNLOCK:
405 ret = _genlock_unlock(lock, handle);
406 break;
407 case GENLOCK_RDLOCK:
408 case GENLOCK_WRLOCK:
409 ret = _genlock_lock(lock, handle, op, flags, timeout);
410 break;
411 default:
Naomi Luisb558aed2011-12-12 12:07:48 -0800412 GENLOCK_LOG_ERR("Invalid lock operation\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700413 ret = -EINVAL;
414 break;
415 }
416
417 return ret;
418}
419EXPORT_SYMBOL(genlock_lock);
420
421/**
422 * genlock_wait - Wait for the lock to be released
423 * @handle - pointer to the genlock handle that is waiting for the lock
424 * @timeout - optional timeout to wait for the lock to get released
425 */
426
427int genlock_wait(struct genlock_handle *handle, uint32_t timeout)
428{
429 struct genlock *lock = handle->lock;
430 unsigned long irqflags;
431 int ret = 0;
432 unsigned int ticks = msecs_to_jiffies(timeout);
433
Naomi Luisb558aed2011-12-12 12:07:48 -0800434 if (lock == NULL) {
435 GENLOCK_LOG_ERR("Handle does not have a lock attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700436 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800437 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700438
439 spin_lock_irqsave(&lock->lock, irqflags);
440
441 /*
442 * if timeout is 0 and the lock is already unlocked, then success
443 * otherwise return -EAGAIN
444 */
445
446 if (timeout == 0) {
447 ret = (lock->state == _UNLOCKED) ? 0 : -EAGAIN;
448 goto done;
449 }
450
451 while (lock->state != _UNLOCKED) {
452 unsigned int elapsed;
453
454 spin_unlock_irqrestore(&lock->lock, irqflags);
455
456 elapsed = wait_event_interruptible_timeout(lock->queue,
457 lock->state == _UNLOCKED, ticks);
458
459 spin_lock_irqsave(&lock->lock, irqflags);
460
461 if (elapsed <= 0) {
462 ret = (elapsed < 0) ? elapsed : -ETIMEDOUT;
463 break;
464 }
465
466 ticks = elapsed;
467 }
468
469done:
470 spin_unlock_irqrestore(&lock->lock, irqflags);
471 return ret;
472}
473
474/**
475 * genlock_release_lock - Release a lock attached to a handle
476 * @handle - Pointer to the handle holding the lock
477 */
478
479void genlock_release_lock(struct genlock_handle *handle)
480{
481 unsigned long flags;
482
483 if (handle == NULL || handle->lock == NULL)
484 return;
485
486 spin_lock_irqsave(&handle->lock->lock, flags);
487
488 /* If the handle is holding the lock, then force it closed */
489
490 if (handle_has_lock(handle->lock, handle)) {
491 list_del(&handle->entry);
492 _genlock_signal(handle->lock);
493 }
494 spin_unlock_irqrestore(&handle->lock->lock, flags);
495
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700496 kref_put(&handle->lock->refcount, genlock_destroy);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700497 handle->lock = NULL;
498 handle->active = 0;
499}
500EXPORT_SYMBOL(genlock_release_lock);
501
502/*
503 * Release function called when all references to a handle are released
504 */
505
506static int genlock_handle_release(struct inode *inodep, struct file *file)
507{
508 struct genlock_handle *handle = file->private_data;
509
510 genlock_release_lock(handle);
511 kfree(handle);
512
513 return 0;
514}
515
516static const struct file_operations genlock_handle_fops = {
517 .release = genlock_handle_release
518};
519
520/*
521 * Allocate a new genlock handle
522 */
523
524static struct genlock_handle *_genlock_get_handle(void)
525{
526 struct genlock_handle *handle = kzalloc(sizeof(*handle), GFP_KERNEL);
Naomi Luisb558aed2011-12-12 12:07:48 -0800527 if (handle == NULL) {
528 GENLOCK_LOG_ERR("Unable to allocate memory for the handle\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700529 return ERR_PTR(-ENOMEM);
Naomi Luisb558aed2011-12-12 12:07:48 -0800530 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700531
532 return handle;
533}
534
535/**
536 * genlock_get_handle - Create a new genlock handle
537 *
538 * Returns: A pointer to a new genlock handle
539 */
540
541struct genlock_handle *genlock_get_handle(void)
542{
543 struct genlock_handle *handle = _genlock_get_handle();
544 if (IS_ERR(handle))
545 return handle;
546
547 handle->file = anon_inode_getfile("genlock-handle",
548 &genlock_handle_fops, handle, O_RDWR);
549
550 return handle;
551}
552EXPORT_SYMBOL(genlock_get_handle);
553
554/**
555 * genlock_put_handle - release a reference to a genlock handle
556 * @handle - A pointer to the handle to release
557 */
558
559void genlock_put_handle(struct genlock_handle *handle)
560{
561 if (handle)
562 fput(handle->file);
563}
564EXPORT_SYMBOL(genlock_put_handle);
565
566/**
567 * genlock_get_handle_fd - Get a handle reference from a file descriptor
568 * @fd - The file descriptor for a genlock handle
569 */
570
571struct genlock_handle *genlock_get_handle_fd(int fd)
572{
573 struct file *file = fget(fd);
574
575 if (file == NULL)
576 return ERR_PTR(-EINVAL);
577
578 return file->private_data;
579}
580EXPORT_SYMBOL(genlock_get_handle_fd);
581
582#ifdef CONFIG_GENLOCK_MISCDEVICE
583
584static long genlock_dev_ioctl(struct file *filep, unsigned int cmd,
585 unsigned long arg)
586{
587 struct genlock_lock param;
588 struct genlock_handle *handle = filep->private_data;
589 struct genlock *lock;
590 int ret;
591
592 switch (cmd) {
593 case GENLOCK_IOC_NEW: {
594 lock = genlock_create_lock(handle);
595 if (IS_ERR(lock))
596 return PTR_ERR(lock);
597
598 return 0;
599 }
600 case GENLOCK_IOC_EXPORT: {
Naomi Luisb558aed2011-12-12 12:07:48 -0800601 if (handle->lock == NULL) {
602 GENLOCK_LOG_ERR("Handle does not have a lock"
603 "attached\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700604 return -EINVAL;
Naomi Luisb558aed2011-12-12 12:07:48 -0800605 }
Jordan Crouse29f66af2011-11-17 13:39:20 -0700606
607 ret = genlock_get_fd(handle->lock);
608 if (ret < 0)
609 return ret;
610
611 param.fd = ret;
612
613 if (copy_to_user((void __user *) arg, &param,
614 sizeof(param)))
615 return -EFAULT;
616
617 return 0;
618 }
619 case GENLOCK_IOC_ATTACH: {
620 if (copy_from_user(&param, (void __user *) arg,
621 sizeof(param)))
622 return -EFAULT;
623
624 lock = genlock_attach_lock(handle, param.fd);
625 if (IS_ERR(lock))
626 return PTR_ERR(lock);
627
628 return 0;
629 }
630 case GENLOCK_IOC_LOCK: {
631 if (copy_from_user(&param, (void __user *) arg,
632 sizeof(param)))
633 return -EFAULT;
634
635 return genlock_lock(handle, param.op, param.flags,
636 param.timeout);
637 }
638 case GENLOCK_IOC_WAIT: {
639 if (copy_from_user(&param, (void __user *) arg,
640 sizeof(param)))
641 return -EFAULT;
642
643 return genlock_wait(handle, param.timeout);
644 }
645 case GENLOCK_IOC_RELEASE: {
646 genlock_release_lock(handle);
647 return 0;
648 }
649 default:
Naomi Luisb558aed2011-12-12 12:07:48 -0800650 GENLOCK_LOG_ERR("Invalid ioctl\n");
Jordan Crouse29f66af2011-11-17 13:39:20 -0700651 return -EINVAL;
652 }
653}
654
655static int genlock_dev_release(struct inode *inodep, struct file *file)
656{
657 struct genlock_handle *handle = file->private_data;
658
Jordan Crouse4a2879b2011-12-01 11:52:59 -0700659 genlock_release_lock(handle);
660 kfree(handle);
Jordan Crouse29f66af2011-11-17 13:39:20 -0700661
662 return 0;
663}
664
665static int genlock_dev_open(struct inode *inodep, struct file *file)
666{
667 struct genlock_handle *handle = _genlock_get_handle();
668 if (IS_ERR(handle))
669 return PTR_ERR(handle);
670
671 handle->file = file;
672 file->private_data = handle;
673 return 0;
674}
675
676static const struct file_operations genlock_dev_fops = {
677 .open = genlock_dev_open,
678 .release = genlock_dev_release,
679 .unlocked_ioctl = genlock_dev_ioctl,
680};
681
682static struct miscdevice genlock_dev;
683
684static int genlock_dev_init(void)
685{
686 genlock_dev.minor = MISC_DYNAMIC_MINOR;
687 genlock_dev.name = "genlock";
688 genlock_dev.fops = &genlock_dev_fops;
689 genlock_dev.parent = NULL;
690
691 return misc_register(&genlock_dev);
692}
693
694static void genlock_dev_close(void)
695{
696 misc_deregister(&genlock_dev);
697}
698
699module_init(genlock_dev_init);
700module_exit(genlock_dev_close);
701
702#endif