xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/addons/sonix/SonixCamDevice.cpp (revision 89755088d790ff4fe36f8aa77dacb2bd15507108)
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 		uint32 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 buffer[8];
232 	if (!Sensor())
233 		return B_NO_INIT;
234 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
235 	count++; // includes address
236 	if (count > 5)
237 		return EINVAL;
238 	buffer[0] = (count << 4) | Sensor()->Use400kHz()?0x01:0
239 							 | Sensor()->UseRealIIC()?0x80:0;
240 	buffer[1] = Sensor()->IICWriteAddress();
241 	buffer[2] = address;
242 	memset(&buffer[3], 0, 5);
243 	memcpy(&buffer[3], data, count);
244 	buffer[7] = 0x14; /* absolutely no idea why V4L2 driver use that value */
245 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
246 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
247 	//PRINT((CH ": WriteReg: %s" CT, strerror(err)));
248 	if (err < 0) return err;
249 	err = WaitReadyIIC();
250 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
251 	//PRINT((CH ": Wait: %s" CT, strerror(err)));
252 	if (err) return err;
253 	err = GetStatusIIC();
254 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err);
255 	//PRINT((CH ": Status: %s" CT, strerror(err)));
256 	if (err) return err;
257 	//dprintf(ID "sonix_i2c_write_multi: succeeded\n");
258 	PRINT((CH ": success" CT));
259 	return B_OK;
260 }
261 
262 // -----------------------------------------------------------------------------
263 ssize_t
264 SonixCamDevice::ReadIIC(uint8 address, uint8 *data)
265 {
266 	status_t err, lasterr = B_OK;
267 	uint8 buffer[8];
268 	if (!Sensor())
269 		return B_NO_INIT;
270 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
271 	buffer[0] = (1 << 4) | Sensor()->Use400kHz()?0x01:0
272 						 | Sensor()->UseRealIIC()?0x80:0;
273 	buffer[1] = Sensor()->IICWriteAddress();
274 	buffer[2] = address;
275 	buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */
276 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
277 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
278 	if (err) return err;
279 	err = WaitReadyIIC();
280 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
281 	//if (err) return err;
282 
283 
284 	//dprintf(ID "sonix_i2c_write_multi(, %02x, %d, {%02x, %02x, %02x, %02x, %02x})\n", slave, count, d0, d1, d2, d3, d4);
285 	buffer[0] = (1 << 4) | Sensor()->Use400kHz()?0x01:0
286 				  | 0x02 | Sensor()->UseRealIIC()?0x80:0; /* read 1 byte */
287 	buffer[1] = Sensor()->IICReadAddress();//IICWriteAddress
288 	buffer[7] = 0x10; /* absolutely no idea why V4L2 driver use that value */
289 	err = WriteReg(SN9C102_I2C_SETUP, buffer, 8);
290 	//dprintf(ID "sonix_i2c_write_multi: set_regs error 0x%08lx\n", err);
291 	if (err) return err;
292 	err = WaitReadyIIC();
293 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_wait_ready error 0x%08lx\n", err);
294 	if (err) return err;
295 
296 	err = ReadReg(SN9C102_I2C_DATA0, buffer, 5);
297 	if (err) lasterr = err;
298 
299 	err = GetStatusIIC();
300 	//dprintf(ID "sonix_i2c_write_multi: sonix_i2c_status error 0x%08lx\n", err);
301 	if (err) return err;
302 	//dprintf(ID "sonix_i2c_write_multi: succeeded\n");
303 	if (lasterr) return err;
304 
305 	/* we should get what we want in buffer[4] according to the V4L2 driver...
306 	 * probably because the 5 bytes are a bit shift register?
307 	 */
308 	*data = buffer[4];
309 
310 	return 1;
311 }
312 
313 // -----------------------------------------------------------------------------
314 status_t
315 SonixCamDevice::SetVideoFrame(BRect frame)
316 {
317 	uint16 x, y, width, height;
318 	x = (uint16)frame.left;
319 	y = (uint16)frame.top;
320 	width = (uint16)(frame.right - frame.left + 1) / 16;
321 	height = (uint16)(frame.bottom - frame.top + 1) / 16;
322 	PRINT((CH "(%u, %u, %u, %u)" CT, x, y, width, height));
323 
324 	WriteReg8(SN9C102_H_START, x);
325 	WriteReg8(SN9C102_V_START, y);
326 	WriteReg8(SN9C102_H_SIZE, width);
327 	WriteReg8(SN9C102_V_SIZE, height);
328 	if (Sensor()) {
329 		Sensor()->SetVideoFrame(frame);
330 	}
331 	return CamDevice::SetVideoFrame(frame);
332 }
333 
334 // -----------------------------------------------------------------------------
335 status_t
336 SonixCamDevice::SetScale(float scale)
337 {
338 	status_t err;
339 	uint8 r;
340 	int iscale = (int)scale;
341 
342 	PRINT((CH "(%u)" CT, iscale));
343 	err = ReadReg(SN9C102_SYNC_N_SCALE, &r, 1, true);
344 	if (err < 0)
345 		return err;
346 	r &= ~0x30;
347 	switch (iscale) {
348 	case 1:
349 	case 2:
350 	case 4:
351 		r |= ((iscale-1) << 4);
352 		break;
353 	default:
354 		return EINVAL;
355 	}
356 	err = WriteReg8(SN9C102_SYNC_N_SCALE, r);
357 	return err;
358 }
359 
360 // -----------------------------------------------------------------------------
361 status_t
362 SonixCamDevice::SetVideoParams(float brightness, float contrast, float hue, float red, float green, float blue)
363 {
364 	return B_OK;
365 }
366 
367 // -----------------------------------------------------------------------------
368 size_t
369 SonixCamDevice::MinRawFrameSize()
370 {
371 	// if (fCompressionEnabled) { ... return ; }
372 	BRect vf(VideoFrame());
373 	int w = vf.IntegerWidth()+1;
374 	int h = vf.IntegerHeight()+1;
375 	// 1 byte/pixel
376 	return (size_t)(w*h);
377 }
378 
379 // -----------------------------------------------------------------------------
380 size_t
381 SonixCamDevice::MaxRawFrameSize()
382 {
383 	// if (fCompressionEnabled) { ... return ; }
384 	return MinRawFrameSize()+1024*0; // fixed size frame (uncompressed)
385 }
386 
387 // -----------------------------------------------------------------------------
388 bool
389 SonixCamDevice::ValidateStartOfFrameTag(const uint8 *tag, size_t taglen)
390 {
391 	// SOF come with an 00, 40, 80, C0 sequence,
392 	// supposedly corresponding with an equal byte in the end tag
393 	fFrameTagState = tag[7] & 0xC0;
394 	PRINT((CH "(, %d) state %x" CT, taglen, fFrameTagState));
395 
396 	// which seems to be the same as of the EOF tag
397 	return true;
398 }
399 
400 // -----------------------------------------------------------------------------
401 bool
402 SonixCamDevice::ValidateEndOfFrameTag(const uint8 *tag, size_t taglen, size_t datalen)
403 {
404 	//PRINT((CH "(, %d) %x == %x" CT, taglen, (tag[0] & 0xC0), fFrameTagState));
405 	// make sure the tag corresponds to the SOF we refer to
406 	if ((tag[0] & 0xC0) != fFrameTagState) {
407 		PRINT((CH ": discarded EOF %x != %x" CT, fFrameTagState, tag[0] & 0xC0));
408 		return false;
409 	}
410 	//PRINT((CH ": validated EOF %x, len %d" CT, fFrameTagState, datalen));
411 	return true;
412 }
413 
414 // -----------------------------------------------------------------------------
415 status_t
416 SonixCamDevice::GetFrameBitmap(BBitmap **bm, bigtime_t *stamp /* = NULL */)
417 {
418 	BBitmap *b;
419 	CamFrame *f;
420 	status_t err;
421 	PRINT((CH "()" CT));
422 	err = fDeframer->WaitFrame(200000);
423 	if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); }
424 	if (err < B_OK)
425 		return err;
426 	err = fDeframer->GetFrame(&f, stamp);
427 	if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); }
428 	if (err < B_OK)
429 		return err;
430 	PRINT((CH ": VideoFrame = %fx%f,%fx%f" CT, VideoFrame().left, VideoFrame().top, VideoFrame().right, VideoFrame().bottom));
431 
432 	long int w = (long)(VideoFrame().right - VideoFrame().left + 1);
433 	long int h = (long)(VideoFrame().bottom - VideoFrame().top + 1);
434 	b = new BBitmap(VideoFrame().OffsetToSelf(0,0), 0, B_RGB32, w*4);
435 	PRINT((CH ": Frame: %dx%d" CT, w, h));
436 
437 	bayer2rgb24((unsigned char *)b->Bits(), (unsigned char *)f->Buffer(), w, h);
438 
439 	PRINT((CH ": got 1 frame (len %d)" CT, b->BitsLength()));
440 	*bm = b;
441 	return B_OK;
442 }
443 
444 // -----------------------------------------------------------------------------
445 status_t
446 SonixCamDevice::FillFrameBuffer(BBuffer *buffer, bigtime_t *stamp)
447 {
448 	CamFrame *f;
449 	status_t err;
450 	PRINT((CH "()" CT));
451 
452 	memset(buffer->Data(), 0, buffer->SizeAvailable());
453 	err = fDeframer->WaitFrame(2000000);
454 	if (err < B_OK) { PRINT((CH ": WaitFrame: %s" CT, strerror(err))); }
455 	if (err < B_OK)
456 		return err;
457 
458 	err = fDeframer->GetFrame(&f, stamp);
459 	if (err < B_OK) { PRINT((CH ": GetFrame: %s" CT, strerror(err))); }
460 	if (err < B_OK)
461 		return err;
462 
463 	long int w = (long)(VideoFrame().right - VideoFrame().left + 1);
464 	long int h = (long)(VideoFrame().bottom - VideoFrame().top + 1);
465 	PRINT((CH ": VideoFrame = %fx%f,%fx%f Frame: %dx%d" CT, VideoFrame().left, VideoFrame().top, VideoFrame().right, VideoFrame().bottom, w, h));
466 
467 	if (buffer->SizeAvailable() >= (size_t)w*h*4)
468 		bayer2rgb32le((unsigned char *)buffer->Data(), (unsigned char *)f->Buffer(), w, h);
469 
470 	delete f;
471 
472 	PRINT((CH ": available %d, required %d" CT, buffer->SizeAvailable(), w*h*4));
473 	if (buffer->SizeAvailable() < (size_t)w*h*4)
474 		return E2BIG;
475 	PRINT((CH ": got 1 frame (len %d)" CT, buffer->SizeUsed()));
476 	return B_OK;
477 }
478 
479 // -----------------------------------------------------------------------------
480 void
481 /* DEBUG: dump the SN regs */
482 SonixCamDevice::DumpRegs()
483 {
484 	uint8 regs[SN9C102_REG_COUNT];
485 	status_t err;
486 
487 	//err = sonix_get_regs(dev, SN_ASIC_ID, regs, SN_REG_COUNT);
488 	err = ReadReg(0, regs, SN9C102_REG_COUNT);
489 	if (err < 0)
490 		return;
491 	printf("REG1: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
492 			regs[0], regs[1], regs[2], regs[3], regs[4], regs[5], regs[6], regs[7]);
493 	printf("   2: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
494 			regs[8], regs[9], regs[10], regs[11], regs[12], regs[13], regs[14], regs[15]);
495 	printf("   3: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
496 			regs[16], regs[17], regs[18], regs[19], regs[20], regs[21], regs[22], regs[23]);
497 	printf("   4: %02x %02x %02x %02x  %02x %02x %02x %02x\n",
498 			regs[24], regs[25], regs[26], regs[27], regs[28], regs[29], regs[30], regs[31]);
499 }
500 
501 // -----------------------------------------------------------------------------
502 status_t
503 SonixCamDevice::SendCommand(uint8 dir, uint8 request, uint16 value,
504 							uint16 index, uint16 length, void* data)
505 {
506 	size_t ret;
507 	if (length > 64)
508 		return EINVAL;
509 	if (!GetDevice())
510 		return ENODEV;
511 	ret = GetDevice()->ControlTransfer(
512 				USB_REQTYPE_VENDOR | USB_REQTYPE_INTERFACE_OUT | dir,
513 				request, value, index, length, data);
514 	return ret;
515 }
516 
517 // -----------------------------------------------------------------------------
518 SonixCamDeviceAddon::SonixCamDeviceAddon(WebCamMediaAddOn* webcam)
519 	: CamDeviceAddon(webcam)
520 {
521 	SetSupportedDevices(kSupportedDevices);
522 }
523 
524 // -----------------------------------------------------------------------------
525 SonixCamDeviceAddon::~SonixCamDeviceAddon()
526 {
527 }
528 
529 // -----------------------------------------------------------------------------
530 const char *
531 SonixCamDeviceAddon::BrandName()
532 {
533 	return "Sonix";
534 }
535 
536 // -----------------------------------------------------------------------------
537 SonixCamDevice *
538 SonixCamDeviceAddon::Instantiate(CamRoster &roster, BUSBDevice *from)
539 {
540 	return new SonixCamDevice(*this, from);
541 }
542 
543 extern "C" status_t
544 B_WEBCAM_MKINTFUNC(sonix)
545 (WebCamMediaAddOn* webcam, CamDeviceAddon **addon)
546 {
547 	*addon = new SonixCamDeviceAddon(webcam);
548 	return B_OK;
549 }
550 
551 // XXX: REMOVE ME
552 
553 
554 
555 /*
556  * BAYER2RGB24 ROUTINE TAKEN FROM:
557  *
558  * Sonix SN9C101 based webcam basic I/F routines
559  * Copyright (C) 2004 Takafumi Mizuno <taka-qce@ls-a.jp>
560  *
561  * Redistribution and use in source and binary forms, with or without
562  * modification, are permitted provided that the following conditions
563  * are met:
564  * 1. Redistributions of source code must retain the above copyright
565  *    notice, this list of conditions and the following disclaimer.
566  * 2. Redistributions in binary form must reproduce the above copyright
567  *    notice, this list of conditions and the following disclaimer in the
568  *    documentation and/or other materials provided with the distribution.
569  *
570  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
571  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
572  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
573  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
574  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
575  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
576  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
577  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
578  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
579  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
580  * SUCH DAMAGE.
581  */
582 
583 void bayer2rgb24(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
584 {
585     long int i;
586     unsigned char *rawpt, *scanpt;
587     long int size;
588 
589     rawpt = src;
590     scanpt = dst;
591     size = WIDTH*HEIGHT;
592 
593     for ( i = 0; i < size; i++ ) {
594 	if ( (i/WIDTH) % 2 == 0 ) {
595 	    if ( (i % 2) == 0 ) {
596 		/* B */
597 		if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
598 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
599 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* R */
600 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
601 				 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;	/* G */
602 		    *scanpt++ = *rawpt;					/* B */
603 		} else {
604 		    /* first line or left column */
605 		    *scanpt++ = *(rawpt+WIDTH+1);		/* R */
606 		    *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;	/* G */
607 		    *scanpt++ = *rawpt;				/* B */
608 		}
609 	    } else {
610 		/* (B)G */
611 		if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
612 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* R */
613 		    *scanpt++ = *rawpt;					/* G */
614 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
615 		} else {
616 		    /* first line or right column */
617 		    *scanpt++ = *(rawpt+WIDTH);	/* R */
618 		    *scanpt++ = *rawpt;		/* G */
619 		    *scanpt++ = *(rawpt-1);	/* B */
620 		}
621 	    }
622 	} else {
623 	    if ( (i % 2) == 0 ) {
624 		/* G(R) */
625 		if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
626 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
627 		    *scanpt++ = *rawpt;					/* G */
628 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* B */
629 		} else {
630 		    /* bottom line or left column */
631 		    *scanpt++ = *(rawpt+1);		/* R */
632 		    *scanpt++ = *rawpt;			/* G */
633 		    *scanpt++ = *(rawpt-WIDTH);		/* B */
634 		}
635 	    } else {
636 		/* R */
637 		if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
638 		    *scanpt++ = *rawpt;					/* R */
639 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
640 				 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;	/* G */
641 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
642 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* B */
643 		} else {
644 		    /* bottom line or right column */
645 		    *scanpt++ = *rawpt;				/* R */
646 		    *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;	/* G */
647 		    *scanpt++ = *(rawpt-WIDTH-1);		/* B */
648 		}
649 	    }
650 	}
651 	rawpt++;
652     }
653 
654 }
655 
656 /* modified bayer2rgb24 to output rgb-32 little endian (B_RGB32)
657  * François Revol
658  */
659 
660 void bayer2rgb32le(unsigned char *dst, unsigned char *src, long int WIDTH, long int HEIGHT)
661 {
662     long int i;
663     unsigned char *rawpt, *scanpt;
664     long int size;
665 
666     rawpt = src;
667     scanpt = dst;
668     size = WIDTH*HEIGHT;
669 
670     for ( i = 0; i < size; i++ ) {
671 	if ( (i/WIDTH) % 2 == 0 ) {
672 	    if ( (i % 2) == 0 ) {
673 		/* B */
674 		if ( (i > WIDTH) && ((i % WIDTH) > 0) ) {
675 		    *scanpt++ = *rawpt;					/* B */
676 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
677 				 *(rawpt+WIDTH)+*(rawpt-WIDTH))/4;	/* G */
678 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
679 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* R */
680 		} else {
681 		    /* first line or left column */
682 		    *scanpt++ = *rawpt;				/* B */
683 		    *scanpt++ = (*(rawpt+1)+*(rawpt+WIDTH))/2;	/* G */
684 		    *scanpt++ = *(rawpt+WIDTH+1);		/* R */
685 		}
686 	    } else {
687 		/* (B)G */
688 		if ( (i > WIDTH) && ((i % WIDTH) < (WIDTH-1)) ) {
689 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* B */
690 		    *scanpt++ = *rawpt;					/* G */
691 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* R */
692 		} else {
693 		    /* first line or right column */
694 		    *scanpt++ = *(rawpt-1);	/* B */
695 		    *scanpt++ = *rawpt;		/* G */
696 		    *scanpt++ = *(rawpt+WIDTH);	/* R */
697 		}
698 	    }
699 	} else {
700 	    if ( (i % 2) == 0 ) {
701 		/* G(R) */
702 		if ( (i < (WIDTH*(HEIGHT-1))) && ((i % WIDTH) > 0) ) {
703 		    *scanpt++ = (*(rawpt+WIDTH)+*(rawpt-WIDTH))/2;	/* B */
704 		    *scanpt++ = *rawpt;					/* G */
705 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1))/2;		/* R */
706 		} else {
707 		    /* bottom line or left column */
708 		    *scanpt++ = *(rawpt-WIDTH);		/* B */
709 		    *scanpt++ = *rawpt;			/* G */
710 		    *scanpt++ = *(rawpt+1);		/* R */
711 		}
712 	    } else {
713 		/* R */
714 		if ( i < (WIDTH*(HEIGHT-1)) && ((i % WIDTH) < (WIDTH-1)) ) {
715 		    *scanpt++ = (*(rawpt-WIDTH-1)+*(rawpt-WIDTH+1)+
716 				 *(rawpt+WIDTH-1)+*(rawpt+WIDTH+1))/4;	/* B */
717 		    *scanpt++ = (*(rawpt-1)+*(rawpt+1)+
718 				 *(rawpt-WIDTH)+*(rawpt+WIDTH))/4;	/* G */
719 		    *scanpt++ = *rawpt;					/* R */
720 		} else {
721 		    /* bottom line or right column */
722 		    *scanpt++ = *(rawpt-WIDTH-1);		/* B */
723 		    *scanpt++ = (*(rawpt-1)+*(rawpt-WIDTH))/2;	/* G */
724 		    *scanpt++ = *rawpt;				/* R */
725 		}
726 	    }
727 	}
728 	rawpt++;
729 	scanpt++;
730     }
731 
732 }
733 
734 
735