Full support for Ginger Console
[linux-ginger.git] / drivers / media / video / pvrusb2 / pvrusb2-i2c-core.c
bloba334b1a966a2a4b07f3dc44f2398a9a12c095550
1 /*
4 * Copyright (C) 2005 Mike Isely <isely@pobox.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <linux/i2c.h>
22 #include "pvrusb2-i2c-core.h"
23 #include "pvrusb2-hdw-internal.h"
24 #include "pvrusb2-debug.h"
25 #include "pvrusb2-fx2-cmd.h"
26 #include "pvrusb2.h"
28 #define trace_i2c(...) pvr2_trace(PVR2_TRACE_I2C,__VA_ARGS__)
32 This module attempts to implement a compliant I2C adapter for the pvrusb2
33 device.
37 static unsigned int i2c_scan;
38 module_param(i2c_scan, int, S_IRUGO|S_IWUSR);
39 MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
41 static int ir_mode[PVR_NUM] = { [0 ... PVR_NUM-1] = 1 };
42 module_param_array(ir_mode, int, NULL, 0444);
43 MODULE_PARM_DESC(ir_mode,"specify: 0=disable IR reception, 1=normal IR");
45 static int pvr2_disable_ir_video;
46 module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video,
47 int, S_IRUGO|S_IWUSR);
48 MODULE_PARM_DESC(disable_autoload_ir_video,
49 "1=do not try to autoload ir_video IR receiver");
51 /* Mapping of IR schemes to known I2C addresses - if any */
52 static const unsigned char ir_video_addresses[] = {
53 [PVR2_IR_SCHEME_29XXX] = 0x18,
54 [PVR2_IR_SCHEME_24XXX] = 0x18,
57 static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
58 u8 i2c_addr, /* I2C address we're talking to */
59 u8 *data, /* Data to write */
60 u16 length) /* Size of data to write */
62 /* Return value - default 0 means success */
63 int ret;
66 if (!data) length = 0;
67 if (length > (sizeof(hdw->cmd_buffer) - 3)) {
68 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
69 "Killing an I2C write to %u that is too large"
70 " (desired=%u limit=%u)",
71 i2c_addr,
72 length,(unsigned int)(sizeof(hdw->cmd_buffer) - 3));
73 return -ENOTSUPP;
76 LOCK_TAKE(hdw->ctl_lock);
78 /* Clear the command buffer (likely to be paranoia) */
79 memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
81 /* Set up command buffer for an I2C write */
82 hdw->cmd_buffer[0] = FX2CMD_I2C_WRITE; /* write prefix */
83 hdw->cmd_buffer[1] = i2c_addr; /* i2c addr of chip */
84 hdw->cmd_buffer[2] = length; /* length of what follows */
85 if (length) memcpy(hdw->cmd_buffer + 3, data, length);
87 /* Do the operation */
88 ret = pvr2_send_request(hdw,
89 hdw->cmd_buffer,
90 length + 3,
91 hdw->cmd_buffer,
92 1);
93 if (!ret) {
94 if (hdw->cmd_buffer[0] != 8) {
95 ret = -EIO;
96 if (hdw->cmd_buffer[0] != 7) {
97 trace_i2c("unexpected status"
98 " from i2_write[%d]: %d",
99 i2c_addr,hdw->cmd_buffer[0]);
104 LOCK_GIVE(hdw->ctl_lock);
106 return ret;
109 static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
110 u8 i2c_addr, /* I2C address we're talking to */
111 u8 *data, /* Data to write */
112 u16 dlen, /* Size of data to write */
113 u8 *res, /* Where to put data we read */
114 u16 rlen) /* Amount of data to read */
116 /* Return value - default 0 means success */
117 int ret;
120 if (!data) dlen = 0;
121 if (dlen > (sizeof(hdw->cmd_buffer) - 4)) {
122 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
123 "Killing an I2C read to %u that has wlen too large"
124 " (desired=%u limit=%u)",
125 i2c_addr,
126 dlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 4));
127 return -ENOTSUPP;
129 if (res && (rlen > (sizeof(hdw->cmd_buffer) - 1))) {
130 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
131 "Killing an I2C read to %u that has rlen too large"
132 " (desired=%u limit=%u)",
133 i2c_addr,
134 rlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 1));
135 return -ENOTSUPP;
138 LOCK_TAKE(hdw->ctl_lock);
140 /* Clear the command buffer (likely to be paranoia) */
141 memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
143 /* Set up command buffer for an I2C write followed by a read */
144 hdw->cmd_buffer[0] = FX2CMD_I2C_READ; /* read prefix */
145 hdw->cmd_buffer[1] = dlen; /* arg length */
146 hdw->cmd_buffer[2] = rlen; /* answer length. Device will send one
147 more byte (status). */
148 hdw->cmd_buffer[3] = i2c_addr; /* i2c addr of chip */
149 if (dlen) memcpy(hdw->cmd_buffer + 4, data, dlen);
151 /* Do the operation */
152 ret = pvr2_send_request(hdw,
153 hdw->cmd_buffer,
154 4 + dlen,
155 hdw->cmd_buffer,
156 rlen + 1);
157 if (!ret) {
158 if (hdw->cmd_buffer[0] != 8) {
159 ret = -EIO;
160 if (hdw->cmd_buffer[0] != 7) {
161 trace_i2c("unexpected status"
162 " from i2_read[%d]: %d",
163 i2c_addr,hdw->cmd_buffer[0]);
168 /* Copy back the result */
169 if (res && rlen) {
170 if (ret) {
171 /* Error, just blank out the return buffer */
172 memset(res, 0, rlen);
173 } else {
174 memcpy(res, hdw->cmd_buffer + 1, rlen);
178 LOCK_GIVE(hdw->ctl_lock);
180 return ret;
183 /* This is the common low level entry point for doing I2C operations to the
184 hardware. */
185 static int pvr2_i2c_basic_op(struct pvr2_hdw *hdw,
186 u8 i2c_addr,
187 u8 *wdata,
188 u16 wlen,
189 u8 *rdata,
190 u16 rlen)
192 if (!rdata) rlen = 0;
193 if (!wdata) wlen = 0;
194 if (rlen || !wlen) {
195 return pvr2_i2c_read(hdw,i2c_addr,wdata,wlen,rdata,rlen);
196 } else {
197 return pvr2_i2c_write(hdw,i2c_addr,wdata,wlen);
202 /* This is a special entry point for cases of I2C transaction attempts to
203 the IR receiver. The implementation here simulates the IR receiver by
204 issuing a command to the FX2 firmware and using that response to return
205 what the real I2C receiver would have returned. We use this for 24xxx
206 devices, where the IR receiver chip has been removed and replaced with
207 FX2 related logic. */
208 static int i2c_24xxx_ir(struct pvr2_hdw *hdw,
209 u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
211 u8 dat[4];
212 unsigned int stat;
214 if (!(rlen || wlen)) {
215 /* This is a probe attempt. Just let it succeed. */
216 return 0;
219 /* We don't understand this kind of transaction */
220 if ((wlen != 0) || (rlen == 0)) return -EIO;
222 if (rlen < 3) {
223 /* Mike Isely <isely@pobox.com> Appears to be a probe
224 attempt from lirc. Just fill in zeroes and return. If
225 we try instead to do the full transaction here, then bad
226 things seem to happen within the lirc driver module
227 (version 0.8.0-7 sources from Debian, when run under
228 vanilla 2.6.17.6 kernel) - and I don't have the patience
229 to chase it down. */
230 if (rlen > 0) rdata[0] = 0;
231 if (rlen > 1) rdata[1] = 0;
232 return 0;
235 /* Issue a command to the FX2 to read the IR receiver. */
236 LOCK_TAKE(hdw->ctl_lock); do {
237 hdw->cmd_buffer[0] = FX2CMD_GET_IR_CODE;
238 stat = pvr2_send_request(hdw,
239 hdw->cmd_buffer,1,
240 hdw->cmd_buffer,4);
241 dat[0] = hdw->cmd_buffer[0];
242 dat[1] = hdw->cmd_buffer[1];
243 dat[2] = hdw->cmd_buffer[2];
244 dat[3] = hdw->cmd_buffer[3];
245 } while (0); LOCK_GIVE(hdw->ctl_lock);
247 /* Give up if that operation failed. */
248 if (stat != 0) return stat;
250 /* Mangle the results into something that looks like the real IR
251 receiver. */
252 rdata[2] = 0xc1;
253 if (dat[0] != 1) {
254 /* No code received. */
255 rdata[0] = 0;
256 rdata[1] = 0;
257 } else {
258 u16 val;
259 /* Mash the FX2 firmware-provided IR code into something
260 that the normal i2c chip-level driver expects. */
261 val = dat[1];
262 val <<= 8;
263 val |= dat[2];
264 val >>= 1;
265 val &= ~0x0003;
266 val |= 0x8000;
267 rdata[0] = (val >> 8) & 0xffu;
268 rdata[1] = val & 0xffu;
271 return 0;
274 /* This is a special entry point that is entered if an I2C operation is
275 attempted to a wm8775 chip on model 24xxx hardware. Autodetect of this
276 part doesn't work, but we know it is really there. So let's look for
277 the autodetect attempt and just return success if we see that. */
278 static int i2c_hack_wm8775(struct pvr2_hdw *hdw,
279 u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
281 if (!(rlen || wlen)) {
282 // This is a probe attempt. Just let it succeed.
283 return 0;
285 return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
288 /* This is an entry point designed to always fail any attempt to perform a
289 transfer. We use this to cause certain I2C addresses to not be
290 probed. */
291 static int i2c_black_hole(struct pvr2_hdw *hdw,
292 u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
294 return -EIO;
297 /* This is a special entry point that is entered if an I2C operation is
298 attempted to a cx25840 chip on model 24xxx hardware. This chip can
299 sometimes wedge itself. Worse still, when this happens msp3400 can
300 falsely detect this part and then the system gets hosed up after msp3400
301 gets confused and dies. What we want to do here is try to keep msp3400
302 away and also try to notice if the chip is wedged and send a warning to
303 the system log. */
304 static int i2c_hack_cx25840(struct pvr2_hdw *hdw,
305 u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
307 int ret;
308 unsigned int subaddr;
309 u8 wbuf[2];
310 int state = hdw->i2c_cx25840_hack_state;
312 if (!(rlen || wlen)) {
313 // Probe attempt - always just succeed and don't bother the
314 // hardware (this helps to make the state machine further
315 // down somewhat easier).
316 return 0;
319 if (state == 3) {
320 return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
323 /* We're looking for the exact pattern where the revision register
324 is being read. The cx25840 module will always look at the
325 revision register first. Any other pattern of access therefore
326 has to be a probe attempt from somebody else so we'll reject it.
327 Normally we could just let each client just probe the part
328 anyway, but when the cx25840 is wedged, msp3400 will get a false
329 positive and that just screws things up... */
331 if (wlen == 0) {
332 switch (state) {
333 case 1: subaddr = 0x0100; break;
334 case 2: subaddr = 0x0101; break;
335 default: goto fail;
337 } else if (wlen == 2) {
338 subaddr = (wdata[0] << 8) | wdata[1];
339 switch (subaddr) {
340 case 0x0100: state = 1; break;
341 case 0x0101: state = 2; break;
342 default: goto fail;
344 } else {
345 goto fail;
347 if (!rlen) goto success;
348 state = 0;
349 if (rlen != 1) goto fail;
351 /* If we get to here then we have a legitimate read for one of the
352 two revision bytes, so pass it through. */
353 wbuf[0] = subaddr >> 8;
354 wbuf[1] = subaddr;
355 ret = pvr2_i2c_basic_op(hdw,i2c_addr,wbuf,2,rdata,rlen);
357 if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) {
358 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
359 "WARNING: Detected a wedged cx25840 chip;"
360 " the device will not work.");
361 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
362 "WARNING: Try power cycling the pvrusb2 device.");
363 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
364 "WARNING: Disabling further access to the device"
365 " to prevent other foul-ups.");
366 // This blocks all further communication with the part.
367 hdw->i2c_func[0x44] = NULL;
368 pvr2_hdw_render_useless(hdw);
369 goto fail;
372 /* Success! */
373 pvr2_trace(PVR2_TRACE_CHIPS,"cx25840 appears to be OK.");
374 state = 3;
376 success:
377 hdw->i2c_cx25840_hack_state = state;
378 return 0;
380 fail:
381 hdw->i2c_cx25840_hack_state = state;
382 return -EIO;
385 /* This is a very, very limited I2C adapter implementation. We can only
386 support what we actually know will work on the device... */
387 static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
388 struct i2c_msg msgs[],
389 int num)
391 int ret = -ENOTSUPP;
392 pvr2_i2c_func funcp = NULL;
393 struct pvr2_hdw *hdw = (struct pvr2_hdw *)(i2c_adap->algo_data);
395 if (!num) {
396 ret = -EINVAL;
397 goto done;
399 if (msgs[0].addr < PVR2_I2C_FUNC_CNT) {
400 funcp = hdw->i2c_func[msgs[0].addr];
402 if (!funcp) {
403 ret = -EIO;
404 goto done;
407 if (num == 1) {
408 if (msgs[0].flags & I2C_M_RD) {
409 /* Simple read */
410 u16 tcnt,bcnt,offs;
411 if (!msgs[0].len) {
412 /* Length == 0 read. This is a probe. */
413 if (funcp(hdw,msgs[0].addr,NULL,0,NULL,0)) {
414 ret = -EIO;
415 goto done;
417 ret = 1;
418 goto done;
420 /* If the read is short enough we'll do the whole
421 thing atomically. Otherwise we have no choice
422 but to break apart the reads. */
423 tcnt = msgs[0].len;
424 offs = 0;
425 while (tcnt) {
426 bcnt = tcnt;
427 if (bcnt > sizeof(hdw->cmd_buffer)-1) {
428 bcnt = sizeof(hdw->cmd_buffer)-1;
430 if (funcp(hdw,msgs[0].addr,NULL,0,
431 msgs[0].buf+offs,bcnt)) {
432 ret = -EIO;
433 goto done;
435 offs += bcnt;
436 tcnt -= bcnt;
438 ret = 1;
439 goto done;
440 } else {
441 /* Simple write */
442 ret = 1;
443 if (funcp(hdw,msgs[0].addr,
444 msgs[0].buf,msgs[0].len,NULL,0)) {
445 ret = -EIO;
447 goto done;
449 } else if (num == 2) {
450 if (msgs[0].addr != msgs[1].addr) {
451 trace_i2c("i2c refusing 2 phase transfer with"
452 " conflicting target addresses");
453 ret = -ENOTSUPP;
454 goto done;
456 if ((!((msgs[0].flags & I2C_M_RD))) &&
457 (msgs[1].flags & I2C_M_RD)) {
458 u16 tcnt,bcnt,wcnt,offs;
459 /* Write followed by atomic read. If the read
460 portion is short enough we'll do the whole thing
461 atomically. Otherwise we have no choice but to
462 break apart the reads. */
463 tcnt = msgs[1].len;
464 wcnt = msgs[0].len;
465 offs = 0;
466 while (tcnt || wcnt) {
467 bcnt = tcnt;
468 if (bcnt > sizeof(hdw->cmd_buffer)-1) {
469 bcnt = sizeof(hdw->cmd_buffer)-1;
471 if (funcp(hdw,msgs[0].addr,
472 msgs[0].buf,wcnt,
473 msgs[1].buf+offs,bcnt)) {
474 ret = -EIO;
475 goto done;
477 offs += bcnt;
478 tcnt -= bcnt;
479 wcnt = 0;
481 ret = 2;
482 goto done;
483 } else {
484 trace_i2c("i2c refusing complex transfer"
485 " read0=%d read1=%d",
486 (msgs[0].flags & I2C_M_RD),
487 (msgs[1].flags & I2C_M_RD));
489 } else {
490 trace_i2c("i2c refusing %d phase transfer",num);
493 done:
494 if (pvrusb2_debug & PVR2_TRACE_I2C_TRAF) {
495 unsigned int idx,offs,cnt;
496 for (idx = 0; idx < num; idx++) {
497 cnt = msgs[idx].len;
498 printk(KERN_INFO
499 "pvrusb2 i2c xfer %u/%u:"
500 " addr=0x%x len=%d %s",
501 idx+1,num,
502 msgs[idx].addr,
503 cnt,
504 (msgs[idx].flags & I2C_M_RD ?
505 "read" : "write"));
506 if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) {
507 if (cnt > 8) cnt = 8;
508 printk(" [");
509 for (offs = 0; offs < (cnt>8?8:cnt); offs++) {
510 if (offs) printk(" ");
511 printk("%02x",msgs[idx].buf[offs]);
513 if (offs < cnt) printk(" ...");
514 printk("]");
516 if (idx+1 == num) {
517 printk(" result=%d",ret);
519 printk("\n");
521 if (!num) {
522 printk(KERN_INFO
523 "pvrusb2 i2c xfer null transfer result=%d\n",
524 ret);
527 return ret;
530 static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
532 return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
535 static struct i2c_algorithm pvr2_i2c_algo_template = {
536 .master_xfer = pvr2_i2c_xfer,
537 .functionality = pvr2_i2c_functionality,
540 static struct i2c_adapter pvr2_i2c_adap_template = {
541 .owner = THIS_MODULE,
542 .class = 0,
546 /* Return true if device exists at given address */
547 static int do_i2c_probe(struct pvr2_hdw *hdw, int addr)
549 struct i2c_msg msg[1];
550 int rc;
551 msg[0].addr = 0;
552 msg[0].flags = I2C_M_RD;
553 msg[0].len = 0;
554 msg[0].buf = NULL;
555 msg[0].addr = addr;
556 rc = i2c_transfer(&hdw->i2c_adap, msg, ARRAY_SIZE(msg));
557 return rc == 1;
560 static void do_i2c_scan(struct pvr2_hdw *hdw)
562 int i;
563 printk(KERN_INFO "%s: i2c scan beginning\n", hdw->name);
564 for (i = 0; i < 128; i++) {
565 if (do_i2c_probe(hdw, i)) {
566 printk(KERN_INFO "%s: i2c scan: found device @ 0x%x\n",
567 hdw->name, i);
570 printk(KERN_INFO "%s: i2c scan done.\n", hdw->name);
573 static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
575 struct i2c_board_info info;
576 unsigned char addr = 0;
577 if (pvr2_disable_ir_video) {
578 pvr2_trace(PVR2_TRACE_INFO,
579 "Automatic binding of ir_video has been disabled.");
580 return;
582 if (hdw->ir_scheme_active < ARRAY_SIZE(ir_video_addresses)) {
583 addr = ir_video_addresses[hdw->ir_scheme_active];
585 if (!addr) {
586 /* The device either doesn't support I2C-based IR or we
587 don't know (yet) how to operate IR on the device. */
588 return;
590 pvr2_trace(PVR2_TRACE_INFO,
591 "Binding ir_video to i2c address 0x%02x.", addr);
592 memset(&info, 0, sizeof(struct i2c_board_info));
593 strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
594 info.addr = addr;
595 i2c_new_device(&hdw->i2c_adap, &info);
598 void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
600 unsigned int idx;
602 /* The default action for all possible I2C addresses is just to do
603 the transfer normally. */
604 for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) {
605 hdw->i2c_func[idx] = pvr2_i2c_basic_op;
608 /* However, deal with various special cases for 24xxx hardware. */
609 if (ir_mode[hdw->unit_number] == 0) {
610 printk(KERN_INFO "%s: IR disabled\n",hdw->name);
611 hdw->i2c_func[0x18] = i2c_black_hole;
612 } else if (ir_mode[hdw->unit_number] == 1) {
613 if (hdw->ir_scheme_active == PVR2_IR_SCHEME_24XXX) {
614 /* Set up translation so that our IR looks like a
615 29xxx device */
616 hdw->i2c_func[0x18] = i2c_24xxx_ir;
619 if (hdw->hdw_desc->flag_has_cx25840) {
620 hdw->i2c_func[0x44] = i2c_hack_cx25840;
622 if (hdw->hdw_desc->flag_has_wm8775) {
623 hdw->i2c_func[0x1b] = i2c_hack_wm8775;
626 // Configure the adapter and set up everything else related to it.
627 memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
628 memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo));
629 strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name));
630 hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
631 hdw->i2c_adap.algo = &hdw->i2c_algo;
632 hdw->i2c_adap.algo_data = hdw;
633 hdw->i2c_linked = !0;
634 i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
635 i2c_add_adapter(&hdw->i2c_adap);
636 if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
637 /* Probe for a different type of IR receiver on this
638 device. This is really the only way to differentiate
639 older 24xxx devices from 24xxx variants that include an
640 IR blaster. If the IR blaster is present, the IR
641 receiver is part of that chip and thus we must disable
642 the emulated IR receiver. */
643 if (do_i2c_probe(hdw, 0x71)) {
644 pvr2_trace(PVR2_TRACE_INFO,
645 "Device has newer IR hardware;"
646 " disabling unneeded virtual IR device");
647 hdw->i2c_func[0x18] = NULL;
648 /* Remember that this is a different device... */
649 hdw->ir_scheme_active = PVR2_IR_SCHEME_24XXX_MCE;
652 if (i2c_scan) do_i2c_scan(hdw);
654 pvr2_i2c_register_ir(hdw);
657 void pvr2_i2c_core_done(struct pvr2_hdw *hdw)
659 if (hdw->i2c_linked) {
660 i2c_del_adapter(&hdw->i2c_adap);
661 hdw->i2c_linked = 0;
666 Stuff for Emacs to see, in order to encourage consistent editing style:
667 *** Local Variables: ***
668 *** mode: c ***
669 *** fill-column: 75 ***
670 *** tab-width: 8 ***
671 *** c-basic-offset: 8 ***
672 *** End: ***