Code:
static ssize_t skel_write(struct file *file, const char *user_buffer,
size_t count, loff_t *ppos)
{
struct usb_skel *dev;
int retval = 0,i = 0,motor_count,dir=0;
struct urb *urb = NULL;
char *buf = NULL;
char *buf1 = NULL;
size_t writesize = min(count+10, (size_t)MAX_TRANSFER);
printk(KERN_INFO "device_write(%p,%s,%d),ioused : %d\n", file, user_buffer, count,is_ioctl_used);
dev = file->private_data;
// verify that we actually have some data to write
if (count == 0)
goto exit;
/*
* limit the number of URBs in flight to stop a user from using up all
* RAM
*/
if (!(file->f_flags & O_NONBLOCK)) {
if (down_interruptible(&dev->limit_sem)) {
retval = -ERESTARTSYS;
goto exit;
}
} else {
if (down_trylock(&dev->limit_sem)) {
retval = -EAGAIN;
goto exit;
}
}
spin_lock_irq(&dev->err_lock);
retval = dev->errors;
if (retval < 0) {
// any error is reported once
dev->errors = 0;
// to preserve notifications about reset
retval = (retval == -EPIPE) ? retval : -EIO;
}
spin_unlock_irq(&dev->err_lock);
if (retval < 0)
goto error;
/* create a urb, and a buffer for it, and copy the data to the urb */
buf1=(char *)kmalloc(sizeof(char)*20,GFP_KERNEL); //Allocate 2nd buffer.
if(is_ioctl_used) { //Whether the write function is called from IOCTL or Directly (echo > /dev/stepper)
sprintf(buf1,user_buffer);
} else {
if (copy_from_user(buf1, user_buffer,count)) {
retval = -EFAULT;
goto error;
}
}
motor_count=simple_strtol(buf1,NULL,10);
if(motor_count<0) { //Rotation counts of stepper motor.
motor_count=motor_count * -1; //If motor_count<0 then rotate in anti-clock direction.
dir=1;
}
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
retval = -ENOMEM;
goto error;
}
buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL,
&urb->transfer_dma);
if (!buf) {
retval = -ENOMEM;
goto error;
}
/* this lock makes sure we don't submit URBs to gone devices */
mutex_lock(&dev->io_mutex);
if (!dev->interface) { /* disconnect() was called */
mutex_unlock(&dev->io_mutex);
retval = -ENODEV;
goto error;
}
/* initialize the urb properly */
usb_fill_int_urb(urb, dev->udev,
usb_sndintpipe(dev->udev, dev->bulk_out_endpointAddr),
buf, writesize, skel_write_bulk_callback, dev,dev->bInterval);
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_anchor_urb(urb, &dev->submitted);
for(i=0;i<motor_count;i++) { //Loop to rotate motor based on counts.
printk("data : %d, motor_cnt : %d, master_counter : %d\n",ptr->data,motor_count,master_counter);
if(dir==0) ptr=ptr->next;
else ptr=ptr->prev;
// Fill the buffers.
buf[0]=0x01;
buf[1]=0;
buf[2]=ptr->data;
/* send the data out the bulk port */
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
dev_err(&dev->interface->dev,
"%s - failed submitting write urb, error %d\n",
__func__, retval);
mutex_unlock(&dev->io_mutex);
goto error_unanchor;
}
if(++master_counter && master_counter > 47) master_counter=0;
/*
* release our reference to this urb, the USB core will eventually free
* it entirely
*/
mdelay(50); //Delay is required to match with motor speed.
}
mutex_unlock(&dev->io_mutex);
usb_free_coherent(dev->udev, writesize, buf, urb->transfer_dma);
kfree(buf1);
usb_free_urb(urb);
is_ioctl_used=0;
return writesize;
error_unanchor:
usb_unanchor_urb(urb);
error:
if (urb) {
usb_free_coherent(dev->udev, writesize, buf, urb->transfer_dma);
usb_free_urb(urb);
}
up(&dev->limit_sem);
exit:
return retval;
}