[media] include/media: move driver interface headers to a separate dir
[sfrench/cifs-2.6.git] / drivers / media / platform / soc_camera / soc_mediabus.c
1 /*
2  * soc-camera media bus helper routines
3  *
4  * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13
14 #include <media/v4l2-device.h>
15 #include <media/v4l2-mediabus.h>
16 #include <media/drv-intf/soc_mediabus.h>
17
18 static const struct soc_mbus_lookup mbus_fmt[] = {
19 {
20         .code = MEDIA_BUS_FMT_YUYV8_2X8,
21         .fmt = {
22                 .fourcc                 = V4L2_PIX_FMT_YUYV,
23                 .name                   = "YUYV",
24                 .bits_per_sample        = 8,
25                 .packing                = SOC_MBUS_PACKING_2X8_PADHI,
26                 .order                  = SOC_MBUS_ORDER_LE,
27                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
28         },
29 }, {
30         .code = MEDIA_BUS_FMT_YVYU8_2X8,
31         .fmt = {
32                 .fourcc                 = V4L2_PIX_FMT_YVYU,
33                 .name                   = "YVYU",
34                 .bits_per_sample        = 8,
35                 .packing                = SOC_MBUS_PACKING_2X8_PADHI,
36                 .order                  = SOC_MBUS_ORDER_LE,
37                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
38         },
39 }, {
40         .code = MEDIA_BUS_FMT_UYVY8_2X8,
41         .fmt = {
42                 .fourcc                 = V4L2_PIX_FMT_UYVY,
43                 .name                   = "UYVY",
44                 .bits_per_sample        = 8,
45                 .packing                = SOC_MBUS_PACKING_2X8_PADHI,
46                 .order                  = SOC_MBUS_ORDER_LE,
47                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
48         },
49 }, {
50         .code = MEDIA_BUS_FMT_VYUY8_2X8,
51         .fmt = {
52                 .fourcc                 = V4L2_PIX_FMT_VYUY,
53                 .name                   = "VYUY",
54                 .bits_per_sample        = 8,
55                 .packing                = SOC_MBUS_PACKING_2X8_PADHI,
56                 .order                  = SOC_MBUS_ORDER_LE,
57                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
58         },
59 }, {
60         .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
61         .fmt = {
62                 .fourcc                 = V4L2_PIX_FMT_RGB555,
63                 .name                   = "RGB555",
64                 .bits_per_sample        = 8,
65                 .packing                = SOC_MBUS_PACKING_2X8_PADHI,
66                 .order                  = SOC_MBUS_ORDER_LE,
67                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
68         },
69 }, {
70         .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
71         .fmt = {
72                 .fourcc                 = V4L2_PIX_FMT_RGB555X,
73                 .name                   = "RGB555X",
74                 .bits_per_sample        = 8,
75                 .packing                = SOC_MBUS_PACKING_2X8_PADHI,
76                 .order                  = SOC_MBUS_ORDER_BE,
77                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
78         },
79 }, {
80         .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
81         .fmt = {
82                 .fourcc                 = V4L2_PIX_FMT_RGB565,
83                 .name                   = "RGB565",
84                 .bits_per_sample        = 8,
85                 .packing                = SOC_MBUS_PACKING_2X8_PADHI,
86                 .order                  = SOC_MBUS_ORDER_LE,
87                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
88         },
89 }, {
90         .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
91         .fmt = {
92                 .fourcc                 = V4L2_PIX_FMT_RGB565X,
93                 .name                   = "RGB565X",
94                 .bits_per_sample        = 8,
95                 .packing                = SOC_MBUS_PACKING_2X8_PADHI,
96                 .order                  = SOC_MBUS_ORDER_BE,
97                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
98         },
99 }, {
100         .code = MEDIA_BUS_FMT_RGB666_1X18,
101         .fmt = {
102                 .fourcc                 = V4L2_PIX_FMT_RGB32,
103                 .name                   = "RGB666/32bpp",
104                 .bits_per_sample        = 18,
105                 .packing                = SOC_MBUS_PACKING_EXTEND32,
106                 .order                  = SOC_MBUS_ORDER_LE,
107         },
108 }, {
109         .code = MEDIA_BUS_FMT_RGB888_1X24,
110         .fmt = {
111                 .fourcc                 = V4L2_PIX_FMT_RGB32,
112                 .name                   = "RGB888/32bpp",
113                 .bits_per_sample        = 24,
114                 .packing                = SOC_MBUS_PACKING_EXTEND32,
115                 .order                  = SOC_MBUS_ORDER_LE,
116         },
117 }, {
118         .code = MEDIA_BUS_FMT_RGB888_2X12_BE,
119         .fmt = {
120                 .fourcc                 = V4L2_PIX_FMT_RGB32,
121                 .name                   = "RGB888/32bpp",
122                 .bits_per_sample        = 12,
123                 .packing                = SOC_MBUS_PACKING_EXTEND32,
124                 .order                  = SOC_MBUS_ORDER_BE,
125         },
126 }, {
127         .code = MEDIA_BUS_FMT_RGB888_2X12_LE,
128         .fmt = {
129                 .fourcc                 = V4L2_PIX_FMT_RGB32,
130                 .name                   = "RGB888/32bpp",
131                 .bits_per_sample        = 12,
132                 .packing                = SOC_MBUS_PACKING_EXTEND32,
133                 .order                  = SOC_MBUS_ORDER_LE,
134         },
135 }, {
136         .code = MEDIA_BUS_FMT_SBGGR8_1X8,
137         .fmt = {
138                 .fourcc                 = V4L2_PIX_FMT_SBGGR8,
139                 .name                   = "Bayer 8 BGGR",
140                 .bits_per_sample        = 8,
141                 .packing                = SOC_MBUS_PACKING_NONE,
142                 .order                  = SOC_MBUS_ORDER_LE,
143                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
144         },
145 }, {
146         .code = MEDIA_BUS_FMT_SBGGR10_1X10,
147         .fmt = {
148                 .fourcc                 = V4L2_PIX_FMT_SBGGR10,
149                 .name                   = "Bayer 10 BGGR",
150                 .bits_per_sample        = 10,
151                 .packing                = SOC_MBUS_PACKING_EXTEND16,
152                 .order                  = SOC_MBUS_ORDER_LE,
153                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
154         },
155 }, {
156         .code = MEDIA_BUS_FMT_Y8_1X8,
157         .fmt = {
158                 .fourcc                 = V4L2_PIX_FMT_GREY,
159                 .name                   = "Grey",
160                 .bits_per_sample        = 8,
161                 .packing                = SOC_MBUS_PACKING_NONE,
162                 .order                  = SOC_MBUS_ORDER_LE,
163                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
164         },
165 }, {
166         .code = MEDIA_BUS_FMT_Y10_1X10,
167         .fmt = {
168                 .fourcc                 = V4L2_PIX_FMT_Y10,
169                 .name                   = "Grey 10bit",
170                 .bits_per_sample        = 10,
171                 .packing                = SOC_MBUS_PACKING_EXTEND16,
172                 .order                  = SOC_MBUS_ORDER_LE,
173                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
174         },
175 }, {
176         .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
177         .fmt = {
178                 .fourcc                 = V4L2_PIX_FMT_SBGGR10,
179                 .name                   = "Bayer 10 BGGR",
180                 .bits_per_sample        = 8,
181                 .packing                = SOC_MBUS_PACKING_2X8_PADHI,
182                 .order                  = SOC_MBUS_ORDER_LE,
183                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
184         },
185 }, {
186         .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE,
187         .fmt = {
188                 .fourcc                 = V4L2_PIX_FMT_SBGGR10,
189                 .name                   = "Bayer 10 BGGR",
190                 .bits_per_sample        = 8,
191                 .packing                = SOC_MBUS_PACKING_2X8_PADLO,
192                 .order                  = SOC_MBUS_ORDER_LE,
193                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
194         },
195 }, {
196         .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE,
197         .fmt = {
198                 .fourcc                 = V4L2_PIX_FMT_SBGGR10,
199                 .name                   = "Bayer 10 BGGR",
200                 .bits_per_sample        = 8,
201                 .packing                = SOC_MBUS_PACKING_2X8_PADHI,
202                 .order                  = SOC_MBUS_ORDER_BE,
203                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
204         },
205 }, {
206         .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE,
207         .fmt = {
208                 .fourcc                 = V4L2_PIX_FMT_SBGGR10,
209                 .name                   = "Bayer 10 BGGR",
210                 .bits_per_sample        = 8,
211                 .packing                = SOC_MBUS_PACKING_2X8_PADLO,
212                 .order                  = SOC_MBUS_ORDER_BE,
213                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
214         },
215 }, {
216         .code = MEDIA_BUS_FMT_JPEG_1X8,
217         .fmt = {
218                 .fourcc                 = V4L2_PIX_FMT_JPEG,
219                 .name                   = "JPEG",
220                 .bits_per_sample        = 8,
221                 .packing                = SOC_MBUS_PACKING_VARIABLE,
222                 .order                  = SOC_MBUS_ORDER_LE,
223                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
224         },
225 }, {
226         .code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE,
227         .fmt = {
228                 .fourcc                 = V4L2_PIX_FMT_RGB444,
229                 .name                   = "RGB444",
230                 .bits_per_sample        = 8,
231                 .packing                = SOC_MBUS_PACKING_2X8_PADHI,
232                 .order                  = SOC_MBUS_ORDER_BE,
233                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
234         },
235 }, {
236         .code = MEDIA_BUS_FMT_YUYV8_1_5X8,
237         .fmt = {
238                 .fourcc                 = V4L2_PIX_FMT_YUV420,
239                 .name                   = "YUYV 4:2:0",
240                 .bits_per_sample        = 8,
241                 .packing                = SOC_MBUS_PACKING_1_5X8,
242                 .order                  = SOC_MBUS_ORDER_LE,
243                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
244         },
245 }, {
246         .code = MEDIA_BUS_FMT_YVYU8_1_5X8,
247         .fmt = {
248                 .fourcc                 = V4L2_PIX_FMT_YVU420,
249                 .name                   = "YVYU 4:2:0",
250                 .bits_per_sample        = 8,
251                 .packing                = SOC_MBUS_PACKING_1_5X8,
252                 .order                  = SOC_MBUS_ORDER_LE,
253                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
254         },
255 }, {
256         .code = MEDIA_BUS_FMT_UYVY8_1X16,
257         .fmt = {
258                 .fourcc                 = V4L2_PIX_FMT_UYVY,
259                 .name                   = "UYVY 16bit",
260                 .bits_per_sample        = 16,
261                 .packing                = SOC_MBUS_PACKING_EXTEND16,
262                 .order                  = SOC_MBUS_ORDER_LE,
263                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
264         },
265 }, {
266         .code = MEDIA_BUS_FMT_VYUY8_1X16,
267         .fmt = {
268                 .fourcc                 = V4L2_PIX_FMT_VYUY,
269                 .name                   = "VYUY 16bit",
270                 .bits_per_sample        = 16,
271                 .packing                = SOC_MBUS_PACKING_EXTEND16,
272                 .order                  = SOC_MBUS_ORDER_LE,
273                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
274         },
275 }, {
276         .code = MEDIA_BUS_FMT_YUYV8_1X16,
277         .fmt = {
278                 .fourcc                 = V4L2_PIX_FMT_YUYV,
279                 .name                   = "YUYV 16bit",
280                 .bits_per_sample        = 16,
281                 .packing                = SOC_MBUS_PACKING_EXTEND16,
282                 .order                  = SOC_MBUS_ORDER_LE,
283                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
284         },
285 }, {
286         .code = MEDIA_BUS_FMT_YVYU8_1X16,
287         .fmt = {
288                 .fourcc                 = V4L2_PIX_FMT_YVYU,
289                 .name                   = "YVYU 16bit",
290                 .bits_per_sample        = 16,
291                 .packing                = SOC_MBUS_PACKING_EXTEND16,
292                 .order                  = SOC_MBUS_ORDER_LE,
293                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
294         },
295 }, {
296         .code = MEDIA_BUS_FMT_SGRBG8_1X8,
297         .fmt = {
298                 .fourcc                 = V4L2_PIX_FMT_SGRBG8,
299                 .name                   = "Bayer 8 GRBG",
300                 .bits_per_sample        = 8,
301                 .packing                = SOC_MBUS_PACKING_NONE,
302                 .order                  = SOC_MBUS_ORDER_LE,
303                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
304         },
305 }, {
306         .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
307         .fmt = {
308                 .fourcc                 = V4L2_PIX_FMT_SGRBG10DPCM8,
309                 .name                   = "Bayer 10 BGGR DPCM 8",
310                 .bits_per_sample        = 8,
311                 .packing                = SOC_MBUS_PACKING_NONE,
312                 .order                  = SOC_MBUS_ORDER_LE,
313                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
314         },
315 }, {
316         .code = MEDIA_BUS_FMT_SGBRG10_1X10,
317         .fmt = {
318                 .fourcc                 = V4L2_PIX_FMT_SGBRG10,
319                 .name                   = "Bayer 10 GBRG",
320                 .bits_per_sample        = 10,
321                 .packing                = SOC_MBUS_PACKING_EXTEND16,
322                 .order                  = SOC_MBUS_ORDER_LE,
323                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
324         },
325 }, {
326         .code = MEDIA_BUS_FMT_SGRBG10_1X10,
327         .fmt = {
328                 .fourcc                 = V4L2_PIX_FMT_SGRBG10,
329                 .name                   = "Bayer 10 GRBG",
330                 .bits_per_sample        = 10,
331                 .packing                = SOC_MBUS_PACKING_EXTEND16,
332                 .order                  = SOC_MBUS_ORDER_LE,
333                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
334         },
335 }, {
336         .code = MEDIA_BUS_FMT_SRGGB10_1X10,
337         .fmt = {
338                 .fourcc                 = V4L2_PIX_FMT_SRGGB10,
339                 .name                   = "Bayer 10 RGGB",
340                 .bits_per_sample        = 10,
341                 .packing                = SOC_MBUS_PACKING_EXTEND16,
342                 .order                  = SOC_MBUS_ORDER_LE,
343                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
344         },
345 }, {
346         .code = MEDIA_BUS_FMT_SBGGR12_1X12,
347         .fmt = {
348                 .fourcc                 = V4L2_PIX_FMT_SBGGR12,
349                 .name                   = "Bayer 12 BGGR",
350                 .bits_per_sample        = 12,
351                 .packing                = SOC_MBUS_PACKING_EXTEND16,
352                 .order                  = SOC_MBUS_ORDER_LE,
353                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
354         },
355 }, {
356         .code = MEDIA_BUS_FMT_SGBRG12_1X12,
357         .fmt = {
358                 .fourcc                 = V4L2_PIX_FMT_SGBRG12,
359                 .name                   = "Bayer 12 GBRG",
360                 .bits_per_sample        = 12,
361                 .packing                = SOC_MBUS_PACKING_EXTEND16,
362                 .order                  = SOC_MBUS_ORDER_LE,
363                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
364         },
365 }, {
366         .code = MEDIA_BUS_FMT_SGRBG12_1X12,
367         .fmt = {
368                 .fourcc                 = V4L2_PIX_FMT_SGRBG12,
369                 .name                   = "Bayer 12 GRBG",
370                 .bits_per_sample        = 12,
371                 .packing                = SOC_MBUS_PACKING_EXTEND16,
372                 .order                  = SOC_MBUS_ORDER_LE,
373                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
374         },
375 }, {
376         .code = MEDIA_BUS_FMT_SRGGB12_1X12,
377         .fmt = {
378                 .fourcc                 = V4L2_PIX_FMT_SRGGB12,
379                 .name                   = "Bayer 12 RGGB",
380                 .bits_per_sample        = 12,
381                 .packing                = SOC_MBUS_PACKING_EXTEND16,
382                 .order                  = SOC_MBUS_ORDER_LE,
383                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
384         },
385 },
386 };
387
388 int soc_mbus_samples_per_pixel(const struct soc_mbus_pixelfmt *mf,
389                         unsigned int *numerator, unsigned int *denominator)
390 {
391         switch (mf->packing) {
392         case SOC_MBUS_PACKING_NONE:
393         case SOC_MBUS_PACKING_EXTEND16:
394                 *numerator = 1;
395                 *denominator = 1;
396                 return 0;
397         case SOC_MBUS_PACKING_EXTEND32:
398                 *numerator = 1;
399                 *denominator = 1;
400                 return 0;
401         case SOC_MBUS_PACKING_2X8_PADHI:
402         case SOC_MBUS_PACKING_2X8_PADLO:
403                 *numerator = 2;
404                 *denominator = 1;
405                 return 0;
406         case SOC_MBUS_PACKING_1_5X8:
407                 *numerator = 3;
408                 *denominator = 2;
409                 return 0;
410         case SOC_MBUS_PACKING_VARIABLE:
411                 *numerator = 0;
412                 *denominator = 1;
413                 return 0;
414         }
415         return -EINVAL;
416 }
417 EXPORT_SYMBOL(soc_mbus_samples_per_pixel);
418
419 s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
420 {
421         if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
422                 return width * mf->bits_per_sample / 8;
423
424         switch (mf->packing) {
425         case SOC_MBUS_PACKING_NONE:
426                 return width * mf->bits_per_sample / 8;
427         case SOC_MBUS_PACKING_2X8_PADHI:
428         case SOC_MBUS_PACKING_2X8_PADLO:
429         case SOC_MBUS_PACKING_EXTEND16:
430                 return width * 2;
431         case SOC_MBUS_PACKING_1_5X8:
432                 return width * 3 / 2;
433         case SOC_MBUS_PACKING_VARIABLE:
434                 return 0;
435         case SOC_MBUS_PACKING_EXTEND32:
436                 return width * 4;
437         }
438         return -EINVAL;
439 }
440 EXPORT_SYMBOL(soc_mbus_bytes_per_line);
441
442 s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf,
443                         u32 bytes_per_line, u32 height)
444 {
445         if (mf->layout == SOC_MBUS_LAYOUT_PACKED)
446                 return bytes_per_line * height;
447
448         switch (mf->packing) {
449         case SOC_MBUS_PACKING_2X8_PADHI:
450         case SOC_MBUS_PACKING_2X8_PADLO:
451                 return bytes_per_line * height * 2;
452         case SOC_MBUS_PACKING_1_5X8:
453                 return bytes_per_line * height * 3 / 2;
454         default:
455                 return -EINVAL;
456         }
457 }
458 EXPORT_SYMBOL(soc_mbus_image_size);
459
460 const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
461         u32 code,
462         const struct soc_mbus_lookup *lookup,
463         int n)
464 {
465         int i;
466
467         for (i = 0; i < n; i++)
468                 if (lookup[i].code == code)
469                         return &lookup[i].fmt;
470
471         return NULL;
472 }
473 EXPORT_SYMBOL(soc_mbus_find_fmtdesc);
474
475 const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
476         u32 code)
477 {
478         return soc_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt));
479 }
480 EXPORT_SYMBOL(soc_mbus_get_fmtdesc);
481
482 unsigned int soc_mbus_config_compatible(const struct v4l2_mbus_config *cfg,
483                                         unsigned int flags)
484 {
485         unsigned long common_flags;
486         bool hsync = true, vsync = true, pclk, data, mode;
487         bool mipi_lanes, mipi_clock;
488
489         common_flags = cfg->flags & flags;
490
491         switch (cfg->type) {
492         case V4L2_MBUS_PARALLEL:
493                 hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH |
494                                         V4L2_MBUS_HSYNC_ACTIVE_LOW);
495                 vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH |
496                                         V4L2_MBUS_VSYNC_ACTIVE_LOW);
497         case V4L2_MBUS_BT656:
498                 pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING |
499                                        V4L2_MBUS_PCLK_SAMPLE_FALLING);
500                 data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH |
501                                        V4L2_MBUS_DATA_ACTIVE_LOW);
502                 mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE);
503                 return (!hsync || !vsync || !pclk || !data || !mode) ?
504                         0 : common_flags;
505         case V4L2_MBUS_CSI2:
506                 mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES;
507                 mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK |
508                                              V4L2_MBUS_CSI2_CONTINUOUS_CLOCK);
509                 return (!mipi_lanes || !mipi_clock) ? 0 : common_flags;
510         }
511         return 0;
512 }
513 EXPORT_SYMBOL(soc_mbus_config_compatible);
514
515 static int __init soc_mbus_init(void)
516 {
517         return 0;
518 }
519
520 static void __exit soc_mbus_exit(void)
521 {
522 }
523
524 module_init(soc_mbus_init);
525 module_exit(soc_mbus_exit);
526
527 MODULE_DESCRIPTION("soc-camera media bus interface");
528 MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
529 MODULE_LICENSE("GPL v2");