1 /* linux/drivers/media/video/samsung/fimg2d/fimg2d_ctx.c
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
6 * Samsung Graphics 2D driver
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/slab.h>
14 #include <linux/sched.h>
15 #include <asm/uaccess.h>
16 #include <plat/fimg2d.h>
21 * fimg2d_match_closed - [GENERIC] compare if closed
23 * @data: closed value to be compared
25 inline int fimg2d_match_closed(struct fimg2d_context *ctx, void *data)
27 return (atomic_read(&ctx->closed) == (int)data);
31 * fimg2d_enqueue - [GENERIC] add an item to queue
32 * @info: controller info
33 * @node: list_head of struct to be added
34 * @q: list_head of destination queue
36 inline void fimg2d_enqueue(struct fimg2d_control *info,
37 struct list_head *node, struct list_head *q)
39 list_add_tail(node, q);
43 * fimg2d_dequeue - [GENERIC] remove an item from queue
44 * @info: controller info
45 * @node: list_head of struct to be removed
47 inline void fimg2d_dequeue(struct fimg2d_control *info, struct list_head *node)
53 * fimg2d_queue_is_empty - [GENERIC] check if queue is empty
54 * @q: queue to be checked
56 inline int fimg2d_queue_is_empty(struct list_head *q)
62 * fimg2d_get_first_region - [GENERIC] return first entry of region queue
65 inline struct fimg2d_region *fimg2d_get_first_region(struct fimg2d_context *ctx)
67 if (list_empty(&ctx->reg_q))
70 return list_first_entry(&ctx->reg_q, struct fimg2d_region, node);
74 * fimg2d_find_context - [GENERIC] find a context
75 * @info: controller info
76 * @data: id or status to be used for comparing
77 * @match: function pointer to compare
79 struct fimg2d_context *
80 fimg2d_find_context(struct fimg2d_control *info, void *data,
81 int (*match)(struct fimg2d_context *ctx, void *data))
83 struct fimg2d_context *ctx;
87 list_for_each_entry(ctx, &info->ctx_q, node) {
88 if (match(ctx, data)) {
94 return (found ? ctx : NULL);
98 * fimg2d_set_context - [GENERIC] configure a context
99 * @info: controller info
101 * @c: context provided by user
103 * This function performs below:
104 * 1) copy user data to kernel space
105 * 2) decode rendering type
106 * 3) initialize list_head and context queue
108 int fimg2d_set_context(struct fimg2d_control *info, struct fimg2d_context *ctx,
109 struct fimg2d_user_context __user *c)
111 fimg2d_debug("context: %p\n", ctx);
114 atomic_set(&ctx->closed, 0);
117 memset(&ctx->src, 0, sizeof(ctx->src));
118 memset(&ctx->dst, 0, sizeof(ctx->dst));
120 /* copy src, dst and param info: not needed if NULL */
121 if (c->src && copy_from_user(&ctx->src, c->src, sizeof(ctx->src)))
124 if (c->dst && copy_from_user(&ctx->dst, c->dst, sizeof(ctx->dst)))
127 if (c->param && copy_from_user(&ctx->param, c->param, sizeof(ctx->param)))
133 * 2) configure misc values such as 3rd opr and alpha if needed
135 ctx->rop = info->decode(ctx);
139 /* initialize master queue node and region queue */
140 INIT_LIST_HEAD(&ctx->reg_q);
142 /* clear node count */
143 atomic_set(&ctx->nreg, 0);
148 int fimg2d_update_context(struct fimg2d_control *info, struct fimg2d_context *ctx,
149 struct fimg2d_param *p)
151 fimg2d_debug("context: %p\n", ctx);
153 memcpy(&ctx->param, p, sizeof(ctx->param));
155 ctx->rop = info->decode(ctx);
163 * fimg2d_set_region - [INTERNAL] configure a region
164 * @reg: region to be configured
165 * @r: region provided by user
167 static int fimg2d_set_region(struct fimg2d_region *reg,
168 struct fimg2d_user_region __user *r)
170 /* initialize node for region queue */
171 INIT_LIST_HEAD(®->node);
173 /* update region info */
174 if (r->src && copy_from_user(®->src, r->src, sizeof(reg->src)))
177 if (r->dst && copy_from_user(®->dst, r->dst, sizeof(reg->dst)))
180 if (r->dst_clip && copy_from_user(®->dst_clip, r->dst_clip, sizeof(reg->dst_clip)))
183 /* clip region defined */
191 * fimg2d_add_region - [GENERIC] add a new region to existing context
192 * @info: controller info
194 * @r: user passed region
196 int fimg2d_add_region(struct fimg2d_control *info, struct fimg2d_context *ctx,
197 struct fimg2d_user_region __user *r)
199 struct fimg2d_region *reg;
202 fimg2d_debug("context: %p\n", ctx);
204 if (atomic_read(&ctx->closed)) {
205 printk(KERN_ERR "closed: not permitted to add region\n");
209 reg = kzalloc(sizeof(*reg), GFP_KERNEL);
211 printk(KERN_ERR "failed to create region header\n");
215 /* set region info */
216 ret = fimg2d_set_region(reg, r);
218 printk(KERN_ERR "failed to set region info\n");
223 /* add to region queue */
224 fimg2d_enqueue(info, ®->node, &ctx->reg_q);
226 /* increase node count */
227 atomic_inc(&ctx->nreg);
233 * fimg2d_close_bitblt - [GENERIC] close context
234 * @info: controller info
237 int fimg2d_close_bitblt(struct fimg2d_control *info, struct fimg2d_context *ctx)
239 fimg2d_debug("context: %p\n", ctx);
241 spin_lock(&info->lock);
242 atomic_set(&ctx->closed, 1);
243 spin_unlock(&info->lock);