|
@@ -169,6 +169,9 @@ struct goldfish_pipe {
|
|
|
* waiting to be awoken.
|
|
|
*/
|
|
|
struct goldfish_pipe_dev {
|
|
|
+ /* A magic number to check if this is an instance of this struct */
|
|
|
+ void *magic;
|
|
|
+
|
|
|
/*
|
|
|
* Global device spinlock. Protects the following members:
|
|
|
* - pipes, pipes_capacity
|
|
@@ -215,8 +218,6 @@ struct goldfish_pipe_dev {
|
|
|
struct miscdevice miscdev;
|
|
|
};
|
|
|
|
|
|
-static struct goldfish_pipe_dev goldfish_pipe_dev;
|
|
|
-
|
|
|
static int goldfish_pipe_cmd_locked(struct goldfish_pipe *pipe,
|
|
|
enum PipeCmdCode cmd)
|
|
|
{
|
|
@@ -611,6 +612,9 @@ static void goldfish_interrupt_task(unsigned long dev_addr)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+static void goldfish_pipe_device_deinit(struct platform_device *pdev,
|
|
|
+ struct goldfish_pipe_dev *dev);
|
|
|
+
|
|
|
/*
|
|
|
* The general idea of the interrupt handling:
|
|
|
*
|
|
@@ -631,7 +635,7 @@ static irqreturn_t goldfish_pipe_interrupt(int irq, void *dev_id)
|
|
|
unsigned long flags;
|
|
|
struct goldfish_pipe_dev *dev = dev_id;
|
|
|
|
|
|
- if (dev != &goldfish_pipe_dev)
|
|
|
+ if (dev->magic != &goldfish_pipe_device_deinit)
|
|
|
return IRQ_NONE;
|
|
|
|
|
|
/* Request the signalled pipes from the device */
|
|
@@ -683,6 +687,14 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev)
|
|
|
return id;
|
|
|
}
|
|
|
|
|
|
+/* A helper function to get the instance of goldfish_pipe_dev from file */
|
|
|
+static struct goldfish_pipe_dev *to_goldfish_pipe_dev(struct file *file)
|
|
|
+{
|
|
|
+ struct miscdevice *miscdev = file->private_data;
|
|
|
+
|
|
|
+ return container_of(miscdev, struct goldfish_pipe_dev, miscdev);
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* goldfish_pipe_open - open a channel to the AVD
|
|
|
* @inode: inode of device
|
|
@@ -696,7 +708,7 @@ static int get_free_pipe_id_locked(struct goldfish_pipe_dev *dev)
|
|
|
*/
|
|
|
static int goldfish_pipe_open(struct inode *inode, struct file *file)
|
|
|
{
|
|
|
- struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
|
|
|
+ struct goldfish_pipe_dev *dev = to_goldfish_pipe_dev(file);
|
|
|
unsigned long flags;
|
|
|
int id;
|
|
|
int status;
|
|
@@ -804,9 +816,9 @@ static void write_pa_addr(void *addr, void __iomem *portl, void __iomem *porth)
|
|
|
writel(lower_32_bits(paddr), portl);
|
|
|
}
|
|
|
|
|
|
-static int goldfish_pipe_device_init(struct platform_device *pdev)
|
|
|
+static int goldfish_pipe_device_init(struct platform_device *pdev,
|
|
|
+ struct goldfish_pipe_dev *dev)
|
|
|
{
|
|
|
- struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
|
|
|
int err;
|
|
|
|
|
|
tasklet_init(&dev->irq_tasklet, &goldfish_interrupt_task,
|
|
@@ -861,26 +873,29 @@ static int goldfish_pipe_device_init(struct platform_device *pdev)
|
|
|
dev->base + PIPE_REG_OPEN_BUFFER,
|
|
|
dev->base + PIPE_REG_OPEN_BUFFER_HIGH);
|
|
|
|
|
|
+ platform_set_drvdata(pdev, dev);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void goldfish_pipe_device_deinit(struct platform_device *pdev)
|
|
|
+static void goldfish_pipe_device_deinit(struct platform_device *pdev,
|
|
|
+ struct goldfish_pipe_dev *dev)
|
|
|
{
|
|
|
- misc_deregister(&goldfish_pipe_dev.miscdev);
|
|
|
- tasklet_kill(&goldfish_pipe_dev.irq_tasklet);
|
|
|
- kfree(goldfish_pipe_dev.pipes);
|
|
|
- free_page((unsigned long)goldfish_pipe_dev.buffers);
|
|
|
+ misc_deregister(&dev->miscdev);
|
|
|
+ tasklet_kill(&dev->irq_tasklet);
|
|
|
+ kfree(dev->pipes);
|
|
|
+ free_page((unsigned long)dev->buffers);
|
|
|
}
|
|
|
|
|
|
static int goldfish_pipe_probe(struct platform_device *pdev)
|
|
|
{
|
|
|
- int err;
|
|
|
struct resource *r;
|
|
|
- struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
|
|
|
+ struct goldfish_pipe_dev *dev;
|
|
|
|
|
|
- /* not thread safe, but this should not happen */
|
|
|
- WARN_ON(dev->base);
|
|
|
+ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
|
|
|
+ if (!dev)
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
+ dev->magic = &goldfish_pipe_device_deinit;
|
|
|
spin_lock_init(&dev->lock);
|
|
|
|
|
|
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
@@ -895,10 +910,9 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
|
|
|
}
|
|
|
|
|
|
r = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
|
|
- if (!r) {
|
|
|
- err = -EINVAL;
|
|
|
- goto error;
|
|
|
- }
|
|
|
+ if (!r)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
dev->irq = r->start;
|
|
|
|
|
|
/*
|
|
@@ -913,20 +927,14 @@ static int goldfish_pipe_probe(struct platform_device *pdev)
|
|
|
if (WARN_ON(dev->version < PIPE_CURRENT_DEVICE_VERSION))
|
|
|
return -EINVAL;
|
|
|
|
|
|
- err = goldfish_pipe_device_init(pdev);
|
|
|
- if (!err)
|
|
|
- return 0;
|
|
|
-
|
|
|
-error:
|
|
|
- dev->base = NULL;
|
|
|
- return err;
|
|
|
+ return goldfish_pipe_device_init(pdev, dev);
|
|
|
}
|
|
|
|
|
|
static int goldfish_pipe_remove(struct platform_device *pdev)
|
|
|
{
|
|
|
- struct goldfish_pipe_dev *dev = &goldfish_pipe_dev;
|
|
|
- goldfish_pipe_device_deinit(pdev);
|
|
|
- dev->base = NULL;
|
|
|
+ struct goldfish_pipe_dev *dev = platform_get_drvdata(pdev);
|
|
|
+
|
|
|
+ goldfish_pipe_device_deinit(pdev, dev);
|
|
|
return 0;
|
|
|
}
|
|
|
|