Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

i2c-dev: Split i2cdev_ioctl

Split the handling of the I2C_RDWR and I2C_SMBUS ioctls to their own
functions. This limits the stack usage, saves one level of indentation
and makes the code more readable.

Signed-off-by: Jean Delvare <khali@linux-fr.org>

authored by

Jean Delvare and committed by
Jean Delvare
dba7997a 838349b5

+168 -161
+168 -161
drivers/i2c/i2c-dev.c
··· 200 200 return device_for_each_child(&adapter->dev, &addr, i2cdev_check); 201 201 } 202 202 203 + static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client, 204 + unsigned long arg) 205 + { 206 + struct i2c_rdwr_ioctl_data rdwr_arg; 207 + struct i2c_msg *rdwr_pa; 208 + u8 __user **data_ptrs; 209 + int i, res; 210 + 211 + if (copy_from_user(&rdwr_arg, 212 + (struct i2c_rdwr_ioctl_data __user *)arg, 213 + sizeof(rdwr_arg))) 214 + return -EFAULT; 215 + 216 + /* Put an arbitrary limit on the number of messages that can 217 + * be sent at once */ 218 + if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) 219 + return -EINVAL; 220 + 221 + rdwr_pa = (struct i2c_msg *) 222 + kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), 223 + GFP_KERNEL); 224 + if (!rdwr_pa) 225 + return -ENOMEM; 226 + 227 + if (copy_from_user(rdwr_pa, rdwr_arg.msgs, 228 + rdwr_arg.nmsgs * sizeof(struct i2c_msg))) { 229 + kfree(rdwr_pa); 230 + return -EFAULT; 231 + } 232 + 233 + data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); 234 + if (data_ptrs == NULL) { 235 + kfree(rdwr_pa); 236 + return -ENOMEM; 237 + } 238 + 239 + res = 0; 240 + for (i = 0; i < rdwr_arg.nmsgs; i++) { 241 + /* Limit the size of the message to a sane amount; 242 + * and don't let length change either. */ 243 + if ((rdwr_pa[i].len > 8192) || 244 + (rdwr_pa[i].flags & I2C_M_RECV_LEN)) { 245 + res = -EINVAL; 246 + break; 247 + } 248 + data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; 249 + rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL); 250 + if (rdwr_pa[i].buf == NULL) { 251 + res = -ENOMEM; 252 + break; 253 + } 254 + if (copy_from_user(rdwr_pa[i].buf, data_ptrs[i], 255 + rdwr_pa[i].len)) { 256 + ++i; /* Needs to be kfreed too */ 257 + res = -EFAULT; 258 + break; 259 + } 260 + } 261 + if (res < 0) { 262 + int j; 263 + for (j = 0; j < i; ++j) 264 + kfree(rdwr_pa[j].buf); 265 + kfree(data_ptrs); 266 + kfree(rdwr_pa); 267 + return res; 268 + } 269 + 270 + res = i2c_transfer(client->adapter, rdwr_pa, rdwr_arg.nmsgs); 271 + while (i-- > 0) { 272 + if (res >= 0 && (rdwr_pa[i].flags & I2C_M_RD)) { 273 + if (copy_to_user(data_ptrs[i], rdwr_pa[i].buf, 274 + rdwr_pa[i].len)) 275 + res = -EFAULT; 276 + } 277 + kfree(rdwr_pa[i].buf); 278 + } 279 + kfree(data_ptrs); 280 + kfree(rdwr_pa); 281 + return res; 282 + } 283 + 284 + static noinline int i2cdev_ioctl_smbus(struct i2c_client *client, 285 + unsigned long arg) 286 + { 287 + struct i2c_smbus_ioctl_data data_arg; 288 + union i2c_smbus_data temp; 289 + int datasize, res; 290 + 291 + if (copy_from_user(&data_arg, 292 + (struct i2c_smbus_ioctl_data __user *) arg, 293 + sizeof(struct i2c_smbus_ioctl_data))) 294 + return -EFAULT; 295 + if ((data_arg.size != I2C_SMBUS_BYTE) && 296 + (data_arg.size != I2C_SMBUS_QUICK) && 297 + (data_arg.size != I2C_SMBUS_BYTE_DATA) && 298 + (data_arg.size != I2C_SMBUS_WORD_DATA) && 299 + (data_arg.size != I2C_SMBUS_PROC_CALL) && 300 + (data_arg.size != I2C_SMBUS_BLOCK_DATA) && 301 + (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) && 302 + (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) && 303 + (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) { 304 + dev_dbg(&client->adapter->dev, 305 + "size out of range (%x) in ioctl I2C_SMBUS.\n", 306 + data_arg.size); 307 + return -EINVAL; 308 + } 309 + /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, 310 + so the check is valid if size==I2C_SMBUS_QUICK too. */ 311 + if ((data_arg.read_write != I2C_SMBUS_READ) && 312 + (data_arg.read_write != I2C_SMBUS_WRITE)) { 313 + dev_dbg(&client->adapter->dev, 314 + "read_write out of range (%x) in ioctl I2C_SMBUS.\n", 315 + data_arg.read_write); 316 + return -EINVAL; 317 + } 318 + 319 + /* Note that command values are always valid! */ 320 + 321 + if ((data_arg.size == I2C_SMBUS_QUICK) || 322 + ((data_arg.size == I2C_SMBUS_BYTE) && 323 + (data_arg.read_write == I2C_SMBUS_WRITE))) 324 + /* These are special: we do not use data */ 325 + return i2c_smbus_xfer(client->adapter, client->addr, 326 + client->flags, data_arg.read_write, 327 + data_arg.command, data_arg.size, NULL); 328 + 329 + if (data_arg.data == NULL) { 330 + dev_dbg(&client->adapter->dev, 331 + "data is NULL pointer in ioctl I2C_SMBUS.\n"); 332 + return -EINVAL; 333 + } 334 + 335 + if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || 336 + (data_arg.size == I2C_SMBUS_BYTE)) 337 + datasize = sizeof(data_arg.data->byte); 338 + else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || 339 + (data_arg.size == I2C_SMBUS_PROC_CALL)) 340 + datasize = sizeof(data_arg.data->word); 341 + else /* size == smbus block, i2c block, or block proc. call */ 342 + datasize = sizeof(data_arg.data->block); 343 + 344 + if ((data_arg.size == I2C_SMBUS_PROC_CALL) || 345 + (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || 346 + (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) || 347 + (data_arg.read_write == I2C_SMBUS_WRITE)) { 348 + if (copy_from_user(&temp, data_arg.data, datasize)) 349 + return -EFAULT; 350 + } 351 + if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) { 352 + /* Convert old I2C block commands to the new 353 + convention. This preserves binary compatibility. */ 354 + data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA; 355 + if (data_arg.read_write == I2C_SMBUS_READ) 356 + temp.block[0] = I2C_SMBUS_BLOCK_MAX; 357 + } 358 + res = i2c_smbus_xfer(client->adapter, client->addr, client->flags, 359 + data_arg.read_write, data_arg.command, data_arg.size, &temp); 360 + if (!res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || 361 + (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || 362 + (data_arg.read_write == I2C_SMBUS_READ))) { 363 + if (copy_to_user(data_arg.data, &temp, datasize)) 364 + return -EFAULT; 365 + } 366 + return res; 367 + } 368 + 203 369 static int i2cdev_ioctl(struct inode *inode, struct file *file, 204 370 unsigned int cmd, unsigned long arg) 205 371 { 206 372 struct i2c_client *client = (struct i2c_client *)file->private_data; 207 - struct i2c_rdwr_ioctl_data rdwr_arg; 208 - struct i2c_smbus_ioctl_data data_arg; 209 - union i2c_smbus_data temp; 210 - struct i2c_msg *rdwr_pa; 211 - u8 __user **data_ptrs; 212 - int i,datasize,res; 213 373 unsigned long funcs; 214 374 215 375 dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n", ··· 413 253 return put_user(funcs, (unsigned long __user *)arg); 414 254 415 255 case I2C_RDWR: 416 - if (copy_from_user(&rdwr_arg, 417 - (struct i2c_rdwr_ioctl_data __user *)arg, 418 - sizeof(rdwr_arg))) 419 - return -EFAULT; 420 - 421 - /* Put an arbitrary limit on the number of messages that can 422 - * be sent at once */ 423 - if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS) 424 - return -EINVAL; 425 - 426 - rdwr_pa = (struct i2c_msg *) 427 - kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg), 428 - GFP_KERNEL); 429 - 430 - if (rdwr_pa == NULL) return -ENOMEM; 431 - 432 - if (copy_from_user(rdwr_pa, rdwr_arg.msgs, 433 - rdwr_arg.nmsgs * sizeof(struct i2c_msg))) { 434 - kfree(rdwr_pa); 435 - return -EFAULT; 436 - } 437 - 438 - data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL); 439 - if (data_ptrs == NULL) { 440 - kfree(rdwr_pa); 441 - return -ENOMEM; 442 - } 443 - 444 - res = 0; 445 - for( i=0; i<rdwr_arg.nmsgs; i++ ) { 446 - /* Limit the size of the message to a sane amount; 447 - * and don't let length change either. */ 448 - if ((rdwr_pa[i].len > 8192) || 449 - (rdwr_pa[i].flags & I2C_M_RECV_LEN)) { 450 - res = -EINVAL; 451 - break; 452 - } 453 - data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf; 454 - rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL); 455 - if(rdwr_pa[i].buf == NULL) { 456 - res = -ENOMEM; 457 - break; 458 - } 459 - if(copy_from_user(rdwr_pa[i].buf, 460 - data_ptrs[i], 461 - rdwr_pa[i].len)) { 462 - ++i; /* Needs to be kfreed too */ 463 - res = -EFAULT; 464 - break; 465 - } 466 - } 467 - if (res < 0) { 468 - int j; 469 - for (j = 0; j < i; ++j) 470 - kfree(rdwr_pa[j].buf); 471 - kfree(data_ptrs); 472 - kfree(rdwr_pa); 473 - return res; 474 - } 475 - 476 - res = i2c_transfer(client->adapter, 477 - rdwr_pa, 478 - rdwr_arg.nmsgs); 479 - while(i-- > 0) { 480 - if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD)) { 481 - if(copy_to_user( 482 - data_ptrs[i], 483 - rdwr_pa[i].buf, 484 - rdwr_pa[i].len)) { 485 - res = -EFAULT; 486 - } 487 - } 488 - kfree(rdwr_pa[i].buf); 489 - } 490 - kfree(data_ptrs); 491 - kfree(rdwr_pa); 492 - return res; 256 + return i2cdev_ioctl_rdrw(client, arg); 493 257 494 258 case I2C_SMBUS: 495 - if (copy_from_user(&data_arg, 496 - (struct i2c_smbus_ioctl_data __user *) arg, 497 - sizeof(struct i2c_smbus_ioctl_data))) 498 - return -EFAULT; 499 - if ((data_arg.size != I2C_SMBUS_BYTE) && 500 - (data_arg.size != I2C_SMBUS_QUICK) && 501 - (data_arg.size != I2C_SMBUS_BYTE_DATA) && 502 - (data_arg.size != I2C_SMBUS_WORD_DATA) && 503 - (data_arg.size != I2C_SMBUS_PROC_CALL) && 504 - (data_arg.size != I2C_SMBUS_BLOCK_DATA) && 505 - (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) && 506 - (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) && 507 - (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) { 508 - dev_dbg(&client->adapter->dev, 509 - "size out of range (%x) in ioctl I2C_SMBUS.\n", 510 - data_arg.size); 511 - return -EINVAL; 512 - } 513 - /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1, 514 - so the check is valid if size==I2C_SMBUS_QUICK too. */ 515 - if ((data_arg.read_write != I2C_SMBUS_READ) && 516 - (data_arg.read_write != I2C_SMBUS_WRITE)) { 517 - dev_dbg(&client->adapter->dev, 518 - "read_write out of range (%x) in ioctl I2C_SMBUS.\n", 519 - data_arg.read_write); 520 - return -EINVAL; 521 - } 259 + return i2cdev_ioctl_smbus(client, arg); 522 260 523 - /* Note that command values are always valid! */ 524 - 525 - if ((data_arg.size == I2C_SMBUS_QUICK) || 526 - ((data_arg.size == I2C_SMBUS_BYTE) && 527 - (data_arg.read_write == I2C_SMBUS_WRITE))) 528 - /* These are special: we do not use data */ 529 - return i2c_smbus_xfer(client->adapter, client->addr, 530 - client->flags, 531 - data_arg.read_write, 532 - data_arg.command, 533 - data_arg.size, NULL); 534 - 535 - if (data_arg.data == NULL) { 536 - dev_dbg(&client->adapter->dev, 537 - "data is NULL pointer in ioctl I2C_SMBUS.\n"); 538 - return -EINVAL; 539 - } 540 - 541 - if ((data_arg.size == I2C_SMBUS_BYTE_DATA) || 542 - (data_arg.size == I2C_SMBUS_BYTE)) 543 - datasize = sizeof(data_arg.data->byte); 544 - else if ((data_arg.size == I2C_SMBUS_WORD_DATA) || 545 - (data_arg.size == I2C_SMBUS_PROC_CALL)) 546 - datasize = sizeof(data_arg.data->word); 547 - else /* size == smbus block, i2c block, or block proc. call */ 548 - datasize = sizeof(data_arg.data->block); 549 - 550 - if ((data_arg.size == I2C_SMBUS_PROC_CALL) || 551 - (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || 552 - (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) || 553 - (data_arg.read_write == I2C_SMBUS_WRITE)) { 554 - if (copy_from_user(&temp, data_arg.data, datasize)) 555 - return -EFAULT; 556 - } 557 - if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) { 558 - /* Convert old I2C block commands to the new 559 - convention. This preserves binary compatibility. */ 560 - data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA; 561 - if (data_arg.read_write == I2C_SMBUS_READ) 562 - temp.block[0] = I2C_SMBUS_BLOCK_MAX; 563 - } 564 - res = i2c_smbus_xfer(client->adapter,client->addr,client->flags, 565 - data_arg.read_write, 566 - data_arg.command,data_arg.size,&temp); 567 - if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) || 568 - (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) || 569 - (data_arg.read_write == I2C_SMBUS_READ))) { 570 - if (copy_to_user(data_arg.data, &temp, datasize)) 571 - return -EFAULT; 572 - } 573 - return res; 574 261 case I2C_RETRIES: 575 262 client->adapter->retries = arg; 576 263 break;