rk312x lcdc: hwc layer test ok
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / rkfb_sysfs.c
1 /*
2  * linux/drivers/video/rockchip/rkfb-sysfs.c
3  *
4  * Copyright (C) 2012 Rockchip Corporation
5  * Author: yxj<yxj@rock-chips.com>
6  *
7  * Some code and ideas taken from
8  *drivers/video/omap2/omapfb/omapfb-sys.c
9  *driver by Tomi Valkeinen.
10  *
11  *
12  * This program is free software; you can redistribute it and/or modify it
13  * under the terms of the GNU General Public License version 2 as published by
14  * the Free Software Foundation.
15  *
16  * This program is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19  * more details.
20  *
21  * You should have received a copy of the GNU General Public License along with
22  * this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24
25 #include <linux/fb.h>
26 #include <linux/sysfs.h>
27 #include <linux/device.h>
28 #include <linux/uaccess.h>
29 #include <linux/platform_device.h>
30 #include <linux/kernel.h>
31 #include <linux/mm.h>
32 #include <asm/div64.h>
33 #include <linux/rk_screen.h>
34 #include <linux/rk_fb.h>
35
36 static ssize_t show_screen_info(struct device *dev,
37                                 struct device_attribute *attr, char *buf)
38 {
39         struct fb_info *fbi = dev_get_drvdata(dev);
40         struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par;
41         struct rk_screen *screen = dev_drv->cur_screen;
42         int fps;
43         u32 x = screen->mode.left_margin + screen->mode.right_margin +
44                 screen->mode.xres + screen->mode.hsync_len;
45         u32 y = screen->mode.upper_margin + screen->mode.lower_margin +
46                 screen->mode.yres + screen->mode.vsync_len;
47         u64 ft = (u64)x * y * (dev_drv->pixclock);
48
49         fps = div64_u64(1000000000000llu, ft);
50         return snprintf(buf, PAGE_SIZE, "xres:%d\nyres:%d\nfps:%d\n",
51                         screen->mode.xres, screen->mode.yres, fps);
52 }
53
54 static ssize_t show_disp_info(struct device *dev,
55                               struct device_attribute *attr, char *buf)
56 {
57         struct fb_info *fbi = dev_get_drvdata(dev);
58         struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par;
59         int win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id);
60
61         if (dev_drv->ops->get_disp_info)
62                 return dev_drv->ops->get_disp_info(dev_drv, buf, win_id);
63
64         return 0;
65 }
66
67 static ssize_t show_phys(struct device *dev,
68                          struct device_attribute *attr, char *buf)
69 {
70         struct fb_info *fbi = dev_get_drvdata(dev);
71
72         return snprintf(buf, PAGE_SIZE, "0x%lx-----0x%x\n",
73                         fbi->fix.smem_start, fbi->fix.smem_len);
74 }
75
76 static ssize_t show_virt(struct device *dev,
77                          struct device_attribute *attr, char *buf)
78 {
79         struct fb_info *fbi = dev_get_drvdata(dev);
80
81         return snprintf(buf, PAGE_SIZE, "0x%p-----0x%x\n",
82                         fbi->screen_base, fbi->fix.smem_len);
83 }
84
85 static ssize_t show_fb_state(struct device *dev,
86                              struct device_attribute *attr, char *buf)
87 {
88         struct fb_info *fbi = dev_get_drvdata(dev);
89         struct rk_lcdc_driver *dev_drv =
90             (struct rk_lcdc_driver *)fbi->par;
91         int win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id);
92         int state = dev_drv->ops->get_win_state(dev_drv, win_id);
93
94         return snprintf(buf, PAGE_SIZE, "%s\n", state ? "enabled" : "disabled");
95 }
96
97 static ssize_t show_dual_mode(struct device *dev,
98                               struct device_attribute *attr, char *buf)
99 {
100         struct fb_info *fbi = dev_get_drvdata(dev);
101         struct rk_fb *rk_fb = dev_get_drvdata(fbi->device);
102         int mode = rk_fb->disp_mode;
103
104         return snprintf(buf, PAGE_SIZE, "%d\n", mode);
105 }
106
107 static ssize_t set_fb_state(struct device *dev, struct device_attribute *attr,
108                             const char *buf, size_t count)
109 {
110         struct fb_info *fbi = dev_get_drvdata(dev);
111         struct rk_lcdc_driver *dev_drv =
112             (struct rk_lcdc_driver *)fbi->par;
113         int win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id);
114         int state;
115         int ret;
116
117         ret = kstrtoint(buf, 0, &state);
118         if (ret)
119                 return ret;
120         dev_drv->ops->open(dev_drv, win_id, state);
121         if (state) {
122                 dev_drv->ops->set_par(dev_drv, win_id);
123                 dev_drv->ops->pan_display(dev_drv, win_id);
124                 dev_drv->ops->cfg_done(dev_drv);
125         }
126         return count;
127 }
128
129 static ssize_t show_overlay(struct device *dev,
130                             struct device_attribute *attr, char *buf)
131 {
132         struct fb_info *fbi = dev_get_drvdata(dev);
133         struct rk_lcdc_driver *dev_drv =
134             (struct rk_lcdc_driver *)fbi->par;
135         int ovl;
136         ovl = dev_drv->ops->ovl_mgr(dev_drv, 0, 0);
137
138         if (ovl < 0)
139                 return ovl;
140
141         return snprintf(buf, PAGE_SIZE, "%s\n",
142                         ovl ? "win0 on the top of win1" :
143                         "win1 on the top of win0");
144 }
145
146 static ssize_t set_overlay(struct device *dev, struct device_attribute *attr,
147                            const char *buf, size_t count)
148 {
149         struct fb_info *fbi = dev_get_drvdata(dev);
150         struct rk_lcdc_driver *dev_drv =
151             (struct rk_lcdc_driver *)fbi->par;
152         int ovl;
153         int ret;
154
155         ret = kstrtoint(buf, 0, &ovl);
156         if (ret)
157                 return ret;
158
159         ret = dev_drv->ops->ovl_mgr(dev_drv, ovl, 1);
160         if (ret < 0)
161                 return ret;
162
163         return count;
164 }
165
166 static ssize_t show_fps(struct device *dev,
167                         struct device_attribute *attr, char *buf)
168 {
169         struct fb_info *fbi = dev_get_drvdata(dev);
170         struct rk_lcdc_driver *dev_drv =
171             (struct rk_lcdc_driver *)fbi->par;
172         int fps;
173
174         fps = dev_drv->ops->fps_mgr(dev_drv, 0, 0);
175         if (fps < 0)
176                 return fps;
177
178         return snprintf(buf, PAGE_SIZE, "fps:%d\n", fps);
179 }
180
181 static ssize_t set_fps(struct device *dev, struct device_attribute *attr,
182                        const char *buf, size_t count)
183 {
184         struct fb_info *fbi = dev_get_drvdata(dev);
185         struct rk_lcdc_driver *dev_drv =
186             (struct rk_lcdc_driver *)fbi->par;
187         int fps;
188         int ret;
189
190         ret = kstrtoint(buf, 0, &fps);
191         if (ret)
192                 return ret;
193         ret = dev_drv->ops->fps_mgr(dev_drv, fps, 1);
194         if (ret < 0)
195                 return ret;
196
197         return count;
198 }
199
200 static ssize_t show_fb_win_map(struct device *dev,
201                                struct device_attribute *attr, char *buf)
202 {
203         int ret;
204         struct fb_info *fbi = dev_get_drvdata(dev);
205         struct rk_lcdc_driver *dev_drv =
206             (struct rk_lcdc_driver *)fbi->par;
207
208         mutex_lock(&dev_drv->fb_win_id_mutex);
209         ret =
210             snprintf(buf, PAGE_SIZE, "fb0:win%d\nfb1:win%d\nfb2:win%d\n",
211                      dev_drv->fb0_win_id, dev_drv->fb1_win_id,
212                      dev_drv->fb2_win_id);
213         mutex_unlock(&dev_drv->fb_win_id_mutex);
214
215         return ret;
216 }
217
218 static ssize_t set_fb_win_map(struct device *dev, struct device_attribute *attr,
219                               const char *buf, size_t count)
220 {
221         struct fb_info *fbi = dev_get_drvdata(dev);
222         struct rk_lcdc_driver *dev_drv =
223             (struct rk_lcdc_driver *)fbi->par;
224         int order;
225         int ret;
226
227         ret = kstrtoint(buf, 0, &order);
228         if ((order != FB0_WIN2_FB1_WIN1_FB2_WIN0) &&
229             (order != FB0_WIN1_FB1_WIN2_FB2_WIN0) &&
230             (order != FB0_WIN2_FB1_WIN0_FB2_WIN1) &&
231             (order != FB0_WIN0_FB1_WIN2_FB2_WIN1) &&
232             (order != FB0_WIN0_FB1_WIN1_FB2_WIN2) &&
233             (order != FB0_WIN1_FB1_WIN0_FB2_WIN2)) {
234                 printk(KERN_ERR "un supported map\n"
235                        "you can use the following order:\n" "201:\n"
236                        "fb0-win1\n" "fb1-win0\n" "fb2-win2\n" "210:\n"
237                        "fb0-win0\n" "fb1-win1\n" "fb2-win2\n" "120:\n"
238                        "fb0-win0\n" "fb1-win2\n" "fb2-win1\n" "102:\n"
239                        "fb0-win2\n" "fb1-win0\n" "fb2-win1\n" "021:\n"
240                        "fb0-win1\n" "fb1-win2\n" "fb2-win0\n" "012:\n"
241                        "fb0-win2\n" "fb1-win1\n" "fb2-win0\n");
242                 return count;
243         } else {
244                 dev_drv->ops->fb_win_remap(dev_drv, order);
245         }
246
247         return count;
248 }
249
250 static ssize_t show_hwc_lut(struct device *dev,
251                             struct device_attribute *attr, char *buf)
252 {
253         return 0;
254 }
255
256 static ssize_t set_hwc_lut(struct device *dev, struct device_attribute *attr,
257                            const char *buf, size_t count)
258 {
259         int hwc_lut[256];
260         const char *start = buf;
261         int i = 256, temp;
262         int space_max;
263
264         struct fb_info *fbi = dev_get_drvdata(dev);
265         struct rk_lcdc_driver *dev_drv =
266             (struct rk_lcdc_driver *)fbi->par;
267
268         /*printk("count:%d\n>>%s\n\n",count,start);*/
269         for (i = 0; i < 256; i++) {
270                 space_max = 15; /*max space number 15*/
271                 temp = simple_strtoul(start, NULL, 16);
272                 hwc_lut[i] = temp;
273                 do {
274                         start++;
275                         space_max--;
276                 } while ((*start != ' ') && space_max);
277
278                 if (!space_max)
279                         break;
280                 else
281                         start++;
282         }
283 #if 0
284         for (i = 0; i < 16; i++) {
285                 for (j = 0; j < 16; j++)
286                         printk("0x%08x ", hwc_lut[i * 16 + j]);
287                 printk("\n");
288         }
289 #endif
290         if(dev_drv->ops->set_hwc_lut)
291                 dev_drv->ops->set_hwc_lut(dev_drv, hwc_lut, 1);
292
293         return count;
294 }
295
296 static ssize_t show_dsp_lut(struct device *dev,
297                             struct device_attribute *attr, char *buf)
298 {
299         return 0;
300 }
301
302 static ssize_t set_dsp_lut(struct device *dev, struct device_attribute *attr,
303                            const char *buf, size_t count)
304 {
305         int dsp_lut[256];
306         const char *start = buf;
307         int i = 256, temp;
308         int space_max = 10;
309
310         struct fb_info *fbi = dev_get_drvdata(dev);
311         struct rk_lcdc_driver *dev_drv =
312             (struct rk_lcdc_driver *)fbi->par;
313
314         for (i = 0; i < 256; i++) {
315                 temp = i;
316                 /*init by default value*/
317                 dsp_lut[i] = temp + (temp << 8) + (temp << 16);
318         }
319         /*printk("count:%d\n>>%s\n\n",count,start);*/
320         for (i = 0; i < 256; i++) {
321                 space_max = 10; /*max space number 10*/
322                 temp = simple_strtoul(start, NULL, 10);
323                 dsp_lut[i] = temp;
324                 do {
325                         start++;
326                         space_max--;
327                 } while ((*start != ' ') && space_max);
328
329                 if (!space_max)
330                         break;
331                 else
332                         start++;
333         }
334 #if 0
335         for (i = 0; i < 16; i++) {
336                 for (j = 0; j < 16; j++)
337                         printk("0x%08x ", dsp_lut[i * 16 + j]);
338                 printk("\n");
339         }
340 #endif
341         dev_drv->ops->set_dsp_lut(dev_drv, dsp_lut);
342
343         return count;
344 }
345
346 static ssize_t show_dsp_cabc(struct device *dev,
347                              struct device_attribute *attr, char *buf)
348 {
349         struct fb_info *fbi = dev_get_drvdata(dev);
350         struct rk_lcdc_driver *dev_drv =
351             (struct rk_lcdc_driver *)fbi->par;
352
353         return snprintf(buf, PAGE_SIZE, "cabc mode=%d\n",
354                 dev_drv->cabc_mode);
355         return 0;
356 }
357
358 static ssize_t set_dsp_cabc(struct device *dev, struct device_attribute *attr,
359                             const char *buf, size_t count)
360 {
361         struct fb_info *fbi = dev_get_drvdata(dev);
362         struct rk_lcdc_driver *dev_drv =
363             (struct rk_lcdc_driver *)fbi->par;
364         int ret, mode = 0;
365
366         ret = kstrtoint(buf, 0, &mode);
367         if (ret)
368                 return ret;
369
370         ret = dev_drv->ops->set_dsp_cabc(dev_drv, mode);
371         if (ret < 0)
372                 return ret;
373
374         return count;
375 }
376
377 static ssize_t show_dsp_bcsh(struct device *dev,
378                              struct device_attribute *attr, char *buf)
379 {
380         struct fb_info *fbi = dev_get_drvdata(dev);
381         struct rk_lcdc_driver *dev_drv =
382             (struct rk_lcdc_driver *)fbi->par;
383         int brightness, contrast, sat_con, sin_hue, cos_hue;
384
385         if (dev_drv->ops->get_dsp_bcsh_bcs) {
386                 brightness = dev_drv->ops->get_dsp_bcsh_bcs(dev_drv,
387                                                             BRIGHTNESS);
388                 contrast = dev_drv->ops->get_dsp_bcsh_bcs(dev_drv, CONTRAST);
389                 sat_con = dev_drv->ops->get_dsp_bcsh_bcs(dev_drv, SAT_CON);
390         }
391         if (dev_drv->ops->get_dsp_bcsh_hue) {
392                 sin_hue = dev_drv->ops->get_dsp_bcsh_hue(dev_drv, H_SIN);
393                 cos_hue = dev_drv->ops->get_dsp_bcsh_hue(dev_drv, H_COS);
394         }
395         return snprintf(buf, PAGE_SIZE,
396                         "brightness:%4d,contrast:%4d,sat_con:%4d,"
397                         "sin_hue:%4d,cos_hue:%4d\n",
398                         brightness, contrast, sat_con, sin_hue, cos_hue);
399 }
400
401 static ssize_t set_dsp_bcsh(struct device *dev, struct device_attribute *attr,
402                             const char *buf, size_t count)
403 {
404         struct fb_info *fbi = dev_get_drvdata(dev);
405         struct rk_lcdc_driver *dev_drv =
406             (struct rk_lcdc_driver *)fbi->par;
407         int brightness, contrast, sat_con, ret, sin_hue, cos_hue;
408
409         if (!strncmp(buf, "open", 4)) {
410                 if (dev_drv->ops->open_bcsh)
411                         ret = dev_drv->ops->open_bcsh(dev_drv, 1);
412                 else
413                         ret = -1;
414         } else if (!strncmp(buf, "close", 5)) {
415                 if (dev_drv->ops->open_bcsh)
416                         ret = dev_drv->ops->open_bcsh(dev_drv, 0);
417                 else
418                         ret = -1;
419         } else if (!strncmp(buf, "brightness", 10)) {
420                 sscanf(buf, "brightness %d", &brightness);
421                 if (unlikely(brightness > 255)) {
422                         dev_err(fbi->dev,
423                                 "brightness should be [0:255],now=%d\n\n",
424                                 brightness);
425                         brightness = 255;
426                 }
427                 if (dev_drv->ops->set_dsp_bcsh_bcs)
428                         ret = dev_drv->ops->set_dsp_bcsh_bcs(dev_drv,
429                                                              BRIGHTNESS,
430                                                              brightness);
431                 else
432                         ret = -1;
433         } else if (!strncmp(buf, "contrast", 8)) {
434                 sscanf(buf, "contrast %d", &contrast);
435                 if (unlikely(contrast > 510)) {
436                         dev_err(fbi->dev,
437                                 "contrast should be [0:510],now=%d\n",
438                                 contrast);
439                         contrast = 510;
440                 }
441                 if (dev_drv->ops->set_dsp_bcsh_bcs)
442                         ret = dev_drv->ops->set_dsp_bcsh_bcs(dev_drv,
443                                                              CONTRAST,
444                                                              contrast);
445                 else
446                         ret = -1;
447         } else if (!strncmp(buf, "sat_con", 7)) {
448                 sscanf(buf, "sat_con %d", &sat_con);
449                 if (unlikely(sat_con > 1015)) {
450                         dev_err(fbi->dev,
451                                 "sat_con should be [0:1015],now=%d\n",
452                                 sat_con);
453                         sat_con = 1015;
454                 }
455                 if (dev_drv->ops->set_dsp_bcsh_bcs)
456                         ret = dev_drv->ops->set_dsp_bcsh_bcs(dev_drv,
457                                                              SAT_CON,
458                                                              sat_con);
459                 else
460                         ret = -1;
461         } else if (!strncmp(buf, "hue", 3)) {
462                 sscanf(buf, "hue %d %d", &sin_hue, &cos_hue);
463                 if (unlikely(sin_hue > 511 || cos_hue > 511)) {
464                         dev_err(fbi->dev, "sin_hue=%d,cos_hue=%d\n",
465                                 sin_hue, cos_hue);
466                 }
467                 if (dev_drv->ops->set_dsp_bcsh_hue)
468                         ret = dev_drv->ops->set_dsp_bcsh_hue(dev_drv,
469                                                              sin_hue,
470                                                              cos_hue);
471                 else
472                         ret = -1;
473         } else {
474                 printk("format error\n");
475         }
476
477         if (ret < 0)
478                 return ret;
479
480         return count;
481 }
482
483 static ssize_t show_scale(struct device *dev,
484                           struct device_attribute *attr, char *buf)
485 {
486         struct fb_info *fbi = dev_get_drvdata(dev);
487         struct rk_lcdc_driver *dev_drv =
488             (struct rk_lcdc_driver *)fbi->par;
489         struct rk_screen *screen = dev_drv->cur_screen;
490
491         return snprintf(buf, PAGE_SIZE,
492                 "xscale=%d yscale=%d\nleft=%d top=%d right=%d bottom=%d\n",
493                 (screen->overscan.left + screen->overscan.right)/2,
494                 (screen->overscan.top + screen->overscan.bottom)/2,
495                 screen->overscan.left, screen->overscan.top,
496                 screen->overscan.right, screen->overscan.bottom);
497 }
498
499 static ssize_t set_scale(struct device *dev, struct device_attribute *attr,
500                          const char *buf, size_t count)
501 {
502         struct fb_info *fbi = dev_get_drvdata(dev);
503         struct rk_lcdc_driver *dev_drv =
504             (struct rk_lcdc_driver *)fbi->par;
505         struct rk_screen *screen = dev_drv->cur_screen;
506         u32 left, top, right, bottom;
507
508         if (!strncmp(buf, "overscan", 8)) {
509                 sscanf(buf,
510                        "overscan %d,%d,%d,%d", &left, &top, &right, &bottom);
511                 if (left > 0 && left <= 100)
512                         screen->overscan.left = left;
513                 if (top > 0 && top <= 100)
514                         screen->overscan.top = top;
515                 if (right > 0 && right <= 100)
516                         screen->overscan.right = right;
517                 if (bottom > 0 && bottom <= 100)
518                         screen->overscan.bottom = bottom;
519         } else if (!strncmp(buf, "left", 4)) {
520                 sscanf(buf, "left=%d", &left);
521                 if (left > 0 && left <= 100)
522                         screen->overscan.left = left;
523         } else if (!strncmp(buf, "top", 3)) {
524                 sscanf(buf, "top=%d", &top);
525                 if (top > 0 && top <= 100)
526                         screen->overscan.top = top;
527         } else if (!strncmp(buf, "right", 5)) {
528                 sscanf(buf, "right=%d", &right);
529                 if (right > 0 && right <= 100)
530                         screen->overscan.right = right;
531         } else if (!strncmp(buf, "bottom", 6)) {
532                 sscanf(buf, "bottom=%d", &bottom);
533                 if (bottom > 0 && bottom <= 100)
534                         screen->overscan.bottom = bottom;
535         } else if (!strncmp(buf, "xscale", 6)) {
536                 sscanf(buf, "xscale=%d", &left);
537                 if (left > 0 && left <= 100) {
538                         screen->overscan.left = left;
539                         screen->overscan.right = left;
540                 }
541         } else if (!strncmp(buf, "yscale", 6)) {
542                 sscanf(buf, "yscale=%d", &left);
543                 if (left > 0 && left <= 100) {
544                         screen->overscan.top = left;
545                         screen->overscan.bottom = left;
546                 }
547         } else {
548                 sscanf(buf, "%d", &left);
549                 if (left > 0 && left <= 100) {
550                         screen->overscan.left = left;
551                         screen->overscan.right = left;
552                         screen->overscan.top = left;
553                         screen->overscan.bottom = left;
554                 }
555         }
556
557         if (dev_drv->ops->set_overscan)
558                 dev_drv->ops->set_overscan(dev_drv, &screen->overscan);
559
560         return count;
561 }
562
563 static struct device_attribute rkfb_attrs[] = {
564         __ATTR(phys_addr, S_IRUGO, show_phys, NULL),
565         __ATTR(virt_addr, S_IRUGO, show_virt, NULL),
566         __ATTR(disp_info, S_IRUGO, show_disp_info, NULL),
567         __ATTR(screen_info, S_IRUGO, show_screen_info, NULL),
568         __ATTR(dual_mode, S_IRUGO, show_dual_mode, NULL),
569         __ATTR(enable, S_IRUGO | S_IWUSR, show_fb_state, set_fb_state),
570         __ATTR(overlay, S_IRUGO | S_IWUSR, show_overlay, set_overlay),
571         __ATTR(fps, S_IRUGO | S_IWUSR, show_fps, set_fps),
572         __ATTR(map, S_IRUGO | S_IWUSR, show_fb_win_map, set_fb_win_map),
573         __ATTR(dsp_lut, S_IRUGO | S_IWUSR, show_dsp_lut, set_dsp_lut),
574         __ATTR(hwc_lut, S_IRUGO | S_IWUSR, show_hwc_lut, set_hwc_lut),
575         __ATTR(cabc, S_IRUGO | S_IWUSR, show_dsp_cabc, set_dsp_cabc),
576         __ATTR(bcsh, S_IRUGO | S_IWUSR, show_dsp_bcsh, set_dsp_bcsh),
577         __ATTR(scale, S_IRUGO | S_IWUSR, show_scale, set_scale),
578 };
579
580 int rkfb_create_sysfs(struct fb_info *fbi)
581 {
582         int r, t;
583
584         for (t = 0; t < ARRAY_SIZE(rkfb_attrs); t++) {
585                 r = device_create_file(fbi->dev, &rkfb_attrs[t]);
586                 if (r) {
587                         dev_err(fbi->dev, "failed to create sysfs " "file\n");
588                         return r;
589                 }
590         }
591
592         return 0;
593 }
594
595 void rkfb_remove_sysfs(struct rk_fb *rk_fb)
596 {
597         int i, t;
598
599         for (i = 0; i < rk_fb->num_fb; i++) {
600                 for (t = 0; t < ARRAY_SIZE(rkfb_attrs); t++)
601                         device_remove_file(rk_fb->fb[i]->dev, &rkfb_attrs[t]);
602         }
603 }