static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct usbtmc_device_data *data; int retval = -EBADRQC; data = file->private_data; mutex_lock(&data->io_mutex); if (data->zombie) { retval = -ENODEV; goto skip_io_on_zombie; } switch (cmd) { case USBTMC_IOCTL_CLEAR_OUT_HALT: retval = usbtmc_ioctl_clear_out_halt(data); break; case USBTMC_IOCTL_CLEAR_IN_HALT: retval = usbtmc_ioctl_clear_in_halt(data); break; case USBTMC_IOCTL_INDICATOR_PULSE: retval = usbtmc_ioctl_indicator_pulse(data); break; case USBTMC_IOCTL_CLEAR: retval = usbtmc_ioctl_clear(data); break; case USBTMC_IOCTL_ABORT_BULK_OUT: retval = usbtmc_ioctl_abort_bulk_out(data); break; case USBTMC_IOCTL_ABORT_BULK_IN: retval = usbtmc_ioctl_abort_bulk_in(data); break; } skip_io_on_zombie: mutex_unlock(&data->io_mutex); return retval; }
static ssize_t usbtmc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { struct usbtmc_device_data *data; u8 *buffer; int retval; int actual; unsigned long int n_bytes; int remaining; int done; int this_part; data = filp->private_data; buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); if (!buffer) return -ENOMEM; mutex_lock(&data->io_mutex); if (data->zombie) { retval = -ENODEV; goto exit; } remaining = count; done = 0; while (remaining > 0) { if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE) { this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE; buffer[8] = 0; } else { this_part = remaining; buffer[8] = 1; } /* Setup IO buffer for DEV_DEP_MSG_OUT message */ buffer[0] = 1; buffer[1] = data->bTag; buffer[2] = ~data->bTag; buffer[3] = 0; /* Reserved */ buffer[4] = this_part >> 0; buffer[5] = this_part >> 8; buffer[6] = this_part >> 16; buffer[7] = this_part >> 24; /* buffer[8] is set above... */ buffer[9] = 0; /* Reserved */ buffer[10] = 0; /* Reserved */ buffer[11] = 0; /* Reserved */ if (copy_from_user(&buffer[USBTMC_HEADER_SIZE], buf + done, this_part)) { retval = -EFAULT; goto exit; } n_bytes = roundup(USBTMC_HEADER_SIZE + this_part, 4); memset(buffer + USBTMC_HEADER_SIZE + this_part, 0, n_bytes - (USBTMC_HEADER_SIZE + this_part)); do { retval = usb_bulk_msg(data->usb_dev, usb_sndbulkpipe(data->usb_dev, data->bulk_out), buffer, n_bytes, &actual, USBTMC_TIMEOUT); if (retval != 0) break; n_bytes -= actual; } while (n_bytes); data->bTag_last_write = data->bTag; data->bTag++; if (!data->bTag) data->bTag++; if (retval < 0) { dev_err(&data->intf->dev, "Unable to send data, error %d\n", retval); if (data->auto_abort) usbtmc_ioctl_abort_bulk_out(data); goto exit; } remaining -= this_part; done += this_part; } retval = count; exit: mutex_unlock(&data->io_mutex); kfree(buffer); return retval; }
static ssize_t usbtmc_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { struct usbtmc_device_data *data; struct device *dev; u32 n_characters; u8 *buffer; int actual; size_t done; size_t remaining; int retval; size_t this_part; /* Get pointer to private data structure */ data = filp->private_data; dev = &data->intf->dev; buffer = kmalloc(USBTMC_SIZE_IOBUFFER, GFP_KERNEL); if (!buffer) return -ENOMEM; mutex_lock(&data->io_mutex); if (data->zombie) { retval = -ENODEV; goto exit; } if (data->rigol_quirk) { dev_dbg(dev, "usb_bulk_msg_in: count(%zu)\n", count); retval = send_request_dev_dep_msg_in(data, count); if (retval < 0) { if (data->auto_abort) usbtmc_ioctl_abort_bulk_out(data); goto exit; } } /* Loop until we have fetched everything we requested */ remaining = count; this_part = remaining; done = 0; while (remaining > 0) { if (!data->rigol_quirk) { dev_dbg(dev, "usb_bulk_msg_in: remaining(%zu), count(%zu)\n", remaining, count); if (remaining > USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3) this_part = USBTMC_SIZE_IOBUFFER - USBTMC_HEADER_SIZE - 3; else this_part = remaining; retval = send_request_dev_dep_msg_in(data, this_part); if (retval < 0) { dev_err(dev, "usb_bulk_msg returned %d\n", retval); if (data->auto_abort) usbtmc_ioctl_abort_bulk_out(data); goto exit; } } /* Send bulk URB */ retval = usb_bulk_msg(data->usb_dev, usb_rcvbulkpipe(data->usb_dev, data->bulk_in), buffer, USBTMC_SIZE_IOBUFFER, &actual, USBTMC_TIMEOUT); dev_dbg(dev, "usb_bulk_msg: retval(%u), done(%zu), remaining(%zu), actual(%d)\n", retval, done, remaining, actual); /* Store bTag (in case we need to abort) */ data->bTag_last_read = data->bTag; if (retval < 0) { dev_dbg(dev, "Unable to read data, error %d\n", retval); if (data->auto_abort) usbtmc_ioctl_abort_bulk_in(data); goto exit; } /* Parse header in first packet */ if ((done == 0) || !data->rigol_quirk) { /* Sanity checks for the header */ if (actual < USBTMC_HEADER_SIZE) { dev_err(dev, "Device sent too small first packet: %u < %u\n", actual, USBTMC_HEADER_SIZE); if (data->auto_abort) usbtmc_ioctl_abort_bulk_in(data); goto exit; } if (buffer[0] != 2) { dev_err(dev, "Device sent reply with wrong MsgID: %u != 2\n", buffer[0]); if (data->auto_abort) usbtmc_ioctl_abort_bulk_in(data); goto exit; } if (buffer[1] != data->bTag_last_write) { dev_err(dev, "Device sent reply with wrong bTag: %u != %u\n", buffer[1], data->bTag_last_write); if (data->auto_abort) usbtmc_ioctl_abort_bulk_in(data); goto exit; } /* How many characters did the instrument send? */ n_characters = buffer[4] + (buffer[5] << 8) + (buffer[6] << 16) + (buffer[7] << 24); if (n_characters > this_part) { dev_err(dev, "Device wants to return more data than requested: %u > %zu\n", n_characters, count); if (data->auto_abort) usbtmc_ioctl_abort_bulk_in(data); goto exit; } /* Remove the USBTMC header */ actual -= USBTMC_HEADER_SIZE; /* Check if the message is smaller than requested */ if (data->rigol_quirk) { if (remaining > n_characters) remaining = n_characters; /* Remove padding if it exists */ if (actual > remaining) actual = remaining; } else { if (this_part > n_characters) this_part = n_characters; /* Remove padding if it exists */ if (actual > this_part) actual = this_part; } dev_dbg(dev, "Bulk-IN header: N_characters(%u), bTransAttr(%u)\n", n_characters, buffer[8]); remaining -= actual; /* Terminate if end-of-message bit received from device */ if ((buffer[8] & 0x01) && (actual >= n_characters)) remaining = 0; dev_dbg(dev, "Bulk-IN header: remaining(%zu), buf(%p), buffer(%p) done(%zu)\n", remaining,buf,buffer,done); /* Copy buffer to user space */ if (copy_to_user(buf + done, &buffer[USBTMC_HEADER_SIZE], actual)) { /* There must have been an addressing problem */ retval = -EFAULT; goto exit; } done += actual; } else { if (actual > remaining) actual = remaining; remaining -= actual; dev_dbg(dev, "Bulk-IN header cont: actual(%u), done(%zu), remaining(%zu), buf(%p), buffer(%p)\n", actual, done, remaining,buf,buffer); /* Copy buffer to user space */ if (copy_to_user(buf + done, buffer, actual)) { /* There must have been an addressing problem */ retval = -EFAULT; goto exit; } done += actual; } } /* Update file position value */ *f_pos = *f_pos + done; retval = done; exit: mutex_unlock(&data->io_mutex); kfree(buffer); return retval; }
static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct usbtmc_device_data *data; int retval = -EBADRQC; data = file->private_data; mutex_lock(&data->io_mutex); if (data->zombie) { retval = -ENODEV; goto skip_io_on_zombie; } switch (cmd) { case USBTMC_IOCTL_CLEAR_OUT_HALT: retval = usbtmc_ioctl_clear_out_halt(data); break; case USBTMC_IOCTL_CLEAR_IN_HALT: retval = usbtmc_ioctl_clear_in_halt(data); break; case USBTMC_IOCTL_INDICATOR_PULSE: retval = usbtmc_ioctl_indicator_pulse(data); break; case USBTMC_IOCTL_CLEAR: retval = usbtmc_ioctl_clear(data); break; case USBTMC_IOCTL_ABORT_BULK_OUT: retval = usbtmc_ioctl_abort_bulk_out(data); break; case USBTMC_IOCTL_ABORT_BULK_IN: retval = usbtmc_ioctl_abort_bulk_in(data); break; case USBTMC488_IOCTL_GET_CAPS: retval = copy_to_user((void __user *)arg, &data->usb488_caps, sizeof(data->usb488_caps)); if (retval) retval = -EFAULT; break; case USBTMC488_IOCTL_READ_STB: retval = usbtmc488_ioctl_read_stb(data, (void __user *)arg); break; case USBTMC488_IOCTL_REN_CONTROL: retval = usbtmc488_ioctl_simple(data, (void __user *)arg, USBTMC488_REQUEST_REN_CONTROL); break; case USBTMC488_IOCTL_GOTO_LOCAL: retval = usbtmc488_ioctl_simple(data, (void __user *)arg, USBTMC488_REQUEST_GOTO_LOCAL); break; case USBTMC488_IOCTL_LOCAL_LOCKOUT: retval = usbtmc488_ioctl_simple(data, (void __user *)arg, USBTMC488_REQUEST_LOCAL_LOCKOUT); break; } skip_io_on_zombie: mutex_unlock(&data->io_mutex); return retval; }