1 /* 2 * i2c - generic driver for Inter-Integrated Circuit bus (I2C). 3 */ 4 5 /* kernel headers */ 6 #include <minix/chardriver.h> 7 #include <minix/drivers.h> 8 #include <minix/ds.h> 9 #include <minix/i2c.h> 10 #include <minix/log.h> 11 #include <minix/type.h> 12 #include <minix/board.h> 13 14 /* system headers */ 15 #include <sys/mman.h> 16 17 /* usr headers */ 18 #include <string.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 22 /* SoC specific headers - 1 for each SoC */ 23 #include "omap_i2c.h" 24 25 /* local definitions */ 26 27 /* i2c slave addresses can be up to 10 bits */ 28 #define NR_I2CDEV (0x3ff) 29 30 /* local function prototypes */ 31 static int do_reserve(endpoint_t endpt, int slave_addr); 32 static int check_reservation(endpoint_t endpt, int slave_addr); 33 static void update_reservation(endpoint_t endpt, char *key); 34 static void ds_event(void); 35 36 static int validate_ioctl_exec(minix_i2c_ioctl_exec_t * ioctl_exec); 37 static int do_i2c_ioctl_exec(endpoint_t caller, cp_grant_id_t grant_nr); 38 39 static int env_parse_instance(void); 40 41 /* libchardriver callbacks */ 42 static int i2c_ioctl(devminor_t minor, unsigned long request, endpoint_t endpt, 43 cp_grant_id_t grant, int flags, endpoint_t user_endpt, cdev_id_t id); 44 static void i2c_other(message * m, int ipc_status); 45 46 /* Globals */ 47 48 /* the bus that this instance of the driver is responsible for */ 49 uint32_t i2c_bus_id; 50 51 /* Table of i2c device reservations. */ 52 static struct i2cdev 53 { 54 uint8_t inuse; 55 endpoint_t endpt; 56 char key[DS_MAX_KEYLEN]; 57 } i2cdev[NR_I2CDEV]; 58 59 /* Process a request for an i2c operation. 60 * This is the interface that all hardware specific code must implement. 61 */ 62 int (*process) (minix_i2c_ioctl_exec_t * ioctl_exec); 63 64 /* logging - use with log_warn(), log_info(), log_debug(), log_trace() */ 65 static struct log log = { 66 .name = "i2c", 67 .log_level = LEVEL_INFO, 68 .log_func = default_log 69 }; 70 71 /* Entry points to the i2c driver from libchardriver. 72 * Only i2c_ioctl() and i2c_other() are implemented. The rest are no-op. 73 */ 74 static struct chardriver i2c_tab = { 75 .cdr_ioctl = i2c_ioctl, 76 .cdr_other = i2c_other 77 }; 78 79 static int 80 sef_cb_lu_state_save(int UNUSED(result), int UNUSED(flags)) 81 { 82 int r; 83 char key[DS_MAX_KEYLEN]; 84 85 memset(key, '\0', DS_MAX_KEYLEN); 86 snprintf(key, DS_MAX_KEYLEN, "i2c.%d.i2cdev", i2c_bus_id + 1); 87 r = ds_publish_mem(key, i2cdev, sizeof(i2cdev), DSF_OVERWRITE); 88 if (r != OK) { 89 log_warn(&log, "ds_publish_mem(%s) failed (r=%d)\n", key, r); 90 return r; 91 } 92 93 log_debug(&log, "State Saved\n"); 94 95 return OK; 96 } 97 98 /* 99 * Claim an unclaimed device for exclusive use by endpt. This function can 100 * also be used to update the endpt if the endpt's label matches the label 101 * already associated with the slave address. This is useful if a driver 102 * shuts down unexpectedly and starts up with a new endpt and wants to reserve 103 * the same device it reserved before. 104 */ 105 static int 106 do_reserve(endpoint_t endpt, int slave_addr) 107 { 108 int r; 109 char key[DS_MAX_KEYLEN]; 110 char label[DS_MAX_KEYLEN]; 111 112 /* find the label for the endpoint */ 113 r = ds_retrieve_label_name(label, endpt); 114 if (r != OK) { 115 log_warn(&log, "Couldn't find label for endpt='0x%x'\n", 116 endpt); 117 return r; 118 } 119 120 /* construct the key i2cdriver_announce published (saves an IPC call) */ 121 snprintf(key, DS_MAX_KEYLEN, "drv.i2c.%d.%s", i2c_bus_id + 1, label); 122 123 if (slave_addr < 0 || slave_addr >= NR_I2CDEV) { 124 log_debug(&log, 125 "slave address must be positive & no more than 10 bits\n"); 126 return EINVAL; 127 } 128 129 /* check if device is in use by another driver */ 130 if (i2cdev[slave_addr].inuse != 0 131 && strncmp(i2cdev[slave_addr].key, key, DS_MAX_KEYLEN) != 0) { 132 log_debug(&log, "address in use by '%s'/0x%x\n", 133 i2cdev[slave_addr].key, i2cdev[slave_addr].endpt); 134 return EBUSY; 135 } 136 137 /* device is free or already owned by us, claim it */ 138 i2cdev[slave_addr].inuse = 1; 139 i2cdev[slave_addr].endpt = endpt; 140 memcpy(i2cdev[slave_addr].key, key, DS_MAX_KEYLEN); 141 142 sef_cb_lu_state_save(0, 0); /* save reservations */ 143 144 log_debug(&log, "Device 0x%x claimed by 0x%x key='%s'\n", 145 slave_addr, endpt, key); 146 147 return OK; 148 } 149 150 /* 151 * All drivers must reserve their device(s) before doing operations on them 152 * (read/write, etc). ioctl()'s from VFS (i.e. user programs) can only use 153 * devices that haven't been reserved. A driver isn't allowed to access a 154 * device that another driver has reserved (not even other instances of the 155 * same driver). 156 */ 157 static int 158 check_reservation(endpoint_t endpt, int slave_addr) 159 { 160 if (slave_addr < 0 || slave_addr >= NR_I2CDEV) { 161 log_debug(&log, 162 "slave address must be positive & no more than 10 bits\n"); 163 return EINVAL; 164 } 165 166 if (endpt == VFS_PROC_NR && i2cdev[slave_addr].inuse == 0) { 167 log_debug(&log, 168 "allowing ioctl() from VFS to access unclaimed device\n"); 169 return OK; 170 } 171 172 if (i2cdev[slave_addr].inuse && i2cdev[slave_addr].endpt != endpt) { 173 log_debug(&log, "device reserved by another endpoint\n"); 174 return EBUSY; 175 } else if (i2cdev[slave_addr].inuse == 0) { 176 log_debug(&log, 177 "all drivers sending messages directly to this driver must reserve\n"); 178 return EPERM; 179 } else { 180 log_debug(&log, "allowing access to registered device\n"); 181 return OK; 182 } 183 } 184 185 /* 186 * i2c listens to updates from ds about i2c device drivers starting up. 187 * When a driver comes back up with the same label, the endpt associated 188 * with the reservation needs to be updated. This function does the updating. 189 */ 190 static void 191 update_reservation(endpoint_t endpt, char *key) 192 { 193 int i; 194 195 log_debug(&log, "Updating reservation for '%s' endpt=0x%x\n", key, 196 endpt); 197 198 for (i = 0; i < NR_I2CDEV; i++) { 199 200 /* find devices in use that the driver owns */ 201 if (i2cdev[i].inuse != 0 202 && strncmp(i2cdev[i].key, key, DS_MAX_KEYLEN) == 0) { 203 /* update reservation with new endpoint */ 204 do_reserve(endpt, i); 205 log_debug(&log, "Found device to update 0x%x\n", i); 206 } 207 } 208 } 209 210 /* 211 * Checks a minix_i2c_ioctl_exec_t to see if the fields make sense. 212 */ 213 static int 214 validate_ioctl_exec(minix_i2c_ioctl_exec_t * ioctl_exec) 215 { 216 i2c_op_t op; 217 i2c_addr_t addr; 218 size_t len; 219 220 op = ioctl_exec->iie_op; 221 if (op != I2C_OP_READ && 222 op != I2C_OP_READ_WITH_STOP && 223 op != I2C_OP_WRITE && 224 op != I2C_OP_WRITE_WITH_STOP && 225 op != I2C_OP_READ_BLOCK && op != I2C_OP_WRITE_BLOCK) { 226 log_warn(&log, "iie_op value not valid\n"); 227 return EINVAL; 228 } 229 230 addr = ioctl_exec->iie_addr; 231 if (addr < 0 || addr >= NR_I2CDEV) { 232 log_warn(&log, "iie_addr out of range 0x0-0x%x\n", NR_I2CDEV); 233 return EINVAL; 234 } 235 236 len = ioctl_exec->iie_cmdlen; 237 if (len > I2C_EXEC_MAX_CMDLEN) { 238 log_warn(&log, 239 "iie_cmdlen out of range 0-I2C_EXEC_MAX_CMDLEN\n"); 240 return EINVAL; 241 } 242 243 len = ioctl_exec->iie_buflen; 244 if (len > I2C_EXEC_MAX_BUFLEN) { 245 log_warn(&log, 246 "iie_buflen out of range 0-I2C_EXEC_MAX_BUFLEN\n"); 247 return EINVAL; 248 } 249 250 return OK; 251 } 252 253 /* 254 * Performs the action in minix_i2c_ioctl_exec_t. 255 */ 256 static int 257 do_i2c_ioctl_exec(endpoint_t caller, cp_grant_id_t grant_nr) 258 { 259 int r; 260 minix_i2c_ioctl_exec_t ioctl_exec; 261 262 /* Copy the requested exection into the driver */ 263 r = sys_safecopyfrom(caller, grant_nr, (vir_bytes) 0, 264 (vir_bytes) & ioctl_exec, sizeof(ioctl_exec)); 265 if (r != OK) { 266 log_warn(&log, "sys_safecopyfrom() failed\n"); 267 return r; 268 } 269 270 /* input validation */ 271 r = validate_ioctl_exec(&ioctl_exec); 272 if (r != OK) { 273 log_debug(&log, "Message validation failed\n"); 274 return r; 275 } 276 277 /* permission check */ 278 r = check_reservation(caller, ioctl_exec.iie_addr); 279 if (r != OK) { 280 log_debug(&log, "check_reservation() denied the request\n"); 281 return r; 282 } 283 284 /* Call the device specific code to execute the action */ 285 r = process(&ioctl_exec); 286 if (r != OK) { 287 log_debug(&log, "process() failed\n"); 288 return r; 289 } 290 291 /* Copy the results of the execution back to the calling process */ 292 r = sys_safecopyto(caller, grant_nr, (vir_bytes) 0, 293 (vir_bytes) & ioctl_exec, sizeof(ioctl_exec)); 294 if (r != OK) { 295 log_warn(&log, "sys_safecopyto() failed\n"); 296 return r; 297 } 298 299 return OK; 300 } 301 302 static int 303 i2c_ioctl(devminor_t UNUSED(minor), unsigned long request, endpoint_t endpt, 304 cp_grant_id_t grant, int UNUSED(flags), endpoint_t UNUSED(user_endpt), 305 cdev_id_t UNUSED(id)) 306 { 307 int r; 308 309 switch (request) { 310 case MINIX_I2C_IOCTL_EXEC: 311 r = do_i2c_ioctl_exec(endpt, grant); 312 break; 313 default: 314 log_warn(&log, "Invalid ioctl() 0x%x\n", request); 315 r = ENOTTY; 316 break; 317 } 318 319 return r; 320 } 321 322 static void 323 i2c_other(message * m, int ipc_status) 324 { 325 message m_reply; 326 int r; 327 328 if (is_ipc_notify(ipc_status)) { 329 /* handle notifications about drivers changing state */ 330 if (m->m_source == DS_PROC_NR) { 331 ds_event(); 332 } 333 return; 334 } 335 336 switch (m->m_type) { 337 case BUSC_I2C_RESERVE: 338 /* reserve a device on the bus for exclusive access */ 339 r = do_reserve(m->m_source, m->m_li2cdriver_i2c_busc_i2c_reserve.addr); 340 break; 341 case BUSC_I2C_EXEC: 342 /* handle request from another driver */ 343 r = do_i2c_ioctl_exec(m->m_source, m->m_li2cdriver_i2c_busc_i2c_exec.grant); 344 break; 345 default: 346 log_warn(&log, "Invalid message type (0x%x)\n", m->m_type); 347 r = EINVAL; 348 break; 349 } 350 351 log_trace(&log, "i2c_other() returning r=%d\n", r); 352 353 /* Send a reply. */ 354 memset(&m_reply, 0, sizeof(m_reply)); 355 m_reply.m_type = r; 356 357 if ((r = ipc_send(m->m_source, &m_reply)) != OK) 358 log_warn(&log, "ipc_send() to %d failed: %d\n", m->m_source, r); 359 } 360 361 /* 362 * The bus drivers are subscribed to DS events about device drivers on their 363 * bus. When the device drivers restart, DS sends a notification and this 364 * function updates the reservation table with the device driver's new 365 * endpoint. 366 */ 367 static void 368 ds_event(void) 369 { 370 char key[DS_MAX_KEYLEN]; 371 u32_t value; 372 int type; 373 endpoint_t owner_endpoint; 374 int r; 375 376 /* check for pending events */ 377 while ((r = ds_check(key, &type, &owner_endpoint)) == OK) { 378 379 r = ds_retrieve_u32(key, &value); 380 if (r != OK) { 381 log_warn(&log, "ds_retrieve_u32() failed r=%d\n", r); 382 return; 383 } 384 385 log_debug(&log, "key='%s' owner_endpoint=0x%x\n", key, 386 owner_endpoint); 387 388 if (value == DS_DRIVER_UP) { 389 /* clean up any old reservations the driver had */ 390 log_debug(&log, "DS_DRIVER_UP\n"); 391 update_reservation(owner_endpoint, key); 392 } 393 } 394 } 395 396 static int 397 lu_state_restore(void) 398 { 399 int r; 400 char key[DS_MAX_KEYLEN]; 401 size_t size; 402 403 env_parse_instance(); 404 405 size = sizeof(i2cdev); 406 407 memset(key, '\0', DS_MAX_KEYLEN); 408 snprintf(key, DS_MAX_KEYLEN, "i2c.%d.i2cdev", i2c_bus_id + 1); 409 410 r = ds_retrieve_mem(key, (char *) i2cdev, &size); 411 if (r != OK) { 412 log_warn(&log, "ds_retrieve_mem(%s) failed (r=%d)\n", key, r); 413 return r; 414 } 415 416 log_debug(&log, "State Restored\n"); 417 418 return OK; 419 } 420 421 static int 422 sef_cb_init(int type, sef_init_info_t * UNUSED(info)) 423 { 424 int r; 425 char regex[DS_MAX_KEYLEN]; 426 struct machine machine; 427 sys_getmachine(&machine); 428 429 if (type != SEF_INIT_FRESH) { 430 /* Restore a prior state. */ 431 lu_state_restore(); 432 } 433 434 if (BOARD_IS_BBXM(machine.board_id) || BOARD_IS_BB(machine.board_id)){ 435 /* Set callback and initialize the bus */ 436 r = omap_interface_setup(&process, i2c_bus_id); 437 if (r != OK) { 438 return r; 439 } 440 } else { 441 return ENODEV; 442 } 443 444 /* Announce we are up when necessary. */ 445 if (type != SEF_INIT_LU) { 446 447 /* only capture events for this particular bus */ 448 snprintf(regex, DS_MAX_KEYLEN, "drv\\.i2c\\.%d\\..*", 449 i2c_bus_id + 1); 450 451 /* Subscribe to driver events for i2c drivers */ 452 r = ds_subscribe(regex, DSF_INITIAL | DSF_OVERWRITE); 453 if (r != OK) { 454 log_warn(&log, "ds_subscribe() failed\n"); 455 return r; 456 } 457 458 chardriver_announce(); 459 } 460 461 /* Save state */ 462 sef_cb_lu_state_save(0, 0); 463 464 /* Initialization completed successfully. */ 465 return OK; 466 } 467 468 static void 469 sef_local_startup() 470 { 471 /* Register init callbacks. */ 472 sef_setcb_init_fresh(sef_cb_init); 473 sef_setcb_init_lu(sef_cb_init); 474 sef_setcb_init_restart(sef_cb_init); 475 476 /* Register live update callbacks */ 477 sef_setcb_lu_state_save(sef_cb_lu_state_save); 478 479 /* Let SEF perform startup. */ 480 sef_startup(); 481 } 482 483 static int 484 env_parse_instance(void) 485 { 486 int r; 487 long instance; 488 489 /* Parse the instance number passed to service */ 490 instance = 0; 491 r = env_parse("instance", "d", 0, &instance, 1, 3); 492 if (r == -1) { 493 log_warn(&log, 494 "Expecting '-arg instance=N' argument (N=1..3)\n"); 495 return EXIT_FAILURE; 496 } 497 498 /* Device files count from 1, hardware starts counting from 0 */ 499 i2c_bus_id = instance - 1; 500 501 return OK; 502 } 503 504 int 505 main(int argc, char *argv[]) 506 { 507 int r; 508 509 env_setargs(argc, argv); 510 511 r = env_parse_instance(); 512 if (r != OK) { 513 return r; 514 } 515 516 memset(i2cdev, '\0', sizeof(i2cdev)); 517 sef_local_startup(); 518 chardriver_task(&i2c_tab); 519 520 return OK; 521 } 522