diff options
author | Stefani Seibold <stefani@seibold.net> | 2009-12-21 17:37:26 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-22 17:17:55 -0500 |
commit | 45465487897a1c6d508b14b904dc5777f7ec7e04 (patch) | |
tree | 935c8dae68dc793ff2f795d57cf027531475cd53 /drivers/platform/x86/sony-laptop.c | |
parent | 2ec91eec47f713e3d158ba5b28a24a85a2cf3650 (diff) |
kfifo: move struct kfifo in place
This is a new generic kernel FIFO implementation.
The current kernel fifo API is not very widely used, because it has to
many constrains. Only 17 files in the current 2.6.31-rc5 used it.
FIFO's are like list's a very basic thing and a kfifo API which handles
the most use case would save a lot of development time and memory
resources.
I think this are the reasons why kfifo is not in use:
- The API is to simple, important functions are missing
- A fifo can be only allocated dynamically
- There is a requirement of a spinlock whether you need it or not
- There is no support for data records inside a fifo
So I decided to extend the kfifo in a more generic way without blowing up
the API to much. The new API has the following benefits:
- Generic usage: For kernel internal use and/or device driver.
- Provide an API for the most use case.
- Slim API: The whole API provides 25 functions.
- Linux style habit.
- DECLARE_KFIFO, DEFINE_KFIFO and INIT_KFIFO Macros
- Direct copy_to_user from the fifo and copy_from_user into the fifo.
- The kfifo itself is an in place member of the using data structure, this save an
indirection access and does not waste the kernel allocator.
- Lockless access: if only one reader and one writer is active on the fifo,
which is the common use case, no additional locking is necessary.
- Remove spinlock - give the user the freedom of choice what kind of locking to use if
one is required.
- Ability to handle records. Three type of records are supported:
- Variable length records between 0-255 bytes, with a record size
field of 1 bytes.
- Variable length records between 0-65535 bytes, with a record size
field of 2 bytes.
- Fixed size records, which no record size field.
- Preserve memory resource.
- Performance!
- Easy to use!
This patch:
Since most users want to have the kfifo as part of another object,
reorganize the code to allow including struct kfifo in another data
structure. This requires changing the kfifo_alloc and kfifo_init
prototypes so that we pass an existing kfifo pointer into them. This
patch changes the implementation and all existing users.
[akpm@linux-foundation.org: fix warning]
Signed-off-by: Stefani Seibold <stefani@seibold.net>
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
Acked-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Acked-by: Andi Kleen <ak@linux.intel.com>
Acked-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/platform/x86/sony-laptop.c')
-rw-r--r-- | drivers/platform/x86/sony-laptop.c | 46 |
1 files changed, 23 insertions, 23 deletions
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index 7a2cc8a5c975..04625a048e74 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c | |||
@@ -142,7 +142,7 @@ struct sony_laptop_input_s { | |||
142 | atomic_t users; | 142 | atomic_t users; |
143 | struct input_dev *jog_dev; | 143 | struct input_dev *jog_dev; |
144 | struct input_dev *key_dev; | 144 | struct input_dev *key_dev; |
145 | struct kfifo *fifo; | 145 | struct kfifo fifo; |
146 | spinlock_t fifo_lock; | 146 | spinlock_t fifo_lock; |
147 | struct workqueue_struct *wq; | 147 | struct workqueue_struct *wq; |
148 | }; | 148 | }; |
@@ -300,7 +300,7 @@ static void do_sony_laptop_release_key(struct work_struct *work) | |||
300 | { | 300 | { |
301 | struct sony_laptop_keypress kp; | 301 | struct sony_laptop_keypress kp; |
302 | 302 | ||
303 | while (kfifo_get(sony_laptop_input.fifo, (unsigned char *)&kp, | 303 | while (kfifo_get(&sony_laptop_input.fifo, (unsigned char *)&kp, |
304 | sizeof(kp)) == sizeof(kp)) { | 304 | sizeof(kp)) == sizeof(kp)) { |
305 | msleep(10); | 305 | msleep(10); |
306 | input_report_key(kp.dev, kp.key, 0); | 306 | input_report_key(kp.dev, kp.key, 0); |
@@ -362,7 +362,7 @@ static void sony_laptop_report_input_event(u8 event) | |||
362 | /* we emit the scancode so we can always remap the key */ | 362 | /* we emit the scancode so we can always remap the key */ |
363 | input_event(kp.dev, EV_MSC, MSC_SCAN, event); | 363 | input_event(kp.dev, EV_MSC, MSC_SCAN, event); |
364 | input_sync(kp.dev); | 364 | input_sync(kp.dev); |
365 | kfifo_put(sony_laptop_input.fifo, | 365 | kfifo_put(&sony_laptop_input.fifo, |
366 | (unsigned char *)&kp, sizeof(kp)); | 366 | (unsigned char *)&kp, sizeof(kp)); |
367 | 367 | ||
368 | if (!work_pending(&sony_laptop_release_key_work)) | 368 | if (!work_pending(&sony_laptop_release_key_work)) |
@@ -385,12 +385,11 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device) | |||
385 | 385 | ||
386 | /* kfifo */ | 386 | /* kfifo */ |
387 | spin_lock_init(&sony_laptop_input.fifo_lock); | 387 | spin_lock_init(&sony_laptop_input.fifo_lock); |
388 | sony_laptop_input.fifo = | 388 | error = |
389 | kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, | 389 | kfifo_alloc(&sony_laptop_input.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, |
390 | &sony_laptop_input.fifo_lock); | 390 | &sony_laptop_input.fifo_lock); |
391 | if (IS_ERR(sony_laptop_input.fifo)) { | 391 | if (error) { |
392 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); | 392 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); |
393 | error = PTR_ERR(sony_laptop_input.fifo); | ||
394 | goto err_dec_users; | 393 | goto err_dec_users; |
395 | } | 394 | } |
396 | 395 | ||
@@ -474,7 +473,7 @@ err_destroy_wq: | |||
474 | destroy_workqueue(sony_laptop_input.wq); | 473 | destroy_workqueue(sony_laptop_input.wq); |
475 | 474 | ||
476 | err_free_kfifo: | 475 | err_free_kfifo: |
477 | kfifo_free(sony_laptop_input.fifo); | 476 | kfifo_free(&sony_laptop_input.fifo); |
478 | 477 | ||
479 | err_dec_users: | 478 | err_dec_users: |
480 | atomic_dec(&sony_laptop_input.users); | 479 | atomic_dec(&sony_laptop_input.users); |
@@ -500,7 +499,7 @@ static void sony_laptop_remove_input(void) | |||
500 | } | 499 | } |
501 | 500 | ||
502 | destroy_workqueue(sony_laptop_input.wq); | 501 | destroy_workqueue(sony_laptop_input.wq); |
503 | kfifo_free(sony_laptop_input.fifo); | 502 | kfifo_free(&sony_laptop_input.fifo); |
504 | } | 503 | } |
505 | 504 | ||
506 | /*********** Platform Device ***********/ | 505 | /*********** Platform Device ***********/ |
@@ -2079,7 +2078,7 @@ static struct attribute_group spic_attribute_group = { | |||
2079 | 2078 | ||
2080 | struct sonypi_compat_s { | 2079 | struct sonypi_compat_s { |
2081 | struct fasync_struct *fifo_async; | 2080 | struct fasync_struct *fifo_async; |
2082 | struct kfifo *fifo; | 2081 | struct kfifo fifo; |
2083 | spinlock_t fifo_lock; | 2082 | spinlock_t fifo_lock; |
2084 | wait_queue_head_t fifo_proc_list; | 2083 | wait_queue_head_t fifo_proc_list; |
2085 | atomic_t open_count; | 2084 | atomic_t open_count; |
@@ -2104,12 +2103,12 @@ static int sonypi_misc_open(struct inode *inode, struct file *file) | |||
2104 | /* Flush input queue on first open */ | 2103 | /* Flush input queue on first open */ |
2105 | unsigned long flags; | 2104 | unsigned long flags; |
2106 | 2105 | ||
2107 | spin_lock_irqsave(sonypi_compat.fifo->lock, flags); | 2106 | spin_lock_irqsave(&sonypi_compat.fifo_lock, flags); |
2108 | 2107 | ||
2109 | if (atomic_inc_return(&sonypi_compat.open_count) == 1) | 2108 | if (atomic_inc_return(&sonypi_compat.open_count) == 1) |
2110 | __kfifo_reset(sonypi_compat.fifo); | 2109 | __kfifo_reset(&sonypi_compat.fifo); |
2111 | 2110 | ||
2112 | spin_unlock_irqrestore(sonypi_compat.fifo->lock, flags); | 2111 | spin_unlock_irqrestore(&sonypi_compat.fifo_lock, flags); |
2113 | 2112 | ||
2114 | return 0; | 2113 | return 0; |
2115 | } | 2114 | } |
@@ -2120,17 +2119,17 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf, | |||
2120 | ssize_t ret; | 2119 | ssize_t ret; |
2121 | unsigned char c; | 2120 | unsigned char c; |
2122 | 2121 | ||
2123 | if ((kfifo_len(sonypi_compat.fifo) == 0) && | 2122 | if ((kfifo_len(&sonypi_compat.fifo) == 0) && |
2124 | (file->f_flags & O_NONBLOCK)) | 2123 | (file->f_flags & O_NONBLOCK)) |
2125 | return -EAGAIN; | 2124 | return -EAGAIN; |
2126 | 2125 | ||
2127 | ret = wait_event_interruptible(sonypi_compat.fifo_proc_list, | 2126 | ret = wait_event_interruptible(sonypi_compat.fifo_proc_list, |
2128 | kfifo_len(sonypi_compat.fifo) != 0); | 2127 | kfifo_len(&sonypi_compat.fifo) != 0); |
2129 | if (ret) | 2128 | if (ret) |
2130 | return ret; | 2129 | return ret; |
2131 | 2130 | ||
2132 | while (ret < count && | 2131 | while (ret < count && |
2133 | (kfifo_get(sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) { | 2132 | (kfifo_get(&sonypi_compat.fifo, &c, sizeof(c)) == sizeof(c))) { |
2134 | if (put_user(c, buf++)) | 2133 | if (put_user(c, buf++)) |
2135 | return -EFAULT; | 2134 | return -EFAULT; |
2136 | ret++; | 2135 | ret++; |
@@ -2147,7 +2146,7 @@ static ssize_t sonypi_misc_read(struct file *file, char __user *buf, | |||
2147 | static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait) | 2146 | static unsigned int sonypi_misc_poll(struct file *file, poll_table *wait) |
2148 | { | 2147 | { |
2149 | poll_wait(file, &sonypi_compat.fifo_proc_list, wait); | 2148 | poll_wait(file, &sonypi_compat.fifo_proc_list, wait); |
2150 | if (kfifo_len(sonypi_compat.fifo)) | 2149 | if (kfifo_len(&sonypi_compat.fifo)) |
2151 | return POLLIN | POLLRDNORM; | 2150 | return POLLIN | POLLRDNORM; |
2152 | return 0; | 2151 | return 0; |
2153 | } | 2152 | } |
@@ -2309,7 +2308,7 @@ static struct miscdevice sonypi_misc_device = { | |||
2309 | 2308 | ||
2310 | static void sonypi_compat_report_event(u8 event) | 2309 | static void sonypi_compat_report_event(u8 event) |
2311 | { | 2310 | { |
2312 | kfifo_put(sonypi_compat.fifo, (unsigned char *)&event, sizeof(event)); | 2311 | kfifo_put(&sonypi_compat.fifo, (unsigned char *)&event, sizeof(event)); |
2313 | kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN); | 2312 | kill_fasync(&sonypi_compat.fifo_async, SIGIO, POLL_IN); |
2314 | wake_up_interruptible(&sonypi_compat.fifo_proc_list); | 2313 | wake_up_interruptible(&sonypi_compat.fifo_proc_list); |
2315 | } | 2314 | } |
@@ -2319,11 +2318,12 @@ static int sonypi_compat_init(void) | |||
2319 | int error; | 2318 | int error; |
2320 | 2319 | ||
2321 | spin_lock_init(&sonypi_compat.fifo_lock); | 2320 | spin_lock_init(&sonypi_compat.fifo_lock); |
2322 | sonypi_compat.fifo = kfifo_alloc(SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, | 2321 | error = |
2322 | kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL, | ||
2323 | &sonypi_compat.fifo_lock); | 2323 | &sonypi_compat.fifo_lock); |
2324 | if (IS_ERR(sonypi_compat.fifo)) { | 2324 | if (error) { |
2325 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); | 2325 | printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); |
2326 | return PTR_ERR(sonypi_compat.fifo); | 2326 | return error; |
2327 | } | 2327 | } |
2328 | 2328 | ||
2329 | init_waitqueue_head(&sonypi_compat.fifo_proc_list); | 2329 | init_waitqueue_head(&sonypi_compat.fifo_proc_list); |
@@ -2342,14 +2342,14 @@ static int sonypi_compat_init(void) | |||
2342 | return 0; | 2342 | return 0; |
2343 | 2343 | ||
2344 | err_free_kfifo: | 2344 | err_free_kfifo: |
2345 | kfifo_free(sonypi_compat.fifo); | 2345 | kfifo_free(&sonypi_compat.fifo); |
2346 | return error; | 2346 | return error; |
2347 | } | 2347 | } |
2348 | 2348 | ||
2349 | static void sonypi_compat_exit(void) | 2349 | static void sonypi_compat_exit(void) |
2350 | { | 2350 | { |
2351 | misc_deregister(&sonypi_misc_device); | 2351 | misc_deregister(&sonypi_misc_device); |
2352 | kfifo_free(sonypi_compat.fifo); | 2352 | kfifo_free(&sonypi_compat.fifo); |
2353 | } | 2353 | } |
2354 | #else | 2354 | #else |
2355 | static int sonypi_compat_init(void) { return 0; } | 2355 | static int sonypi_compat_init(void) { return 0; } |