1 1.1 brad /* $NetBSD: common.c,v 1.1 2021/12/07 17:39:55 brad Exp $ */ 2 1.1 brad 3 1.1 brad /* 4 1.1 brad * Copyright (c) 2021 Brad Spencer <brad (at) anduin.eldar.org> 5 1.1 brad * 6 1.1 brad * Permission to use, copy, modify, and distribute this software for any 7 1.1 brad * purpose with or without fee is hereby granted, provided that the above 8 1.1 brad * copyright notice and this permission notice appear in all copies. 9 1.1 brad * 10 1.1 brad * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 1.1 brad * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 1.1 brad * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 1.1 brad * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 1.1 brad * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 1.1 brad * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 1.1 brad * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 1.1 brad */ 18 1.1 brad 19 1.1 brad #ifdef __RCSID 20 1.1 brad __RCSID("$NetBSD: common.c,v 1.1 2021/12/07 17:39:55 brad Exp $"); 21 1.1 brad #endif 22 1.1 brad 23 1.1 brad /* Common functions dealing with the SCMD devices. This does not 24 1.1 brad * know how to talk to anything in particular, it calls out to the 25 1.1 brad * functions defined in the function blocks for that. 26 1.1 brad */ 27 1.1 brad 28 1.1 brad #include <inttypes.h> 29 1.1 brad #include <stdbool.h> 30 1.1 brad #include <stdio.h> 31 1.1 brad #include <stdlib.h> 32 1.1 brad #include <unistd.h> 33 1.1 brad #include <err.h> 34 1.1 brad #include <fcntl.h> 35 1.1 brad #include <string.h> 36 1.1 brad #include <limits.h> 37 1.1 brad #include <errno.h> 38 1.1 brad 39 1.1 brad #include <dev/ic/scmdreg.h> 40 1.1 brad 41 1.1 brad #define EXTERN 42 1.1 brad #include "common.h" 43 1.1 brad #include "responses.h" 44 1.1 brad #include "scmdctl.h" 45 1.1 brad 46 1.1 brad 47 1.1 brad int 48 1.1 brad decode_motor_level(int raw) 49 1.1 brad { 50 1.1 brad int r; 51 1.1 brad 52 1.1 brad r = abs(128 - raw); 53 1.1 brad if (raw < 128) 54 1.1 brad r = r * -1; 55 1.1 brad 56 1.1 brad return r; 57 1.1 brad } 58 1.1 brad 59 1.1 brad int common_clear(struct function_block *fb, int fd, bool debug) 60 1.1 brad { 61 1.1 brad return (*(fb->func_clear))(fd, debug); 62 1.1 brad } 63 1.1 brad 64 1.1 brad int 65 1.1 brad common_identify(struct function_block *fb, int fd, bool debug, int a_module, struct scmd_identify_response *r) 66 1.1 brad { 67 1.1 brad uint8_t b; 68 1.1 brad int err; 69 1.1 brad 70 1.1 brad err = (*(fb->func_clear))(fd, debug); 71 1.1 brad if (! err) { 72 1.1 brad err = (*(fb->func_phy_read))(fd, debug, a_module, SCMD_REG_ID, SCMD_REG_ID, &b); 73 1.1 brad if (! err) 74 1.1 brad r->id = b; 75 1.1 brad err = (*(fb->func_phy_read))(fd, debug, a_module, SCMD_REG_FID, SCMD_REG_FID, &b); 76 1.1 brad if (! err) 77 1.1 brad r->fwversion = b; 78 1.1 brad err = (*(fb->func_phy_read))(fd, debug, a_module, SCMD_REG_CONFIG_BITS, SCMD_REG_CONFIG_BITS, &b); 79 1.1 brad if (! err) 80 1.1 brad r->config_bits = b; 81 1.1 brad err = (*(fb->func_phy_read))(fd, debug, a_module, SCMD_REG_SLAVE_ADDR, SCMD_REG_SLAVE_ADDR, &b); 82 1.1 brad if (! err) 83 1.1 brad r->slv_i2c_address = b; 84 1.1 brad } 85 1.1 brad 86 1.1 brad return err; 87 1.1 brad } 88 1.1 brad 89 1.1 brad int common_diag(struct function_block *fb, int fd, bool debug, int a_module, struct scmd_diag_response *r) 90 1.1 brad { 91 1.1 brad uint8_t b; 92 1.1 brad int err, m; 93 1.1 brad 94 1.1 brad err = (*(fb->func_clear))(fd, debug); 95 1.1 brad if (! err) { 96 1.1 brad m = 0; 97 1.1 brad for(uint8_t n = SCMD_REG_U_I2C_RD_ERR; n <= SCMD_REG_GEN_TEST_WORD; n++) { 98 1.1 brad err = (*(fb->func_phy_read))(fd, debug, a_module, n, n, &b); 99 1.1 brad if (! err) { 100 1.1 brad r->diags[m] = b; 101 1.1 brad } 102 1.1 brad m++; 103 1.1 brad } 104 1.1 brad } 105 1.1 brad 106 1.1 brad return err; 107 1.1 brad } 108 1.1 brad 109 1.1 brad /* This tries to avoid reading just every register if only one 110 1.1 brad * motor is asked about. 111 1.1 brad */ 112 1.1 brad int 113 1.1 brad common_get_motor(struct function_block *fb, int fd, bool debug, int a_module, struct scmd_motor_response *r) 114 1.1 brad { 115 1.1 brad uint8_t b; 116 1.1 brad int err = 0,m; 117 1.1 brad 118 1.1 brad if (a_module != SCMD_ANY_MODULE && 119 1.1 brad (a_module < 0 || a_module > 16)) 120 1.1 brad return EINVAL; 121 1.1 brad 122 1.1 brad err = (*(fb->func_clear))(fd, debug); 123 1.1 brad if (! err) { 124 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_DRIVER_ENABLE, SCMD_REG_DRIVER_ENABLE, &b); 125 1.1 brad if (! err) 126 1.1 brad r->driver = b; 127 1.1 brad 128 1.1 brad m = 0; 129 1.1 brad for(uint8_t n = SCMD_REG_MA_DRIVE; n <= SCMD_REG_S16B_DRIVE; n++) { 130 1.1 brad r->motorlevels[m] = SCMD_NO_MOTOR; 131 1.1 brad if (a_module != SCMD_ANY_MODULE && 132 1.1 brad (m / 2) != a_module) 133 1.1 brad goto skip; 134 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, n, n, &b); 135 1.1 brad if (! err) 136 1.1 brad r->motorlevels[m] = b; 137 1.1 brad skip: 138 1.1 brad m++; 139 1.1 brad } 140 1.1 brad 141 1.1 brad if (a_module == SCMD_ANY_MODULE || 142 1.1 brad a_module == 0) { 143 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_MOTOR_A_INVERT, SCMD_REG_MOTOR_A_INVERT, &b); 144 1.1 brad if (!err) 145 1.1 brad r->invert[0] = (b & 0x01); 146 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_MOTOR_B_INVERT, SCMD_REG_MOTOR_B_INVERT, &b); 147 1.1 brad if (!err) 148 1.1 brad r->invert[1] = (b & 0x01); 149 1.1 brad } 150 1.1 brad 151 1.1 brad if (a_module != 0) { 152 1.1 brad m = 2; 153 1.1 brad for(uint8_t n = SCMD_REG_INV_2_9; n <= SCMD_REG_INV_26_33; n++) { 154 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, n, n, &b); 155 1.1 brad if (!err) { 156 1.1 brad for(uint8_t j = 0; j < 8;j++) { 157 1.1 brad r->invert[m] = (b & (1 << j)); 158 1.1 brad m++; 159 1.1 brad } 160 1.1 brad } 161 1.1 brad } 162 1.1 brad } 163 1.1 brad 164 1.1 brad if (a_module == SCMD_ANY_MODULE || 165 1.1 brad a_module == 0) { 166 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_BRIDGE, SCMD_REG_BRIDGE, &b); 167 1.1 brad if (!err) 168 1.1 brad r->bridge[0] = (b & 0x01); 169 1.1 brad } 170 1.1 brad 171 1.1 brad if (a_module != 0) { 172 1.1 brad m = 1; 173 1.1 brad for(uint8_t n = SCMD_REG_BRIDGE_SLV_L; n <= SCMD_REG_BRIDGE_SLV_H; n++) { 174 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, n, n, &b); 175 1.1 brad if (!err) { 176 1.1 brad for(uint8_t j = 0; j < 8;j++) { 177 1.1 brad r->bridge[m] = (b & (1 << j)); 178 1.1 brad m++; 179 1.1 brad } 180 1.1 brad } 181 1.1 brad } 182 1.1 brad } 183 1.1 brad } 184 1.1 brad 185 1.1 brad return err; 186 1.1 brad } 187 1.1 brad 188 1.1 brad int 189 1.1 brad common_set_motor(struct function_block *fb, int fd, bool debug, int a_module, char a_motor, int8_t reg_v) 190 1.1 brad { 191 1.1 brad uint8_t reg; 192 1.1 brad int err; 193 1.1 brad int reg_index; 194 1.1 brad 195 1.1 brad if (a_module < 0 || a_module > 16) 196 1.1 brad return EINVAL; 197 1.1 brad 198 1.1 brad if (!(a_motor == 'A' || a_motor == 'B')) 199 1.1 brad return EINVAL; 200 1.1 brad 201 1.1 brad err = (*(fb->func_clear))(fd, debug); 202 1.1 brad if (! err) { 203 1.1 brad reg_index = a_module * 2; 204 1.1 brad if (a_motor == 'B') 205 1.1 brad reg_index++; 206 1.1 brad reg = SCMD_REG_MA_DRIVE + reg_index; 207 1.1 brad reg_v = reg_v + 128; 208 1.1 brad if (debug) 209 1.1 brad fprintf(stderr,"common_set_motor: reg_index: %d ; reg: %02X ; reg_v: %d\n",reg_index,reg,reg_v); 210 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, reg, reg_v); 211 1.1 brad } 212 1.1 brad 213 1.1 brad return err; 214 1.1 brad } 215 1.1 brad 216 1.1 brad int 217 1.1 brad common_invert_motor(struct function_block *fb, int fd, bool debug, int a_module, char a_motor) 218 1.1 brad { 219 1.1 brad uint8_t b; 220 1.1 brad int err; 221 1.1 brad uint8_t reg, reg_index = 0, reg_offset = 0; 222 1.1 brad int motor_index; 223 1.1 brad 224 1.1 brad err = (*(fb->func_clear))(fd, debug); 225 1.1 brad if (! err) { 226 1.1 brad if (a_module == 0) { 227 1.1 brad if (a_motor == 'A') { 228 1.1 brad reg = SCMD_REG_MOTOR_A_INVERT; 229 1.1 brad } else { 230 1.1 brad reg = SCMD_REG_MOTOR_B_INVERT; 231 1.1 brad } 232 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, reg, reg, &b); 233 1.1 brad if (!err) { 234 1.1 brad b = b ^ 0x01; 235 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, reg, b); 236 1.1 brad } 237 1.1 brad } else { 238 1.1 brad motor_index = (a_module * 2) - 2; 239 1.1 brad if (a_motor == 'B') 240 1.1 brad motor_index++; 241 1.1 brad reg_offset = motor_index / 8; 242 1.1 brad motor_index = motor_index % 8; 243 1.1 brad reg_index = 1 << motor_index; 244 1.1 brad reg = SCMD_REG_INV_2_9 + reg_offset; 245 1.1 brad if (debug) 246 1.1 brad fprintf(stderr,"common_invert_motor: remote invert: motor_index: %d ; reg_offset: %d ; reg_index: %02X ; reg: %02X\n",motor_index,reg_offset,reg_index,reg); 247 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, reg, reg, &b); 248 1.1 brad if (!err) { 249 1.1 brad b = b ^ reg_index; 250 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, reg, b); 251 1.1 brad } 252 1.1 brad } 253 1.1 brad } 254 1.1 brad 255 1.1 brad return err; 256 1.1 brad } 257 1.1 brad 258 1.1 brad int 259 1.1 brad common_bridge_motor(struct function_block *fb, int fd, bool debug, int a_module) 260 1.1 brad { 261 1.1 brad uint8_t b; 262 1.1 brad int err = 0; 263 1.1 brad uint8_t reg, reg_index = 0, reg_offset = 0; 264 1.1 brad int module_index; 265 1.1 brad 266 1.1 brad err = (*(fb->func_clear))(fd, debug); 267 1.1 brad if (! err) { 268 1.1 brad if (a_module == 0) { 269 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_BRIDGE, SCMD_REG_BRIDGE, &b); 270 1.1 brad if (!err) { 271 1.1 brad b = b ^ 0x01; 272 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, SCMD_REG_BRIDGE, b); 273 1.1 brad } 274 1.1 brad } else { 275 1.1 brad module_index = a_module - 1; 276 1.1 brad reg_offset = module_index / 8; 277 1.1 brad module_index = module_index % 8; 278 1.1 brad reg_index = 1 << module_index; 279 1.1 brad reg = SCMD_REG_BRIDGE_SLV_L + reg_offset; 280 1.1 brad if (debug) 281 1.1 brad fprintf(stderr,"common_bridge_motor: remote bridge: module_index: %d ; reg_offset: %d ; reg_index: %02X ; reg: %02X\n",module_index,reg_offset,reg_index,reg); 282 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, reg, reg, &b); 283 1.1 brad if (!err) { 284 1.1 brad b = b ^ reg_index; 285 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, reg, b); 286 1.1 brad } 287 1.1 brad } 288 1.1 brad } 289 1.1 brad 290 1.1 brad return err; 291 1.1 brad } 292 1.1 brad 293 1.1 brad int 294 1.1 brad common_enable_disable(struct function_block *fb, int fd, bool debug, int subcmd) 295 1.1 brad { 296 1.1 brad int err; 297 1.1 brad uint8_t reg_v; 298 1.1 brad 299 1.1 brad if (!(subcmd == SCMD_ENABLE || subcmd == SCMD_DISABLE)) 300 1.1 brad return EINVAL; 301 1.1 brad 302 1.1 brad err = (*(fb->func_clear))(fd, debug); 303 1.1 brad if (! err) { 304 1.1 brad switch (subcmd) { 305 1.1 brad case SCMD_ENABLE: 306 1.1 brad reg_v = SCMD_DRIVER_ENABLE; 307 1.1 brad break; 308 1.1 brad case SCMD_DISABLE: 309 1.1 brad reg_v = SCMD_DRIVER_DISABLE; 310 1.1 brad break; 311 1.1 brad default: 312 1.1 brad return EINVAL; 313 1.1 brad } 314 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, SCMD_REG_DRIVER_ENABLE, reg_v); 315 1.1 brad } 316 1.1 brad 317 1.1 brad return err; 318 1.1 brad } 319 1.1 brad 320 1.1 brad /* These control commands can take a very long time and the restart 321 1.1 brad * make cause the device to become unresponsive for a bit. 322 1.1 brad */ 323 1.1 brad int 324 1.1 brad common_control_1(struct function_block *fb, int fd, bool debug, int subcmd) 325 1.1 brad { 326 1.1 brad int err; 327 1.1 brad uint8_t reg_v; 328 1.1 brad 329 1.1 brad if (!(subcmd == SCMD_RESTART || subcmd == SCMD_ENUMERATE)) 330 1.1 brad return EINVAL; 331 1.1 brad 332 1.1 brad err = (*(fb->func_clear))(fd, debug); 333 1.1 brad if (! err) { 334 1.1 brad switch (subcmd) { 335 1.1 brad case SCMD_RESTART: 336 1.1 brad reg_v = SCMD_CONTROL_1_RESTART; 337 1.1 brad break; 338 1.1 brad case SCMD_ENUMERATE: 339 1.1 brad reg_v = SCMD_CONTROL_1_REENUMERATE; 340 1.1 brad break; 341 1.1 brad default: 342 1.1 brad return EINVAL; 343 1.1 brad } 344 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, SCMD_REG_CONTROL_1, reg_v); 345 1.1 brad } 346 1.1 brad 347 1.1 brad return err; 348 1.1 brad } 349 1.1 brad 350 1.1 brad int 351 1.1 brad common_get_update_rate(struct function_block *fb, int fd, bool debug, uint8_t *rate) 352 1.1 brad { 353 1.1 brad uint8_t b; 354 1.1 brad int err; 355 1.1 brad 356 1.1 brad err = (*(fb->func_clear))(fd, debug); 357 1.1 brad if (! err) { 358 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_UPDATE_RATE, SCMD_REG_UPDATE_RATE, &b); 359 1.1 brad if (!err) 360 1.1 brad *rate = b; 361 1.1 brad } 362 1.1 brad 363 1.1 brad return err; 364 1.1 brad } 365 1.1 brad 366 1.1 brad int 367 1.1 brad common_set_update_rate(struct function_block *fb, int fd, bool debug, uint8_t rate) 368 1.1 brad { 369 1.1 brad int err; 370 1.1 brad 371 1.1 brad err = (*(fb->func_clear))(fd, debug); 372 1.1 brad if (! err) { 373 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, SCMD_REG_UPDATE_RATE, rate); 374 1.1 brad } 375 1.1 brad 376 1.1 brad return err; 377 1.1 brad } 378 1.1 brad 379 1.1 brad int 380 1.1 brad common_force_update(struct function_block *fb, int fd, bool debug) 381 1.1 brad { 382 1.1 brad int err; 383 1.1 brad 384 1.1 brad err = (*(fb->func_clear))(fd, debug); 385 1.1 brad if (! err) { 386 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, SCMD_REG_FORCE_UPDATE, 0x01); 387 1.1 brad } 388 1.1 brad 389 1.1 brad return err; 390 1.1 brad } 391 1.1 brad 392 1.1 brad int 393 1.1 brad common_get_ebus_speed(struct function_block *fb, int fd, bool debug, uint8_t *speed) 394 1.1 brad { 395 1.1 brad uint8_t b; 396 1.1 brad int err; 397 1.1 brad 398 1.1 brad err = (*(fb->func_clear))(fd, debug); 399 1.1 brad if (! err) { 400 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, SCMD_REG_E_BUS_SPEED, SCMD_REG_E_BUS_SPEED, &b); 401 1.1 brad if (!err) 402 1.1 brad *speed = b; 403 1.1 brad } 404 1.1 brad 405 1.1 brad return err; 406 1.1 brad } 407 1.1 brad 408 1.1 brad int 409 1.1 brad common_set_ebus_speed(struct function_block *fb, int fd, bool debug, uint8_t speed) 410 1.1 brad { 411 1.1 brad int err; 412 1.1 brad 413 1.1 brad if (speed > 0x03) 414 1.1 brad return EINVAL; 415 1.1 brad 416 1.1 brad err = (*(fb->func_clear))(fd, debug); 417 1.1 brad if (! err) { 418 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, SCMD_REG_E_BUS_SPEED, speed); 419 1.1 brad } 420 1.1 brad 421 1.1 brad return err; 422 1.1 brad } 423 1.1 brad 424 1.1 brad int 425 1.1 brad common_get_lock_state(struct function_block *fb, int fd, bool debug, int ltype, uint8_t *lstate) 426 1.1 brad { 427 1.1 brad uint8_t b; 428 1.1 brad uint8_t reg; 429 1.1 brad int err; 430 1.1 brad 431 1.1 brad switch (ltype) { 432 1.1 brad case SCMD_LOCAL_USER_LOCK: 433 1.1 brad reg = SCMD_REG_LOCAL_USER_LOCK; 434 1.1 brad break; 435 1.1 brad case SCMD_LOCAL_MASTER_LOCK: 436 1.1 brad reg = SCMD_REG_LOCAL_MASTER_LOCK; 437 1.1 brad break; 438 1.1 brad case SCMD_GLOBAL_USER_LOCK: 439 1.1 brad reg = SCMD_REG_USER_LOCK; 440 1.1 brad break; 441 1.1 brad case SCMD_GLOBAL_MASTER_LOCK: 442 1.1 brad reg = SCMD_REG_MASTER_LOCK; 443 1.1 brad break; 444 1.1 brad default: 445 1.1 brad return EINVAL; 446 1.1 brad } 447 1.1 brad 448 1.1 brad err = (*(fb->func_clear))(fd, debug); 449 1.1 brad if (! err) { 450 1.1 brad err = (*(fb->func_phy_read))(fd, debug, 0, reg, reg, &b); 451 1.1 brad if (!err) 452 1.1 brad *lstate = b; 453 1.1 brad } 454 1.1 brad 455 1.1 brad return err; 456 1.1 brad } 457 1.1 brad 458 1.1 brad int 459 1.1 brad common_set_lock_state(struct function_block *fb, int fd, bool debug, int ltype, uint8_t lstate) 460 1.1 brad { 461 1.1 brad uint8_t reg; 462 1.1 brad uint8_t state; 463 1.1 brad int err; 464 1.1 brad 465 1.1 brad switch (ltype) { 466 1.1 brad case SCMD_LOCAL_USER_LOCK: 467 1.1 brad reg = SCMD_REG_LOCAL_USER_LOCK; 468 1.1 brad break; 469 1.1 brad case SCMD_LOCAL_MASTER_LOCK: 470 1.1 brad reg = SCMD_REG_LOCAL_MASTER_LOCK; 471 1.1 brad break; 472 1.1 brad case SCMD_GLOBAL_USER_LOCK: 473 1.1 brad reg = SCMD_REG_USER_LOCK; 474 1.1 brad break; 475 1.1 brad case SCMD_GLOBAL_MASTER_LOCK: 476 1.1 brad reg = SCMD_REG_MASTER_LOCK; 477 1.1 brad break; 478 1.1 brad default: 479 1.1 brad return EINVAL; 480 1.1 brad } 481 1.1 brad 482 1.1 brad switch (lstate) { 483 1.1 brad case SCMD_LOCK_LOCKED: 484 1.1 brad state = SCMD_ANY_LOCK_LOCKED; 485 1.1 brad break; 486 1.1 brad case SCMD_LOCK_UNLOCK: 487 1.1 brad state = SCMD_MASTER_LOCK_UNLOCKED; 488 1.1 brad if (ltype == SCMD_LOCAL_USER_LOCK || 489 1.1 brad ltype == SCMD_GLOBAL_USER_LOCK) 490 1.1 brad state = SCMD_USER_LOCK_UNLOCKED; 491 1.1 brad break; 492 1.1 brad default: 493 1.1 brad return EINVAL; 494 1.1 brad } 495 1.1 brad 496 1.1 brad err = (*(fb->func_clear))(fd, debug); 497 1.1 brad if (! err) { 498 1.1 brad err = (*(fb->func_phy_write))(fd, debug, 0, reg, state); 499 1.1 brad } 500 1.1 brad 501 1.1 brad return err; 502 1.1 brad } 503