Skip to content

Commit

Permalink
spisdr : Read is working, likely lots of cleanup needed.
Browse files Browse the repository at this point in the history
  • Loading branch information
Philip Balister committed Aug 26, 2009
1 parent 21cb7e0 commit f13c2ef
Showing 1 changed file with 215 additions and 24 deletions.
239 changes: 215 additions & 24 deletions drivers/misc/spisdr.c
Expand Up @@ -8,22 +8,61 @@
* published by the Free Software Foundation.
*/

#include "linux/fs.h"
#include "linux/module.h"
#include "linux/cdev.h"
#include "linux/device.h"
#include "linux/spi/spi.h"
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/mutex.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/wait.h>

struct spisdr_dev {
#include <linux/spi/spi.h>

#include <asm/uaccess.h>

#include <mach/gpio.h>

struct spisdr_data {
struct cdev cdev;
} *spisdr_devp;

struct mutex buf_lock;
unsigned users;
u8 *buffer;
} *spisdr_datap;

static dev_t spisdr_dev_number;
static struct class *spisdr_class;

#define DEVICE_NAME "spisdr"

static struct file_operations spisdr_fops;
static struct file_operations spisdr_fops;
static struct spi_driver spisdr_spi;

static struct spi_device *spi_rx;
static struct spi_device *spi_tx;
static spinlock_t spi_lock_rx;
static spinlock_t spi_lock_tx;

static DECLARE_WAIT_QUEUE_HEAD(data_ready_queue);

static unsigned bufsiz = 4096;
static int in_use = 0;

static irqreturn_t spisdr_irqhandler(int irq, void *dev_id)
{
int serviced = IRQ_NONE;

/*
printk("Received spisdr interrupt\n");
*/

wake_up_interruptible(&data_ready_queue);

serviced = IRQ_HANDLED;

return serviced;
}

static int __init
spisdr_init(void)
Expand All @@ -39,16 +78,16 @@ spisdr_init(void)

spisdr_class = class_create(THIS_MODULE, DEVICE_NAME);

