Linux 2.6.34-rc3
[pohmelfs.git] / drivers / media / video / pvrusb2 / pvrusb2-i2c-core.c
blob7cbe18c4ca9568f75f0c8f7d837e9e8981ac06e1
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_ZILOG] = 0x71,
54 [PVR2_IR_SCHEME_29XXX] = 0x18,
55 [PVR2_IR_SCHEME_24XXX] = 0x18,
58 static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
59 u8 i2c_addr, /* I2C address we're talking to */
60 u8 *data, /* Data to write */
61 u16 length) /* Size of data to write */
63 /* Return value - default 0 means success */
64 int ret;
67 if (!data) length = 0;
68 if (length > (sizeof(hdw->cmd_buffer) - 3)) {
69 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
70 "Killing an I2C write to %u that is too large"
71 " (desired=%u limit=%u)",
72 i2c_addr,
73 length,(unsigned int)(sizeof(hdw->cmd_buffer) - 3));
74 return -ENOTSUPP;
77 LOCK_TAKE(hdw->ctl_lock);
79 /* Clear the command buffer (likely to be paranoia) */
80 memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
82 /* Set up command buffer for an I2C write */
83 hdw->cmd_buffer[0] = FX2CMD_I2C_WRITE; /* write prefix */
84 hdw->cmd_buffer[1] = i2c_addr; /* i2c addr of chip */
85 hdw->cmd_buffer[2] = length; /* length of what follows */
86 if (length) memcpy(hdw->cmd_buffer + 3, data, length);
88 /* Do the operation */
89 ret = pvr2_send_request(hdw,
90 hdw->cmd_buffer,
91 length + 3,
92 hdw->cmd_buffer,
93 1);
94 if (!ret) {
95 if (hdw->cmd_buffer[0] != 8) {
96 ret = -EIO;
97 if (hdw->cmd_buffer[0] != 7) {
98 trace_i2c("unexpected status"
99 " from i2_write[%d]: %d",
100 i2c_addr,hdw->cmd_buffer[0]);
105 LOCK_GIVE(hdw->ctl_lock);
107 return ret;
110 static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */
111 u8 i2c_addr, /* I2C address we're talking to */
112 u8 *data, /* Data to write */
113 u16 dlen, /* Size of data to write */
114 u8 *res, /* Where to put data we read */
115 u16 rlen) /* Amount of data to read */
117 /* Return value - default 0 means success */
118 int ret;
121 if (!data) dlen = 0;
122 if (dlen > (sizeof(hdw->cmd_buffer) - 4)) {
123 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
124 "Killing an I2C read to %u that has wlen too large"
125 " (desired=%u limit=%u)",
126 i2c_addr,
127 dlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 4));
128 return -ENOTSUPP;
130 if (res && (rlen > (sizeof(hdw->cmd_buffer) - 1))) {
131 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
132 "Killing an I2C read to %u that has rlen too large"
133 " (desired=%u limit=%u)",
134 i2c_addr,
135 rlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 1));
136 return -ENOTSUPP;
139 LOCK_TAKE(hdw->ctl_lock);
141 /* Clear the command buffer (likely to be paranoia) */
142 memset(hdw->cmd_buffer, 0, sizeof(hdw->cmd_buffer));
144 /* Set up command buffer for an I2C write followed by a read */
145 hdw->cmd_buffer[0] = FX2CMD_I2C_READ; /* read prefix */
146 hdw->cmd_buffer[1] = dlen; /* arg length */
147 hdw->cmd_buffer[2] = rlen; /* answer length. Device will send one
148 more byte (status). */
149 hdw->cmd_buffer[3] = i2c_addr; /* i2c addr of chip */
150 if (dlen) memcpy(hdw->cmd_buffer + 4, data, dlen);
152 /* Do the operation */
153 ret = pvr2_send_request(hdw,
154 hdw->cmd_buffer,
155 4 + dlen,
156 hdw->cmd_buffer,
157 rlen + 1);
158 if (!ret) {
159 if (hdw->cmd_buffer[0] != 8) {
160 ret = -EIO;
161 if (hdw->cmd_buffer[0] != 7) {
162 trace_i2c("unexpected status"
163 " from i2_read[%d]: %d",
164 i2c_addr,hdw->cmd_buffer[0]);
169 /* Copy back the result */
170 if (res && rlen) {
171 if (ret) {
172 /* Error, just blank out the return buffer */
173 memset(res, 0, rlen);
174 } else {
175 memcpy(res, hdw->cmd_buffer + 1, rlen);
179 LOCK_GIVE(hdw->ctl_lock);
181 return ret;
184 /* This is the common low level entry point for doing I2C operations to the
185 hardware. */
186 static int pvr2_i2c_basic_op(struct pvr2_hdw *hdw,
187 u8 i2c_addr,
188 u8 *wdata,
189 u16 wlen,
190 u8 *rdata,
191 u16 rlen)
193 if (!rdata) rlen = 0;
194 if (!wdata) wlen = 0;
195 if (rlen || !wlen) {
196 return pvr2_i2c_read(hdw,i2c_addr,wdata,wlen,rdata,rlen);
197 } else {
198 return pvr2_i2c_write(hdw,i2c_addr,wdata,wlen);
203 /* This is a special entry point for cases of I2C transaction attempts to
204 the IR receiver. The implementation here simulates the IR receiver by
205 issuing a command to the FX2 firmware and using that response to return
206 what the real I2C receiver would have returned. We use this for 24xxx
207 devices, where the IR receiver chip has been removed and replaced with
208 FX2 related logic. */
209 static int i2c_24xxx_ir(struct pvr2_hdw *hdw,
210 u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
212 u8 dat[4];
213 unsigned int stat;
215 if (!(rlen || wlen)) {
216 /* This is a probe attempt. Just let it succeed. */
217 return 0;
220 /* We don't understand this kind of transaction */
221 if ((wlen != 0) || (rlen == 0)) return -EIO;
223 if (rlen < 3) {
224 /* Mike Isely <isely@pobox.com> Appears to be a probe
225 attempt from lirc. Just fill in zeroes and return. If
226 we try instead to do the full transaction here, then bad
227 things seem to happen within the lirc driver module
228 (version 0.8.0-7 sources from Debian, when run under
229 vanilla 2.6.17.6 kernel) - and I don't have the patience
230 to chase it down. */
231 if (rlen > 0) rdata[0] = 0;
232 if (rlen > 1) rdata[1] = 0;
233 return 0;
236 /* Issue a command to the FX2 to read the IR receiver. */
237 LOCK_TAKE(hdw->ctl_lock); do {
238 hdw->cmd_buffer[0] = FX2CMD_GET_IR_CODE;
239 stat = pvr2_send_request(hdw,
240 hdw->cmd_buffer,1,
241 hdw->cmd_buffer,4);
242 dat[0] = hdw->cmd_buffer[0];
243 dat[1] = hdw->cmd_buffer[1];
244 dat[2] = hdw->cmd_buffer[2];
245 dat[3] = hdw->cmd_buffer[3];
246 } while (0); LOCK_GIVE(hdw->ctl_lock);
248 /* Give up if that operation failed. */
249 if (stat != 0) return stat;
251 /* Mangle the results into something that looks like the real IR
252 receiver. */
253 rdata[2] = 0xc1;
254 if (dat[0] != 1) {
255 /* No code received. */
256 rdata[0] = 0;
257 rdata[1] = 0;
258 } else {
259 u16 val;
260 /* Mash the FX2 firmware-provided IR code into something
261 that the normal i2c chip-level driver expects. */
262 val = dat[1];
263 val <<= 8;
264 val |= dat[2];
265 val >>= 1;
266 val &= ~0x0003;
267 val |= 0x8000;
268 rdata[0] = (val >> 8) & 0xffu;
269 rdata[1] = val & 0xffu;
272 return 0;
275 /* This is a special entry point that is entered if an I2C operation is
276 attempted to a wm8775 chip on model 24xxx hardware. Autodetect of this
277 part doesn't work, but we know it is really there. So let's look for
278 the autodetect attempt and just return success if we see that. */
279 static int i2c_hack_wm8775(struct pvr2_hdw *hdw,
280 u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
282 if (!(rlen || wlen)) {
283 // This is a probe attempt. Just let it succeed.
284 return 0;
286 return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
289 /* This is an entry point designed to always fail any attempt to perform a
290 transfer. We use this to cause certain I2C addresses to not be
291 probed. */
292 static int i2c_black_hole(struct pvr2_hdw *hdw,
293 u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
295 return -EIO;
298 /* This is a special entry point that is entered if an I2C operation is
299 attempted to a cx25840 chip on model 24xxx hardware. This chip can
300 sometimes wedge itself. Worse still, when this happens msp3400 can
301 falsely detect this part and then the system gets hosed up after msp3400
302 gets confused and dies. What we want to do here is try to keep msp3400
303 away and also try to notice if the chip is wedged and send a warning to
304 the system log. */
305 static int i2c_hack_cx25840(struct pvr2_hdw *hdw,
306 u8 i2c_addr,u8 *wdata,u16 wlen,u8 *rdata,u16 rlen)
308 int ret;
309 unsigned int subaddr;
310 u8 wbuf[2];
311 int state = hdw->i2c_cx25840_hack_state;
313 if (!(rlen || wlen)) {
314 // Probe attempt - always just succeed and don't bother the
315 // hardware (this helps to make the state machine further
316 // down somewhat easier).
317 return 0;
320 if (state == 3) {
321 return pvr2_i2c_basic_op(hdw,i2c_addr,wdata,wlen,rdata,rlen);
324 /* We're looking for the exact pattern where the revision register
325 is being read. The cx25840 module will always look at the
326 revision register first. Any other pattern of access therefore
327 has to be a probe attempt from somebody else so we'll reject it.
328 Normally we could just let each client just probe the part
329 anyway, but when the cx25840 is wedged, msp3400 will get a false
330 positive and that just screws things up... */
332 if (wlen == 0) {
333 switch (state) {
334 case 1: subaddr = 0x0100; break;
335 case 2: subaddr = 0x0101; break;
336 default: goto fail;
338 } else if (wlen == 2) {
339 subaddr = (wdata[0] << 8) | wdata[1];
340 switch (subaddr) {
341 case 0x0100: state = 1; break;
342 case 0x0101: state = 2; break;
343 default: goto fail;
345 } else {
346 goto fail;
348 if (!rlen) goto success;
349 state = 0;
350 if (rlen != 1) goto fail;
352 /* If we get to here then we have a legitimate read for one of the
353 two revision bytes, so pass it through. */
354 wbuf[0] = subaddr >> 8;
355 wbuf[1] = subaddr;
356 ret = pvr2_i2c_basic_op(hdw,i2c_addr,wbuf,2,rdata,rlen);
358 if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) {
359 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
360 "WARNING: Detected a wedged cx25840 chip;"
361 " the device will not work.");
362 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
363 "WARNING: Try power cycling the pvrusb2 device.");
364 pvr2_trace(PVR2_TRACE_ERROR_LEGS,
365 "WARNING: Disabling further access to the device"
366 " to prevent other foul-ups.");
367 // This blocks all further communication with the part.
368 hdw->i2c_func[0x44] = NULL;
369 pvr2_hdw_render_useless(hdw);
370 goto fail;
373 /* Success! */
374 pvr2_trace(PVR2_TRACE_CHIPS,"cx25840 appears to be OK.");
375 state = 3;
377 success:
378 hdw->i2c_cx25840_hack_state = state;
379 return 0;
381 fail:
382 hdw->i2c_cx25840_hack_state = state;
383 return -EIO;
386 /* This is a very, very limited I2C adapter implementation. We can only
387 support what we actually know will work on the device... */
388 static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap,
389 struct i2c_msg msgs[],
390 int num)
392 int ret = -ENOTSUPP;
393 pvr2_i2c_func funcp = NULL;
394 struct pvr2_hdw *hdw = (struct pvr2_hdw *)(i2c_adap->algo_data);
396 if (!num) {
397 ret = -EINVAL;
398 goto done;
400 if (msgs[0].addr < PVR2_I2C_FUNC_CNT) {
401 funcp = hdw->i2c_func[msgs[0].addr];
403 if (!funcp) {
404 ret = -EIO;
405 goto done;
408 if (num == 1) {
409 if (msgs[0].flags & I2C_M_RD) {
410 /* Simple read */
411 u16 tcnt,bcnt,offs;
412 if (!msgs[0].len) {
413 /* Length == 0 read. This is a probe. */
414 if (funcp(hdw,msgs[0].addr,NULL,0,NULL,0)) {
415 ret = -EIO;
416 goto done;
418 ret = 1;
419 goto done;
421 /* If the read is short enough we'll do the whole
422 thing atomically. Otherwise we have no choice
423 but to break apart the reads. */
424 tcnt = msgs[0].len;
425 offs = 0;
426 while (tcnt) {
427 bcnt = tcnt;
428 if (bcnt > sizeof(hdw->cmd_buffer)-1) {
429 bcnt = sizeof(hdw->cmd_buffer)-1;
431 if (funcp(hdw,msgs[0].addr,NULL,0,
432 msgs[0].buf+offs,bcnt)) {
433 ret = -EIO;
434 goto done;
436 offs += bcnt;
437 tcnt -= bcnt;
439 ret = 1;
440 goto done;
441 } else {
442 /* Simple write */
443 ret = 1;
444 if (funcp(hdw,msgs[0].addr,
445 msgs[0].buf,msgs[0].len,NULL,0)) {
446 ret = -EIO;
448 goto done;
450 } else if (num == 2) {
451 if (msgs[0].addr != msgs[1].addr) {
452 trace_i2c("i2c refusing 2 phase transfer with"
453 " conflicting target addresses");
454 ret = -ENOTSUPP;
455 goto done;
457 if ((!((msgs[0].flags & I2C_M_RD))) &&
458 (msgs[1].flags & I2C_M_RD)) {
459 u16 tcnt,bcnt,wcnt,offs;
460 /* Write followed by atomic read. If the read
461 portion is short enough we'll do the whole thing
462 atomically. Otherwise we have no choice but to
463 break apart the reads. */
464 tcnt = msgs[1].len;
465 wcnt = msgs[0].len;
466 offs = 0;
467 while (tcnt || wcnt) {
468 bcnt = tcnt;
469 if (bcnt > sizeof(hdw->cmd_buffer)-1) {
470 bcnt = sizeof(hdw->cmd_buffer)-1;
472 if (funcp(hdw,msgs[0].addr,
473 msgs[0].buf,wcnt,
474 msgs[1].buf+offs,bcnt)) {
475 ret = -EIO;
476 goto done;
478 offs += bcnt;
479 tcnt -= bcnt;
480 wcnt = 0;
482 ret = 2;
483 goto done;
484 } else {
485 trace_i2c("i2c refusing complex transfer"
486 " read0=%d read1=%d",
487 (msgs[0].flags & I2C_M_RD),
488 (msgs[1].flags & I2C_M_RD));
490 } else {
491 trace_i2c("i2c refusing %d phase transfer",num);
494 done:
495 if (pvrusb2_debug & PVR2_TRACE_I2C_TRAF) {
496 unsigned int idx,offs,cnt;
497 for (idx = 0; idx < num; idx++) {
498 cnt = msgs[idx].len;
499 printk(KERN_INFO
500 "pvrusb2 i2c xfer %u/%u:"
501 " addr=0x%x len=%d %s",
502 idx+1,num,
503 msgs[idx].addr,
504 cnt,
505 (msgs[idx].flags & I2C_M_RD ?
506 "read" : "write"));
507 if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) {
508 if (cnt > 8) cnt = 8;
509 printk(" [");
510 for (offs = 0; offs < (cnt>8?8:cnt); offs++) {
511 if (offs) printk(" ");
512 printk("%02x",msgs[idx].buf[offs]);
514 if (offs < cnt) printk(" ...");
515 printk("]");
517 if (idx+1 == num) {
518 printk(" result=%d",ret);
520 printk("\n");
522 if (!num) {
523 printk(KERN_INFO
524 "pvrusb2 i2c xfer null transfer result=%d\n",
525 ret);
528 return ret;
531 static u32 pvr2_i2c_functionality(struct i2c_adapter *adap)
533 return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
536 static struct i2c_algorithm pvr2_i2c_algo_template = {
537 .master_xfer = pvr2_i2c_xfer,
538 .functionality = pvr2_i2c_functionality,
541 static struct i2c_adapter pvr2_i2c_adap_template = {
542 .owner = THIS_MODULE,
543 .class = 0,
547 /* Return true if device exists at given address */
548 static int do_i2c_probe(struct pvr2_hdw *hdw, int addr)
550 struct i2c_msg msg[1];
551 int rc;
552 msg[0].addr = 0;
553 msg[0].flags = I2C_M_RD;
554 msg[0].len = 0;
555 msg[0].buf = NULL;
556 msg[0].addr = addr;
557 rc = i2c_transfer(&hdw->i2c_adap, msg, ARRAY_SIZE(msg));
558 return rc == 1;
561 static void do_i2c_scan(struct pvr2_hdw *hdw)
563 int i;
564 printk(KERN_INFO "%s: i2c scan beginning\n", hdw->name);
565 for (i = 0; i < 128; i++) {
566 if (do_i2c_probe(hdw, i)) {
567 printk(KERN_INFO "%s: i2c scan: found device @ 0x%x\n",
568 hdw->name, i);
571 printk(KERN_INFO "%s: i2c scan done.\n", hdw->name);
574 static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
576 struct i2c_board_info info;
577 unsigned char addr = 0;
578 if (pvr2_disable_ir_video) {
579 pvr2_trace(PVR2_TRACE_INFO,
580 "Automatic binding of ir_video has been disabled.");
581 return;
583 if (hdw->ir_scheme_active < ARRAY_SIZE(ir_video_addresses)) {
584 addr = ir_video_addresses[hdw->ir_scheme_active];
586 if (!addr) {
587 /* The device either doesn't support I2C-based IR or we
588 don't know (yet) how to operate IR on the device. */
589 return;
591 pvr2_trace(PVR2_TRACE_INFO,
592 "Binding ir_video to i2c address 0x%02x.", addr);
593 memset(&info, 0, sizeof(struct i2c_board_info));
594 strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
595 info.addr = addr;
596 i2c_new_device(&hdw->i2c_adap, &info);
599 void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
601 unsigned int idx;
603 /* The default action for all possible I2C addresses is just to do
604 the transfer normally. */
605 for (idx = 0; idx < PVR2_I2C_FUNC_CNT; idx++) {
606 hdw->i2c_func[idx] = pvr2_i2c_basic_op;
609 /* However, deal with various special cases for 24xxx hardware. */
610 if (ir_mode[hdw->unit_number] == 0) {
611 printk(KERN_INFO "%s: IR disabled\n",hdw->name);
612 hdw->i2c_func[0x18] = i2c_black_hole;
613 } else if (ir_mode[hdw->unit_number] == 1) {
614 if (hdw->ir_scheme_active == PVR2_IR_SCHEME_24XXX) {
615 /* Set up translation so that our IR looks like a
616 29xxx device */
617 hdw->i2c_func[0x18] = i2c_24xxx_ir;
620 if (hdw->hdw_desc->flag_has_cx25840) {
621 hdw->i2c_func[0x44] = i2c_hack_cx25840;
623 if (hdw->hdw_desc->flag_has_wm8775) {
624 hdw->i2c_func[0x1b] = i2c_hack_wm8775;
627 // Configure the adapter and set up everything else related to it.
628 memcpy(&hdw->i2c_adap,&pvr2_i2c_adap_template,sizeof(hdw->i2c_adap));
629 memcpy(&hdw->i2c_algo,&pvr2_i2c_algo_template,sizeof(hdw->i2c_algo));
630 strlcpy(hdw->i2c_adap.name,hdw->name,sizeof(hdw->i2c_adap.name));
631 hdw->i2c_adap.dev.parent = &hdw->usb_dev->dev;
632 hdw->i2c_adap.algo = &hdw->i2c_algo;
633 hdw->i2c_adap.algo_data = hdw;
634 hdw->i2c_linked = !0;
635 i2c_set_adapdata(&hdw->i2c_adap, &hdw->v4l2_dev);
636 i2c_add_adapter(&hdw->i2c_adap);
637 if (hdw->i2c_func[0x18] == i2c_24xxx_ir) {
638 /* Probe for a different type of IR receiver on this
639 device. This is really the only way to differentiate
640 older 24xxx devices from 24xxx variants that include an
641 IR blaster. If the IR blaster is present, the IR
642 receiver is part of that chip and thus we must disable
643 the emulated IR receiver. */
644 if (do_i2c_probe(hdw, 0x71)) {
645 pvr2_trace(PVR2_TRACE_INFO,
646 "Device has newer IR hardware;"
647 " disabling unneeded virtual IR device");
648 hdw->i2c_func[0x18] = NULL;
649 /* Remember that this is a different device... */
650 hdw->ir_scheme_active = PVR2_IR_SCHEME_24XXX_MCE;
653 if (i2c_scan) do_i2c_scan(hdw);
655 pvr2_i2c_register_ir(hdw);
658 void pvr2_i2c_core_done(struct pvr2_hdw *hdw)
660 if (hdw->i2c_linked) {
661 i2c_del_adapter(&hdw->i2c_adap);
662 hdw->i2c_linked = 0;
667 Stuff for Emacs to see, in order to encourage consistent editing style:
668 *** Local Variables: ***
669 *** mode: c ***
670 *** fill-column: 75 ***
671 *** tab-width: 8 ***
672 *** c-basic-offset: 8 ***
673 *** End: ***