aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorJean Delvare <khali@linux-fr.org>2008-04-22 16:16:47 -0400
committerJean Delvare <khali@hyperion.delvare>2008-04-22 16:16:47 -0400
commitdba7997a87cd12b815c0d58b2a0522a8bb0cf5ec (patch)
treef64fc267508c3136c988562df6eddd7b9f4a15c9 /drivers/i2c
parent838349b5c6454ebce8ec3e8c448941cf8608ffea (diff)
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>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/i2c-dev.c329
1 files changed, 168 insertions, 161 deletions
diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
index 393e679d9faa..d34c14c81c29 100644
--- a/drivers/i2c/i2c-dev.c
+++ b/drivers/i2c/i2c-dev.c
@@ -200,16 +200,176 @@ static int i2cdev_check_addr(struct i2c_adapter *adapter, unsigned int addr)
200 return device_for_each_child(&adapter->dev, &addr, i2cdev_check); 200 return device_for_each_child(&adapter->dev, &addr, i2cdev_check);
201} 201}
202 202
203static int i2cdev_ioctl(struct inode *inode, struct file *file, 203static noinline int i2cdev_ioctl_rdrw(struct i2c_client *client,
204 unsigned int cmd, unsigned long arg) 204 unsigned long arg)
205{ 205{
206 struct i2c_client *client = (struct i2c_client *)file->private_data;
207 struct i2c_rdwr_ioctl_data rdwr_arg; 206 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; 207 struct i2c_msg *rdwr_pa;
211 u8 __user **data_ptrs; 208 u8 __user **data_ptrs;
212 int i,datasize,res; 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
284static 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
369static int i2cdev_ioctl(struct inode *inode, struct file *file,
370 unsigned int cmd, unsigned long arg)
371{
372 struct i2c_client *client = (struct i2c_client *)file->private_data;
213 unsigned long funcs; 373 unsigned long funcs;
214 374
215 dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n", 375 dev_dbg(&client->adapter->dev, "ioctl, cmd=0x%02x, arg=0x%02lx\n",
@@ -253,164 +413,11 @@ static int i2cdev_ioctl(struct inode *inode, struct file *file,
253 return put_user(funcs, (unsigned long __user *)arg); 413 return put_user(funcs, (unsigned long __user *)arg);
254 414
255 case I2C_RDWR: 415 case I2C_RDWR:
256 if (copy_from_user(&rdwr_arg, 416 return i2cdev_ioctl_rdrw(client, arg);
257 (struct i2c_rdwr_ioctl_data __user *)arg,
258 sizeof(rdwr_arg)))
259 return -EFAULT;
260
261 /* Put an arbitrary limit on the number of messages that can
262 * be sent at once */
263 if (rdwr_arg.nmsgs > I2C_RDRW_IOCTL_MAX_MSGS)
264 return -EINVAL;
265
266 rdwr_pa = (struct i2c_msg *)
267 kmalloc(rdwr_arg.nmsgs * sizeof(struct i2c_msg),
268 GFP_KERNEL);
269
270 if (rdwr_pa == NULL) return -ENOMEM;
271
272 if (copy_from_user(rdwr_pa, rdwr_arg.msgs,
273 rdwr_arg.nmsgs * sizeof(struct i2c_msg))) {
274 kfree(rdwr_pa);
275 return -EFAULT;
276 }
277
278 data_ptrs = kmalloc(rdwr_arg.nmsgs * sizeof(u8 __user *), GFP_KERNEL);
279 if (data_ptrs == NULL) {
280 kfree(rdwr_pa);
281 return -ENOMEM;
282 }
283
284 res = 0;
285 for( i=0; i<rdwr_arg.nmsgs; i++ ) {
286 /* Limit the size of the message to a sane amount;
287 * and don't let length change either. */
288 if ((rdwr_pa[i].len > 8192) ||
289 (rdwr_pa[i].flags & I2C_M_RECV_LEN)) {
290 res = -EINVAL;
291 break;
292 }
293 data_ptrs[i] = (u8 __user *)rdwr_pa[i].buf;
294 rdwr_pa[i].buf = kmalloc(rdwr_pa[i].len, GFP_KERNEL);
295 if(rdwr_pa[i].buf == NULL) {
296 res = -ENOMEM;
297 break;
298 }
299 if(copy_from_user(rdwr_pa[i].buf,
300 data_ptrs[i],
301 rdwr_pa[i].len)) {
302 ++i; /* Needs to be kfreed too */
303 res = -EFAULT;
304 break;
305 }
306 }
307 if (res < 0) {
308 int j;
309 for (j = 0; j < i; ++j)
310 kfree(rdwr_pa[j].buf);
311 kfree(data_ptrs);
312 kfree(rdwr_pa);
313 return res;
314 }
315
316 res = i2c_transfer(client->adapter,
317 rdwr_pa,
318 rdwr_arg.nmsgs);
319 while(i-- > 0) {
320 if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD)) {
321 if(copy_to_user(
322 data_ptrs[i],
323 rdwr_pa[i].buf,
324 rdwr_pa[i].len)) {
325 res = -EFAULT;
326 }
327 }
328 kfree(rdwr_pa[i].buf);
329 }
330 kfree(data_ptrs);
331 kfree(rdwr_pa);
332 return res;
333 417
334 case I2C_SMBUS: 418 case I2C_SMBUS:
335 if (copy_from_user(&data_arg, 419 return i2cdev_ioctl_smbus(client, arg);
336 (struct i2c_smbus_ioctl_data __user *) arg,
337 sizeof(struct i2c_smbus_ioctl_data)))
338 return -EFAULT;
339 if ((data_arg.size != I2C_SMBUS_BYTE) &&
340 (data_arg.size != I2C_SMBUS_QUICK) &&
341 (data_arg.size != I2C_SMBUS_BYTE_DATA) &&
342 (data_arg.size != I2C_SMBUS_WORD_DATA) &&
343 (data_arg.size != I2C_SMBUS_PROC_CALL) &&
344 (data_arg.size != I2C_SMBUS_BLOCK_DATA) &&
345 (data_arg.size != I2C_SMBUS_I2C_BLOCK_BROKEN) &&
346 (data_arg.size != I2C_SMBUS_I2C_BLOCK_DATA) &&
347 (data_arg.size != I2C_SMBUS_BLOCK_PROC_CALL)) {
348 dev_dbg(&client->adapter->dev,
349 "size out of range (%x) in ioctl I2C_SMBUS.\n",
350 data_arg.size);
351 return -EINVAL;
352 }
353 /* Note that I2C_SMBUS_READ and I2C_SMBUS_WRITE are 0 and 1,
354 so the check is valid if size==I2C_SMBUS_QUICK too. */
355 if ((data_arg.read_write != I2C_SMBUS_READ) &&
356 (data_arg.read_write != I2C_SMBUS_WRITE)) {
357 dev_dbg(&client->adapter->dev,
358 "read_write out of range (%x) in ioctl I2C_SMBUS.\n",
359 data_arg.read_write);
360 return -EINVAL;
361 }
362
363 /* Note that command values are always valid! */
364
365 if ((data_arg.size == I2C_SMBUS_QUICK) ||
366 ((data_arg.size == I2C_SMBUS_BYTE) &&
367 (data_arg.read_write == I2C_SMBUS_WRITE)))
368 /* These are special: we do not use data */
369 return i2c_smbus_xfer(client->adapter, client->addr,
370 client->flags,
371 data_arg.read_write,
372 data_arg.command,
373 data_arg.size, NULL);
374
375 if (data_arg.data == NULL) {
376 dev_dbg(&client->adapter->dev,
377 "data is NULL pointer in ioctl I2C_SMBUS.\n");
378 return -EINVAL;
379 }
380 420
381 if ((data_arg.size == I2C_SMBUS_BYTE_DATA) ||
382 (data_arg.size == I2C_SMBUS_BYTE))
383 datasize = sizeof(data_arg.data->byte);
384 else if ((data_arg.size == I2C_SMBUS_WORD_DATA) ||
385 (data_arg.size == I2C_SMBUS_PROC_CALL))
386 datasize = sizeof(data_arg.data->word);
387 else /* size == smbus block, i2c block, or block proc. call */
388 datasize = sizeof(data_arg.data->block);
389
390 if ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
391 (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
392 (data_arg.size == I2C_SMBUS_I2C_BLOCK_DATA) ||
393 (data_arg.read_write == I2C_SMBUS_WRITE)) {
394 if (copy_from_user(&temp, data_arg.data, datasize))
395 return -EFAULT;
396 }
397 if (data_arg.size == I2C_SMBUS_I2C_BLOCK_BROKEN) {
398 /* Convert old I2C block commands to the new
399 convention. This preserves binary compatibility. */
400 data_arg.size = I2C_SMBUS_I2C_BLOCK_DATA;
401 if (data_arg.read_write == I2C_SMBUS_READ)
402 temp.block[0] = I2C_SMBUS_BLOCK_MAX;
403 }
404 res = i2c_smbus_xfer(client->adapter,client->addr,client->flags,
405 data_arg.read_write,
406 data_arg.command,data_arg.size,&temp);
407 if (! res && ((data_arg.size == I2C_SMBUS_PROC_CALL) ||
408 (data_arg.size == I2C_SMBUS_BLOCK_PROC_CALL) ||
409 (data_arg.read_write == I2C_SMBUS_READ))) {
410 if (copy_to_user(data_arg.data, &temp, datasize))
411 return -EFAULT;
412 }
413 return res;
414 case I2C_RETRIES: 421 case I2C_RETRIES:
415 client->adapter->retries = arg; 422 client->adapter->retries = arg;
416 break; 423 break;