xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.cpp (revision 020cbad9d40235a2c50a81a42d69912a5ff8fbc4)
1 #include "SonixCamDevice.h"
2 #include "CamDebug.h"
3 #include "CamSensor.h"
4 #include "CamBufferingDeframer.h"
5 #include "CamStreamingDeframer.h"
6 
7 #include <interface/Bitmap.h>
8 #include <media/Buffer.h>
9 
10 const usb_named_support_descriptor kSupportedDevices[] = {
11 {{ 0, 0, 0, 0x0c45, 0x6005 }, "Sonix", "Sonix"},
12 {{ 0, 0, 0, 0x0c45, 0x6009 }, "Trust", "spacec@m 120" },
13 {{ 0, 0, 0, 0x0c45, 0x600D }, "Trust", "spacec@m 120" },
14 {{ 0, 0, 0, 0, 0}, NULL, NULL }
15 };
16 
17 // 12 bytes actually
18 static const uint8 sof_mark_1[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x00 };
19 static const uint8 sof_mark_2[] = { 0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96, 0x01 };
20 static const uint8 *sof_marks[] = { sof_mark_1, sof_mark_2 };
21 
22 static const uint8 eof_mark_1[] = { 0x00, 0x00, 0x00, 0x00 };
23 static const uint8 eof_mark_2[] = { 0x40, 0x00, 0x00, 0x00 };
24 static const uint8 eof_mark_3[] = { 0x80, 0x00, 0x00, 0x00 };
25 static const uint8 eof_mark_4[] = { 0xc0, 0x00, 0x00, 0x00 };
26 static const uint8 *eof_marks[] = { eof_mark_1, eof_mark_2, eof_mark_3, eof_mark_4 };
27 
28 void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT);
29 void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT);
30 
31 // -----------------------------------------------------------------------------
32 SonixCamDevice::SonixCamDevice(CamDeviceAddon &_addon, BUSBDevice* _device)
33           :CamDevice(_addon, _device)
34 {
35 	uchar data[8]; /* store bytes returned from sonix commands */
36 	status_t err;
37 	fFrameTagState = 0;
38 
39 	memset(fCachedRegs, 0, SN9C102_REG_COUNT);
40 	fChipVersion = 2;
41 	if ((GetDevice()->ProductID() & ~0x3F) == 0x6080) {
42 		fChipVersion = 3; // says V4L2
43 	}
44 	switch (GetDevice()->ProductID()) {
45 	case 0x6001:
46 	case 0x6005:
47 	case 0x60ab:
48 		fSensor = CreateSensor("tas5110c1b");
49 		break;
50 	default:
51 		break;
52 	}
53 
54 //	fDeframer = new CamBufferingDeframer(this);
55 	fDeframer = new CamStreamingDeframer(this);
56 	fDeframer->RegisterSOFTags(sof_marks, 2, sizeof(sof_mark_1), 12);
57 	fDeframer->RegisterEOFTags(eof_marks, 4, sizeof(eof_mark_1), sizeof(eof_mark_1));
58 	SetDataInput(fDeframer);
59 
60 	/* init hw */
61 
62 	const BUSBConfiguration *config = GetDevice()->ConfigurationAt(0);
63 	if (config) {
64 		const BUSBInterface *inter = config->InterfaceAt(0);
65 		int i;
66 
67 		GetDevice()->SetConfiguration(config);
68 
69 		for (i = 0; inter && (i < inter->CountEndpoints()); i++) {
70 			const BUSBEndpoint *e = inter->EndpointAt(i);
71 			if (e && e->IsBulk() && e->IsInput()) {
72 				fBulkIn = e;
73 				PRINT((CH ": Using inter[0].endpoint[%d]; maxpktsz: %d" CT, i, e->MaxPacketSize()));
74 				break;
75 			}
76 		}
77 
78 	}
79 
80 	/* sanity check */
81 	err = ReadReg(SN9C102_ASIC_ID, data);
82 	if (err < 0 || data[0] != 0x10) {
83 		PRINT((CH ": BAD ASIC signature! (%u != %u)" CT, data[0], 0x10));
84 		return;
85 	}
86 
87 
88 	if (Sensor()) {
89 		PRINT((CH ": CamSensor: %s" CT, Sensor()->Name()));
90 		fInitStatus = Sensor()->Setup();
91 //		SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1));
92 //		SetVideoFrame(BRect(0, 0, 320-1, 240-1));
93 	}
94 	//SetScale(1);
95 }
96 
97 // -----------------------------------------------------------------------------
98 SonixCamDevice::~SonixCamDevice()
99 {
100 	if (Sensor())
101 		delete fSensor;
102 	fSensor = NULL;
103 }
104 
105 // -----------------------------------------------------------------------------
106 bool
107 SonixCamDevice::SupportsBulk()
108 {
109 	return true;
110 }
111 
112 // -----------------------------------------------------------------------------
113 bool
114 SonixCamDevice::SupportsIsochronous()
115 {
116 	return true;
117 }
118 
119 // -----------------------------------------------------------------------------
120 status_t
121 SonixCamDevice::StartTransfer()
122 {
123 	status_t err;
124 	uint8 r;
125 
126 	SetScale(1);
127 	if (Sensor())
128 		SetVideoFrame(BRect(0, 0, Sensor()->MaxWidth()-1, Sensor()->MaxHeight()-1));
129 
130 	SetVideoFrame(BRect(0, 0, 320-1, 240-1));
131 
132 DumpRegs();
133 	err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
134 	if (err < 0)
135 		return err;
136 	r |= 0x04;
137 	err = WriteReg8(SN9C102_CHIP_CTRL, r);
138 	if (err < 0)
139 		return err;
140 	return CamDevice::StartTransfer();
141 }
142 
143 // -----------------------------------------------------------------------------
144 status_t
145 SonixCamDevice::StopTransfer()
146 {
147 	status_t err;
148 	uint8 r;
149 
150 DumpRegs();
151 	err = CamDevice::StopTransfer();
152 //	if (err < 0)
153 //		return err;
154 	err = ReadReg(SN9C102_CHIP_CTRL, &r, 1, true);
155 	if (err < 0)
156 		return err;
157 	r &= ~0x04;
158 	err = WriteReg8(SN9C102_CHIP_CTRL, r);
159 	if (err < 0)
160 		return err;
161 	return err;
162 }
163 
164 // -----------------------------------------------------------------------------
165 ssize_t
166 SonixCamDevice::WriteReg(uint16 address, uint8 *data, size_t count)
167 {
168 	PRINT((CH "(%u, @%p, %u)" CT, address, data, count));
169 	if (address + count > SN9C102_REG_COUNT) {
170 		PRINT((CH ": Invalid register range [%u;%u]" CT, address, address+count));
171 		return EINVAL;
172 	}
173 	memcpy(&fCachedRegs[address], data, count);
174 	return SendCommand(USB_REQTYPE_DEVICE_OUT, 0x08, address, 0, count, data);
175 }
176 
177 // -----------------------------------------------------------------------------
178 ssize_t
179 SonixCamDevice::ReadReg(uint16 address, uint8 *data, size_t count, bool cached)
180 {
181 	PRINT((CH "(%u, @%p, %u, %d)" CT, address, data, count, cached));
182 	if (address + count > SN9C102_REG_COUNT) {
183 		PRINT((CH ": Invalid register range [%u;%u]" CT, address, address+count));
184 		return EINVAL;
185 	}
186 	if (cached) {
187 		memcpy(data, &fCachedRegs[address], count);
188 		return count;
189 	}
190 	return SendCommand(USB_REQTYPE_DEVICE_IN, 0x00, address, 0, count, data);
191 }
192 
193 // -----------------------------------------------------------------------------
194 status_t
195 SonixCamDevice::GetStatusIIC()
196 {
197 	status_t err;
198 	uint8 status = 0;
199 	err = ReadReg(SN9C102_I2C_SETUP, &status);
200 	//dprintf(ID "i2c_status: error 0x%08lx, status = %02x\n", err, status);
201 	if (err < 0)
202 		return err;
203 	return (status&0x08)?EIO:0;
204 }
205 
206 // -----------------------------------------------------------------------------
207 status_t
208 SonixCamDevice::WaitReadyIIC()
209 {
210 	status_t err;
211 	uint8 status = 0;
212 	int tries = 5;
213 	if (!Sensor())
214 		return B_NO_INIT;
215 	while (tries--) {
216 		err = ReadReg(SN9C102_I2C_SETUP, &status);
217 		//dprintf(ID "i2c_wait_ready: error 0x%08lx, status = %02x\n", err, status);
218 		if (err < 0) return err;
219 		if (status & 0x04) return B_OK;
220 		//XXX:FIXME:spin((1+5+11*dev->sensor->use_400kHz)*8);
221 		snooze((1+5+11*Sensor()->Use400kHz())*8);
222 	}
223 	return EBUSY;
224 }
225 
226 // -----------------------------------------------------------------------------
227 ssize_t
228 SonixCamDevice::WriteIIC(uint8 address, uint8 *data, size_t count)
229 {
230 	status_t err;
231 	uint8 status;
232 	uint8 buffer[8];
233 	if (!Sensor())
234 		return B_NO_INIT;
235 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
236 	count++; // includes address
237 	if (count > 5)
238 		return EINVAL;
239 	buffer[0] = (count << 4) | Sensor()->Use400kHz()?0x01:0
240 							 | Sensor()->UseRealIIC()?0x80:0;
241 	buffer[1] = Sensor()->IICWriteAddress();
242 	buffer[2] = address;
243 	memset(&buffer[3], 0, 5);
244 	memcpy(&buffer[3], data, count);
245 	buffer[7] = 0x14; /* absolutely no idea why V4L2 driver use that value */
246 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
247 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
248 	//PRINT((CH ": WriteReg: %s" CT, strerror(err)));
249 	if (err < 0) return err;
250 	err = WaitReadyIIC();
251 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
252 	//PRINT((CH ": Wait: %s" CT, strerror(err)));
253 	if (err) return err;
254 	err = GetStatusIIC();
255 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err);
256 	//PRINT((CH ": Status: %s" CT, strerror(err)));
257 	if (err) return err;
258 	//dprintf(ID "sonix_i2c_write_multi: succeeded\n");
259 	PRINT((CH ": success" CT));
260 	return B_OK;
261 }
262 
263 // -----------------------------------------------------------------------------
264 ssize_t
265 SonixCamDevice::ReadIIC(uint8 address, uint8 *data)
266 {
267 	status_t err, lasterr = B_OK;
268 	uint8 status;
269 	uint8 buffer[8];
270 	if (!Sensor())
271 		return B_NO_INIT;
272 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
273 	buffer[0] = (1 << 4) | Sensor()->Use400kHz()?0x01:0
274 						 | Sensor()->UseRealIIC()?0x80:0;
275 	buffer[1] = Sensor()->IICWriteAddress();
276 	buffer[2] = address;
277 	buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */
278 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
279 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
280 	if (err) return err;
281 	err = WaitReadyIIC();
282 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
283 	//if (err) return err;
284 
285 
286 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
287 	buffer[0] = (1 << 4) | Sensor()->Use400kHz()?0x01:0
288 				  | 0x02 | Sensor()->UseRealIIC()?0x80:0; /* read 1 byte */
289 	buffer[1] = Sensor()->IICReadAddress();//IICWriteAddress
290 	buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */
291 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
292 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
293 	if (err) return err;
294 	err = WaitReadyIIC();
295 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
296 	if (err) return err;
297 
298 	err = ReadReg(SN9C102_I2C_DATA0, buffer, 5);
299 	if (err) lasterr = err;
300 
301 	err = GetStatusIIC();
302 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err);
303 	if (err) return err;
304 	//dprintf(ID "sonix_i2c_write_multi: succeeded\n");
305 	if (lasterr) return err;
306 
307 	/* we should get what we want in buffer[4] according to the V4L2 driver...
308 	 * probably because the 5 bytes are a bit shift register?
309 	 */
310 	*data = buffer[4];
311 
312 	return 1;
313 }
314 
315 // -----------------------------------------------------------------------------
316 status_t
317 SonixCamDevice::SetVideoFrame(BRect frame)
318 {
319 	uint16 x, y, width, height;
320 	x = (uint16)frame.left;
321 	y = (uint16)frame.top;
322 	width = (uint16)(frame.right - frame.left + 1) / 16;
323 	height = (uint16)(frame.bottom - frame.top + 1) / 16;
324 	PRINT((CH "(%u, %u, %u, %u)" CT, x, y, width, height));
325 
326 	WriteReg8(SN9C102_H_START, x);
327 	WriteReg8(SN9C102_V_START, y);
328 	WriteReg8(SN9C102_H_SIZE, width);
329 	WriteReg8(SN9C102_V_SIZE, height);
330 	if (Sensor()) {
331 		Sensor()->SetVideoFrame(frame);
332 	}
333 	return CamDevice::SetVideoFrame(frame);
334 }
335 
336 // -----------------------------------------------------------------------------
337 status_t
338 SonixCamDevice::SetScale(float scale)
339 {
340 	status_t err;
341 	uint8 r;
342 	int iscale = (int)scale;
343 
344 	PRINT((CH "(%u)" CT, iscale));
345 	err = ReadReg(SN9C102_SYNC_N_SCALE, &r, 1, true);
346 	if (err < 0)
347 		return err;
348 	r &= ~0x30;
349 	switch (iscale) {
350 	case 1:
351 	case 2:
352 	case 4:
353 		r |= ((iscale-1) << 4);
354 		break;
355 	default:
356 		return EINVAL;
357 	}
358 	err = WriteReg8(SN9C102_SYNC_N_SCALE, r);
359 	return err;
360 }
361 
362 // -----------------------------------------------------------------------------
363 status_t
364 SonixCamDevice::SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue)
365 {
366 	return B_OK;
367 }
368 
369 // -----------------------------------------------------------------------------
370 size_t
371 SonixCamDevice::MinRawFrameSize()
372 {
373 	// if (fCompressionEnabled) { ... return ; }
374 	BRect vf(VideoFrame());
375 	int w = vf.IntegerWidth()+1;
376 	int h = vf.IntegerHeight()+1;
377 	// 1 byte/pixel
378 	return (size_t)(w*h);
379 }
380 
381 // -----------------------------------------------------------------------------
382 size_t
383 SonixCamDevice::MaxRawFrameSize()
384 {
385 	// if (fCompressionEnabled) { ... return ; }
386 	return MinRawFrameSize()+1024*0; // fixed size frame (uncompressed)
387 }
388 
389 // -----------------------------------------------------------------------------
390 bool
391 SonixCamDevice::ValidateStartOfFrameTag(const uint8 *tag, size_t taglen)
392 {
393 	// SOF come with an 00, 40, 80, C0 sequence,
394 	// supposedly corresponding with an equal byte in the end tag
395 	fFrameTagState = tag[7] & 0xC0;
396 	PRINT((CH "(, %d) state %x" CT, taglen, fFrameTagState));
397 
398 	// which seems to be the same as of the EOF tag
399 	return true;
400 }
401 
402 // -----------------------------------------------------------------------------
403 bool
404 SonixCamDevice::ValidateEndOfFrameTag(const uint8 *tag, size_t taglen, size_t datalen)
405 {
406 	//PRINT((CH "(, %d) %x == %x" CT, taglen, (tag[0] & 0xC0), fFrameTagState));
407 	// make sure the tag corresponds to the SOF we refer to
408 	if ((tag[0] & 0xC0) != fFrameTagState) {
409 		PRINT((CH ": discarded EOF %x != %x" CT, fFrameTagState, tag[0] & 0xC0));
410 		return false;
411 	}
412 	//PRINT((CH ": validated EOF %x, len %d" CT, fFrameTagState, datalen));
413 	return true;
414 }
415 
416 // -----------------------------------------------------------------------------
417 status_t
418 SonixCamDevice::GetFrameBitmap(BBitmap **bm, bigtime_t *stamp /* = NULL */)
419 {
420 	BBitmap *b;
421 	CamFrame *f;
422 	status_t err;
423 	PRINT((CH "()" CT));
424 	err = fDeframer->WaitFrame(200000);
425 	if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); }
426 	if (err < B_OK)
427 		return err;
428 	err = fDeframer->GetFrame(&f, stamp);
429 	if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); }
430 	if (err < B_OK)
431 		return err;
432 	PRINT((CH ": VideoFrame = %fx%f,%fx%f" CT, VideoFrame().left, VideoFrame().top, VideoFrame().right, VideoFrame().bottom));
433 
434 	long int w = VideoFrame().right - VideoFrame().left + 1;
435 	long int h = VideoFrame().bottom - VideoFrame().top + 1;
436 	b = new BBitmap(VideoFrame().OffsetToSelf(0,0), 0, B_RGB32, w*4);
437 	PRINT((CH ": Frame: %dx%d" CT, w, h));
438 
439 	bayer2rgb24((unsigned char *)b->Bits(), (unsigned char *)f->Buffer(), w, h);
440 
441 	PRINT((CH ": got 1 frame (len %d)" CT, b->BitsLength()));
442 	*bm = b;
443 	return B_OK;
444 }
445 
446 // -----------------------------------------------------------------------------
447 status_t
448 SonixCamDevice::FillFrameBuffer(BBuffer *buffer, bigtime_t *stamp)
449 {
450 	CamFrame *f;
451 	status_t err;
452 	PRINT((CH "()" CT));
453 
454 	memset(buffer->Data(), 0, buffer->SizeAvailable());
455 	err = fDeframer->WaitFrame(2000000);
456 	if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); }
457 	if (err < B_OK)
458 		return err;
459 
460 	err = fDeframer->GetFrame(&f, stamp);
461 	if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); }
462 	if (err < B_OK)
463 		return err;
464 
465 	long int w = VideoFrame().right - VideoFrame().left + 1;
466 	long int h = VideoFrame().bottom - VideoFrame().top + 1;
467 	PRINT((CH ": VideoFrame = %fx%f,%fx%f Frame: %dx%d" CT, VideoFrame().left, VideoFrame().top, VideoFrame().right, VideoFrame().bottom, w, h));
468 
469 	if (buffer->SizeAvailable() >= w*h*4)
470 		bayer2rgb32le((unsigned char *)buffer->Data(), (unsigned char *)f->Buffer(), w, h);
471 
472 	delete f;
473 
474 	PRINT((CH ": available %d, required %d" CT, buffer->SizeAvailable(), w*h*4));
475 	if (buffer->SizeAvailable() < w*h*4)
476 		return E2BIG;
477 	PRINT((CH ": got 1 frame (len %d)" CT, buffer->SizeUsed()));
478 	return B_OK;
479 }
480 
481 // -----------------------------------------------------------------------------
482 void
483 /* DEBUG: dump the SN regs */
484 SonixCamDevice::DumpRegs()
485 {
486 	uint8 regs[SN9C102_REG_COUNT];
487 	status_t err;
488 
489 	//err = sonix_get_regs(dev, SN_ASIC_ID, regs, SN_REG_COUNT);
490 	err = ReadReg(0, regs, SN9C102_REG_COUNT);
491 	if (err < 0)
492 		return;
493 	printf("REG1: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
494 			regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]);
495 	printf("   2: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
496 			regs[8], regs[9], regs[10], regs[11], regs[12], regs[13], regs[14], regs[15]);
497 	printf("   3: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
498 			regs[16], regs[17], regs[18], regs[19], regs[20], regs[21], regs[22], regs[23]);
499 	printf("   4: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
500 			regs[24], regs[25], regs[26], regs[27], regs[28], regs[29], regs[30], regs[31]);
501 }
502 
503 // -----------------------------------------------------------------------------
504 status_t
505 SonixCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
506 							uint16 index, uint16 length, void* data)
507 {
508 	size_t ret;
509 	if (length > 64)
510 		return EINVAL;
511 	if (!GetDevice())
512 		return ENODEV;
513 	ret = GetDevice()->ControlTransfer(
514 				USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT | dir,
515 				request, value, index, length, data);
516 	return ret;
517 }
518 
519 // -----------------------------------------------------------------------------
520 SonixCamDeviceAddon::SonixCamDeviceAddon(WebCamMediaAddOn* webcam)
521 	: CamDeviceAddon(webcam)
522 {
523 	SetSupportedDevices(kSupportedDevices);
524 }
525 
526 // -----------------------------------------------------------------------------
527 SonixCamDeviceAddon::~SonixCamDeviceAddon()
528 {
529 }
530 
531 // -----------------------------------------------------------------------------
532 const char *
533 SonixCamDeviceAddon::BrandName()
534 {
535 	return "Sonix";
536 }
537 
538 // -----------------------------------------------------------------------------
539 SonixCamDevice *
540 SonixCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
541 {
542 	return new SonixCamDevice(*this, from);
543 }
544 
545 extern "C" status_t
546 B_WEBCAM_MKINTFUNC(sonix)
547 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
548 {
549 	*addon = new SonixCamDeviceAddon(webcam);
550 	return B_OK;
551 }
552 
553 // XXX: REMOVE ME
554 
555 
556 
557 /*
558  * BAYER2RGB24 ROUTINE TAKEN FROM:
559  *
560  * Sonix SN9C101 based webcam basic I/F routines
561  * Copyright (C) 2004 Takafumi Mizuno <taka-qce@ls-a.jp>
562  *
563  * Redistribution and use in source and binary forms, with or without
564  * modification, are permitted provided that the following conditions
565  * are met:
566  * 1. Redistributions of source code must retain the above copyright
567  *    notice, this list of conditions and the following disclaimer.
568  * 2. Redistributions in binary form must reproduce the above copyright
569  *    notice, this list of conditions and the following disclaimer in the
570  *    documentation and/or other materials provided with the distribution.
571  *
572  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
573  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
574  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
575  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
576  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
577  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
578  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
579  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
580  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
581  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
582  * SUCH DAMAGE.
583  */
584 
585 void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
586 {
587     long int i;
588     unsigned char *rawpt, *scanpt;
589     long int size;
590 
591     rawpt = src;
592     scanpt = dst;
593     size = WIDTH*HEIGHT;
594 
595     for ( i = 0; i < size; i++ ) {
596 	if ( (i/WIDTH) % 2 == 0 ) {
597 	    if ( (i % 2) == 0 ) {
598 		/* B */
599 		if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
600 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
601 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* R */
602 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
603 				 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;	/* G */
604 		    *scanpt++ = *rawpt;					/* B */
605 		} else {
606 		    /* first line or left column */
607 		    *scanpt++ = *(rawpt+WIDTH+1);		/* R */
608 		    *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;	/* G */
609 		    *scanpt++ = *rawpt;				/* B */
610 		}
611 	    } else {
612 		/* (B)G */
613 		if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
614 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* R */
615 		    *scanpt++ = *rawpt;					/* G */
616 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
617 		} else {
618 		    /* first line or right column */
619 		    *scanpt++ = *(rawpt+WIDTH);	/* R */
620 		    *scanpt++ = *rawpt;		/* G */
621 		    *scanpt++ = *(rawpt-1);	/* B */
622 		}
623 	    }
624 	} else {
625 	    if ( (i % 2) == 0 ) {
626 		/* G(R) */
627 		if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
628 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
629 		    *scanpt++ = *rawpt;					/* G */
630 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* B */
631 		} else {
632 		    /* bottom line or left column */
633 		    *scanpt++ = *(rawpt+1);		/* R */
634 		    *scanpt++ = *rawpt;			/* G */
635 		    *scanpt++ = *(rawpt-WIDTH);		/* B */
636 		}
637 	    } else {
638 		/* R */
639 		if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
640 		    *scanpt++ = *rawpt;					/* R */
641 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
642 				 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;	/* G */
643 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
644 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* B */
645 		} else {
646 		    /* bottom line or right column */
647 		    *scanpt++ = *rawpt;				/* R */
648 		    *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;	/* G */
649 		    *scanpt++ = *(rawpt-WIDTH-1);		/* B */
650 		}
651 	    }
652 	}
653 	rawpt++;
654     }
655 
656 }
657 
658 /* modified bayer2rgb24 to output rgb-32 little endian (B_RGB32)
659  * François Revol
660  */
661 
662 void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
663 {
664     long int i;
665     unsigned char *rawpt, *scanpt;
666     long int size;
667 
668     rawpt = src;
669     scanpt = dst;
670     size = WIDTH*HEIGHT;
671 
672     for ( i = 0; i < size; i++ ) {
673 	if ( (i/WIDTH) % 2 == 0 ) {
674 	    if ( (i % 2) == 0 ) {
675 		/* B */
676 		if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
677 		    *scanpt++ = *rawpt;					/* B */
678 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
679 				 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;	/* G */
680 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
681 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* R */
682 		} else {
683 		    /* first line or left column */
684 		    *scanpt++ = *rawpt;				/* B */
685 		    *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;	/* G */
686 		    *scanpt++ = *(rawpt+WIDTH+1);		/* R */
687 		}
688 	    } else {
689 		/* (B)G */
690 		if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
691 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
692 		    *scanpt++ = *rawpt;					/* G */
693 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* R */
694 		} else {
695 		    /* first line or right column */
696 		    *scanpt++ = *(rawpt-1);	/* B */
697 		    *scanpt++ = *rawpt;		/* G */
698 		    *scanpt++ = *(rawpt+WIDTH);	/* R */
699 		}
700 	    }
701 	} else {
702 	    if ( (i % 2) == 0 ) {
703 		/* G(R) */
704 		if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
705 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* B */
706 		    *scanpt++ = *rawpt;					/* G */
707 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
708 		} else {
709 		    /* bottom line or left column */
710 		    *scanpt++ = *(rawpt-WIDTH);		/* B */
711 		    *scanpt++ = *rawpt;			/* G */
712 		    *scanpt++ = *(rawpt+1);		/* R */
713 		}
714 	    } else {
715 		/* R */
716 		if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
717 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
718 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* B */
719 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
720 				 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;	/* G */
721 		    *scanpt++ = *rawpt;					/* R */
722 		} else {
723 		    /* bottom line or right column */
724 		    *scanpt++ = *(rawpt-WIDTH-1);		/* B */
725 		    *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;	/* G */
726 		    *scanpt++ = *rawpt;				/* R */
727 		}
728 	    }
729 	}
730 	rawpt++;
731 	scanpt++;
732     }
733 
734 }
735 
736 
737