#include<linux/kernel.h>
#include<linux/errno.h>
#include<linux/module.h>
#include<linux/init.h>
#include<linux/slab.h>
#include<linux/kref.h>
#include<linux/usb.h>
#include<linux/device.h>
#include<linux/reiserfs_fs.h>

/* Values for SAMSUNG S3310   SAMSUNG TECHNOLOGY */
#define VENDOR_ID 0x04e8
#define PRODUCT_ID 0x678d

/* Table of devices that work with this driver */
static const struct usb_device_id id_table[ ] = {
	{  USB_DEVICE(VENDOR_ID, PRODUCT_ID)  },
	{ },	/* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, id_table);

/* structure to hold all of our device specific stuff */
struct gotemp {
	struct usb_device *udev;	/* the usb_device for this device */
	int temp;
	struct semaphore limit_sem;	/* Limits the number of writes in progress */
	unsigned char *bulk_in_buffer;	/* buffer to recieve data */
	size_t bulk_in_size;		/* size of the recieved buffer */
	unsigned char *int_in_buffer;
	struct urb *int_in_urb;
};

/* make a sysfs file */
static ssize_t show_temp(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct usb_interface *intf = to_usb_interface(dev);
	struct gotemp *gdev = usb_get_intfdata(intf);
		
	return sprintf(buf, "%d\n", gdev->temp);	/* buffer is page size */
}
static DEVICE_ATTR(temp, S_IRUGO, show_temp, NULL);	/* device attributes temp READ USER GROUP OWNER show function, No storage function */

static int gotemp_probe(struct usb_interface *interface, const struct usb_device_id *id)
{
	int retval= 0;
//	struct usb_host_interface *iface_desc;
	struct usb_endpoint_descriptor *endpoint;
	size_t buffer_size;
	
	struct usb_device * udev = interface_to_usbdev(interface);	/* cast backwards from interface to usb_device */
	struct gotemp *gdev;
	gdev = kzalloc(sizeof(struct gotemp), GFP_KERNEL);	/* allocate space and fill it up with zeros */
	if(!gdev)
	{
		dev_err(&interface->dev,"Out of memory\n");
		return -ENOMEM;
	}
	gdev->udev = usb_get_dev(udev);		/* saving our device configurations in gdev structure */
	/* Setting up endpoint information */
	/* Find a one control endpoint for the device */

//	iface_desc = interface->cur_altsetting;	/* Currently active alternate setting */
	endpoint = &interface->cur_altsetting.endpoint[0].desc;
	buffer_size = le16_tp_cpu(endpoint->wMaxPacketSize);		
	usb_set_intfdata(interface,gdev);	/* save our data pointer in this interface device */

	gdev->int_in_buffer = kmalloc(buffer_size,GFP_KERNEL);
	if(!gdev->int_in_buffer) {
		dev_info(&interface->dev,"Could not allocate buffer\n");
		goto error;	
	}
	

	gdev->temp = 42;
	retval = device_create_file(&interface->dev, &dev_attr_temp);	/* create sysfs attribute for device dev_attr_temp created from DEVICE_ATTR */
	if(retval)
	  goto error;
	/* Let us know what node this device is attached to */
	dev_info(&interface->dev,"USB gotemp device now Attached to: %d\n",interface->minor);
	return 0;
error:
	usb_set_intfdata(interface,NULL);
	kfree(gdev);
	return retval;
}

static void gotemp_disconnect(struct usb_interface *interface)
{
	struct gotemp *gdev;
	gdev = usb_get_intfdata(interface);	/* retrieve our data pointer from struct usb_interface !! Kind of unclear */
	usb_set_intfdata(interface,NULL);	/* nothing is saved there */
	usb_put_dev(gdev->udev);		/* releases the use of usb device structure */
	kfree(gdev);		
	device_remove_file(&interface->dev, &dev_attr_temp);
	dev_info(&interface->dev,"USB gotemp device now Disconnected\n");
}


static struct usb_driver gotemp_driver = {
//	.owner=THIS_MODULE,
	.name="USB-Ishmeet",
	.id_table = id_table,
	.probe = gotemp_probe,
	.disconnect = gotemp_disconnect,
};

static int __init gotemp_init(void)
{
	int retval=0;
//	printk(KERN_INFO "Inserted module: USB\n");  /* stupid printk statements log junk, Keep it clean */
	retval = usb_register(&gotemp_driver);
	if(retval == 0)
	  printk(KERN_INFO "Register USB succesfull\n");
	else
	  err("USB Register failed, Error number : %d",retval);	
	
	
return 0;
}

static void __exit gotemp_exit(void)
{
	usb_deregister(&gotemp_driver);
	printk(KERN_INFO "Removed module: USB\n");
}

module_init(gotemp_init);
module_exit(gotemp_exit);
	
MODULE_AUTHOR("USB-Ishmeet");
MODULE_LICENSE("GPL");