spisdr_devp = kmalloc(sizeof(struct spisdr_dev), GFP_KERNEL);
if (!spisdr_devp) {
spisdr_datap = kzalloc(sizeof(struct spisdr_data), GFP_KERNEL);
if (!spisdr_datap) {
printk("Bad kmalloc\n");
return -ENOMEM;
}

cdev_init(&spisdr_devp->cdev, &spisdr_fops);
spisdr_devp->cdev.owner = THIS_MODULE;
cdev_init(&spisdr_datap->cdev, &spisdr_fops);
spisdr_datap->cdev.owner = THIS_MODULE;

ret = cdev_add(&spisdr_devp->cdev,
ret = cdev_add(&spisdr_datap->cdev,
MKDEV(MAJOR(spisdr_dev_number), 0), 1);
if (ret) {
printk("Bad cdev\n");
Expand All @@ -59,6 +98,27 @@ spisdr_init(void)
device_create(spisdr_class, NULL, MKDEV(MAJOR(spisdr_dev_number),0),
NULL, "spisdr%d", 0);

ret = spi_register_driver(&spisdr_spi);
if (ret < 0) {
device_destroy(spisdr_class, MKDEV(MAJOR(spisdr_dev_number)
, 0));
cdev_del(&spisdr_datap->cdev);
kfree(spisdr_datap);
class_destroy(spisdr_class);
}

if ((gpio_request(133, "SPIDSDR_IRQ") == 0) &&
(gpio_direction_input(133) == 0)){
gpio_export(133, 0);
} else {
printk(KERN_ERR "could not obtain gpio for SPISDR IRQ\n");
return -1;
}

set_irq_type(gpio_to_irq(133), IRQ_TYPE_EDGE_RISING);
ret = request_irq(gpio_to_irq(133), spisdr_irqhandler, IRQF_DISABLED,
"spisdr", &spisdr_datap->cdev);

printk("spisdr Driver Initialized.\n");

return 0;
Expand All @@ -67,12 +127,11 @@ spisdr_init(void)
static void __exit
spisdr_cleanup(void)
{

unregister_chrdev_region(spisdr_dev_number, 1);

device_destroy(spisdr_class, MKDEV(MAJOR(spisdr_dev_number), 0));
cdev_del(&spisdr_devp->cdev);
kfree(spisdr_devp);
cdev_del(&spisdr_datap->cdev);
kfree(spisdr_datap);

class_destroy(spisdr_class);
}
Expand All @@ -81,35 +140,149 @@ spisdr_cleanup(void)
static int
spisdr_open(struct inode *inode, struct file *file)
{
struct spisdr_dev *spisdr_devp;
struct spisdr_data *spisdr_datap;
int status;

printk("spisdr open called\n");

spisdr_devp = container_of(inode->i_cdev, struct spisdr_dev, cdev);
if (in_use)
return -1;
in_use = 1;

spisdr_datap = container_of(inode->i_cdev, struct spisdr_data, cdev);

file->private_data = spisdr_devp;
file->private_data = spisdr_datap;

if (!spisdr_datap->buffer) {
spisdr_datap->buffer = kmalloc(bufsiz, GFP_KERNEL);
if (!spisdr_datap->buffer) {
dev_dbg(&spi_rx->dev, "open/ENOMEM\n");
status = -ENOMEM;
}
}

spi_rx->bits_per_word = 32;
spi_rx->max_speed_hz = 48000000;
spi_setup(spi_rx);

return 0;
}

static int
spisdr_release(struct inode *inode, struct file *file)
{
struct spisdr_dev *spisdr_devp = file->private_data;
struct spisdr_data *spisdr_datap = file->private_data;
int dofree;

printk("spisdr release called\n");

spisdr_devp = 0;
in_use = 0;

kfree(spisdr_datap->buffer);
spisdr_datap->buffer = NULL;

spin_lock_irq(&spi_lock_rx);
dofree = (spi_rx == NULL);
spin_unlock_irq(&spi_lock_rx);

if (dofree)
kfree(spisdr_datap);

spisdr_datap = 0;

return 0;
}

static void spisdr_complete(void *arg)
{
complete(arg);
}

static ssize_t
spisdr_spi_sync(struct spisdr_data *spisdr, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);
int status;

// printk("spisdr spi_sync called\n");

message->complete = spisdr_complete;
message->context = &done;

spin_lock_irq(&spi_lock_rx);
if (spi_rx == NULL)
status = -ESHUTDOWN;
else
status = spi_async(spi_rx, message);
spin_unlock(&spi_lock_rx);

if (status == 0) {
wait_for_completion(&done);
status = message->status;
if (status == 0)
status = message->actual_length;
}
return status;
}

static inline ssize_t
spisdr_read_from_spi(struct spisdr_data *spisdr, size_t len)
{
struct spi_transfer t = {
.rx_buf = spisdr->buffer,
.len = len,
};
struct spi_message m;

// printk("spisdr read_from_spi called\n");

spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spisdr_spi_sync(spisdr, &m);
}

ssize_t
spisdr_read(struct file *file, char *buf, size_t count, loff_t **ppos)
{
printk("spisdr read called\n");
struct spisdr_data *spisdr;
ssize_t status = 0;
DECLARE_WAITQUEUE(wait, current);

// printk("spisdr read called\n");

if (count > bufsiz)
return -EMSGSIZE;

spisdr = file->private_data;

add_wait_queue(&data_ready_queue, &wait);
while (gpio_get_value(133) == 0) {
set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
printk("Signal received\n");
set_current_state(TASK_RUNNING);
remove_wait_queue(&data_ready_queue, &wait);
return -EINTR;
}
schedule();
}
set_current_state(TASK_RUNNING);
remove_wait_queue(&data_ready_queue, &wait);

mutex_lock(&spisdr->buf_lock);
status = spisdr_read_from_spi(spisdr, count);
if (status > 0) {
unsigned long missing;

missing = copy_to_user(buf, spisdr->buffer, status);
if (missing == status)
status = -EFAULT;
else
status = status - missing;
}
mutex_unlock(&spisdr->buf_lock);

return 0;
return status;
}

static ssize_t
Expand Down Expand Up @@ -148,12 +321,30 @@ static struct file_operations spisdr_fops = {

static int spisdr_probe(struct spi_device *spi)
{
printk("In spisdr_probe: bus_num = %d, CS = %d\n", spi->master->bus_num, spi->chip_select);

if (spi->chip_select == 0) {
spi_rx = spi;
spin_lock_init(&spi_lock_rx);
}


if (spi->chip_select == 1) {
spi_tx = spi;
spin_lock_init(&spi_lock_tx);
}

mutex_init(&spisdr_datap->buf_lock);

return 0;
}

static spisdr_remove(struct spi_device *spi)
static int spisdr_remove(struct spi_device *spi)
{

printk("In spisdr_remove\n");

return 0;
}


Expand Down

0 comments on commit f13c2ef

Please sign in to comment.